first commit
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\AbsoluteLinks;
|
||||
|
||||
class BlockProtector {
|
||||
|
||||
private $protectedBlocks = [];
|
||||
|
||||
public function protect( $text ) {
|
||||
if ( ! function_exists( 'has_blocks' ) || ! has_blocks( $text ) ) {
|
||||
return $text;
|
||||
}
|
||||
|
||||
$integrationClass = \WPML_Gutenberg_Integration::class;
|
||||
|
||||
$decodeForwardSlashes = function ( $str ) {
|
||||
return str_replace( '\\/', '/', $str );
|
||||
};
|
||||
|
||||
$replaceBlockWithPlaceholder = function ( $text, $block ) {
|
||||
$key = md5( $block );
|
||||
$this->protectedBlocks[ $key ] = $block;
|
||||
|
||||
return str_replace( $block, $key, $text );
|
||||
};
|
||||
|
||||
return wpml_collect( \WPML_Gutenberg_Integration::parse_blocks( $text ) )
|
||||
->map( [ $integrationClass, 'sanitize_block' ] )
|
||||
->filter( [ $integrationClass, 'has_non_empty_attributes' ] )
|
||||
->map( [ $integrationClass, 'render_block' ] )
|
||||
->map( $decodeForwardSlashes )
|
||||
->reduce( $replaceBlockWithPlaceholder, $text );
|
||||
}
|
||||
|
||||
public function unProtect( $text ) {
|
||||
foreach ( $this->protectedBlocks as $key => $value ) {
|
||||
$text = str_replace( $key, $value, $text );
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,698 @@
|
||||
<?php
|
||||
|
||||
use WPML\FP\Lst;
|
||||
use WPML\FP\Str;
|
||||
|
||||
class AbsoluteLinks {
|
||||
/** @var array */
|
||||
public $custom_post_query_vars = [];
|
||||
|
||||
/** @var array */
|
||||
public $taxonomies_query_vars = [];
|
||||
|
||||
/** @var array */
|
||||
private $active_languages;
|
||||
|
||||
public function __construct() {
|
||||
if ( did_action( 'init' ) ) {
|
||||
$this->init_query_vars();
|
||||
} else {
|
||||
// init_query_vars is using $wp_taxonomies.
|
||||
// We have to change priority of our action
|
||||
// to make sure that all custom taxonomies are already registered.
|
||||
add_action( 'init', [ $this, 'init_query_vars' ], 1000 );
|
||||
}
|
||||
}
|
||||
|
||||
public function init_query_vars() {
|
||||
global $wp_post_types, $wp_taxonomies;
|
||||
|
||||
// Custom posts query vars.
|
||||
foreach ( $wp_post_types as $k => $v ) {
|
||||
if ( 'post' === $k || 'page' === $k ) {
|
||||
continue;
|
||||
}
|
||||
if ( $v->query_var ) {
|
||||
$this->custom_post_query_vars[ $k ] = $v->query_var;
|
||||
}
|
||||
}
|
||||
// Taxonomies query vars.
|
||||
foreach ( $wp_taxonomies as $k => $v ) {
|
||||
if ( 'category' === $k ) {
|
||||
continue;
|
||||
}
|
||||
if ( 'post_tag' === $k && ! $v->query_var ) {
|
||||
$tag_base = get_option( 'tag_base', 'tag' );
|
||||
$v->query_var = $tag_base;
|
||||
}
|
||||
if ( $v->query_var ) {
|
||||
$this->taxonomies_query_vars[ $k ] = $v->query_var;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function _process_generic_text( $source_text, &$alp_broken_links ) {
|
||||
global $wpdb, $wp_rewrite, $sitepress, $sitepress_settings;
|
||||
$sitepress_settings = $sitepress->get_settings();
|
||||
|
||||
$default_language = $sitepress->get_default_language();
|
||||
$current_language = $sitepress->get_current_language();
|
||||
|
||||
$cache_key_args = [
|
||||
$default_language,
|
||||
$current_language,
|
||||
md5( $source_text ),
|
||||
md5( implode( '', $alp_broken_links ) ),
|
||||
];
|
||||
$cache_key = md5( wp_json_encode( $cache_key_args ) );
|
||||
$cache_group = '_process_generic_text';
|
||||
$found = false;
|
||||
|
||||
$text = WPML_Non_Persistent_Cache::get( $cache_key, $cache_group, $found );
|
||||
|
||||
if ( $found ) {
|
||||
return $text;
|
||||
}
|
||||
|
||||
$filtered_icl_post_language = filter_input( INPUT_POST, 'icl_post_language', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
|
||||
|
||||
$block_protector = new \WPML\AbsoluteLinks\BlockProtector();
|
||||
|
||||
$text = $block_protector->protect( $source_text );
|
||||
|
||||
// We need to loop over each language so we create sticky links for all languages.
|
||||
$this->active_languages = array_keys( $sitepress->get_active_languages() );
|
||||
$current_language = empty( $filtered_icl_post_language ) ? $current_language : $filtered_icl_post_language;
|
||||
if ( ! empty( $current_language ) ) {
|
||||
$key = array_search( $current_language, $this->active_languages, true );
|
||||
if ( false !== $key ) {
|
||||
unset( $this->active_languages[ $key ] );
|
||||
}
|
||||
array_unshift( $this->active_languages, $current_language );
|
||||
}
|
||||
|
||||
$blacklist_requests = new WPML_Absolute_Links_Blacklist(
|
||||
apply_filters( 'wpml_sl_blacklist_requests', [], $sitepress )
|
||||
);
|
||||
|
||||
foreach ( $this->active_languages as $test_language ) {
|
||||
$rewrite = $this->initialize_rewrite( $current_language, $default_language, $sitepress );
|
||||
|
||||
$home_url = $sitepress->language_url( $test_language );
|
||||
|
||||
if ( 3 === $sitepress_settings['language_negotiation_type'] ) {
|
||||
$home_url = preg_replace( '#\?lang=([a-z-]+)#i', '', $home_url );
|
||||
}
|
||||
$home_url = str_replace( '?', '\?', $home_url );
|
||||
|
||||
if ( $sitepress_settings['urls']['directory_for_default_language'] && $test_language === $default_language ) {
|
||||
$home_url = str_replace( $default_language . '/', '', $home_url );
|
||||
}
|
||||
|
||||
$int1 = preg_match_all( '@<a([^>]*)href="((' . rtrim( $home_url, '/' ) . ')?/([^"^>^\[^\]]+))"([^>]*)>@i', $text, $alp_matches1 );
|
||||
$int2 = preg_match_all( '@<a([^>]*)href=\'((' . rtrim( $home_url, '/' ) . ')?/([^\'^>^\[^\]]+))\'([^>]*)>@i', $text, $alp_matches2 );
|
||||
|
||||
$alp_matches = [];
|
||||
for ( $i = 0; $i < 6; $i ++ ) {
|
||||
$alp_matches[ $i ] = array_merge( (array) $alp_matches1[ $i ], (array) $alp_matches2[ $i ] );
|
||||
}
|
||||
|
||||
if ( $int1 || $int2 ) {
|
||||
$def_url = [];
|
||||
$url_parts = wp_parse_url( $this->get_home_url_with_no_lang_directory() );
|
||||
$url_parts['path'] = isset( $url_parts['path'] ) ? $url_parts['path'] : '';
|
||||
foreach ( $alp_matches[4] as $k => $dir_path ) {
|
||||
if ( 0 === strpos( $dir_path, WP_CONTENT_DIR ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
list( $lang, $dir_path ) = $this->extract_lang_from_path( $sitepress_settings, $default_language, $dir_path );
|
||||
|
||||
$req_uri = '/' . $dir_path;
|
||||
$req_uri_array = explode( '?', $req_uri );
|
||||
$req_uri = $req_uri_array[0];
|
||||
$req_uri_params = '';
|
||||
if ( isset( $req_uri_array[1] ) ) {
|
||||
$req_uri_params = $req_uri_array[1];
|
||||
}
|
||||
// Separate anchor.
|
||||
$req_uri_array = explode( '#', $req_uri );
|
||||
$req_uri = $req_uri_array[0];
|
||||
|
||||
$anchor_output = isset( $req_uri_array[1] ) ? '#' . $req_uri_array[1] : '';
|
||||
|
||||
$home_path = wp_parse_url( get_home_url() );
|
||||
if ( isset( $home_path['path'] ) ) {
|
||||
$home_path = $home_path['path'];
|
||||
} else {
|
||||
$home_path = '';
|
||||
}
|
||||
$home_path = trim( $home_path, '/' );
|
||||
|
||||
$pathinfo = '';
|
||||
$req_uri = str_replace( $pathinfo, '', rawurldecode( $req_uri ) );
|
||||
$req_uri = trim( $req_uri, '/' );
|
||||
$req_uri = preg_replace( "|^$home_path|", '', $req_uri );
|
||||
$req_uri = trim( $req_uri, '/' );
|
||||
$pathinfo = trim( $pathinfo, '/' );
|
||||
$pathinfo = preg_replace( "|^$home_path|", '', $pathinfo );
|
||||
$pathinfo = trim( $pathinfo, '/' );
|
||||
|
||||
if ( ! empty( $pathinfo ) && ! preg_match( '|^.*' . $wp_rewrite->index . '$|', $pathinfo ) ) {
|
||||
$request = $pathinfo;
|
||||
} else {
|
||||
// If the request uri is the index, blank it out so that we don't try to match it against a rule.
|
||||
if ( $req_uri === $wp_rewrite->index ) {
|
||||
$req_uri = '';
|
||||
}
|
||||
$request = $req_uri;
|
||||
}
|
||||
|
||||
if ( ! $request || $blacklist_requests->is_blacklisted( $request ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$request_match = $request;
|
||||
|
||||
$permalink_query_vars = [];
|
||||
|
||||
foreach ( (array) $rewrite as $match => $query ) {
|
||||
// If the requesting file is the anchor of the match, prepend it to the path info.
|
||||
if ( ( ! empty( $req_uri ) ) && ( strpos( $match, $req_uri ) === 0 ) && ( $req_uri !== $request ) ) {
|
||||
$request_match = $req_uri . '/' . $request;
|
||||
}
|
||||
|
||||
if ( preg_match( "!^$match!", $request_match, $matches ) || preg_match( "!^$match!", urldecode( $request_match ), $matches ) ) {
|
||||
// Got a match.
|
||||
|
||||
// Trim the query of everything up to the '?'.
|
||||
$query = preg_replace( '!^.+\?!', '', $query );
|
||||
|
||||
// Substitute the substring matches into the query.
|
||||
$query = addslashes( WP_MatchesMapRegex::apply( $query, $matches ) );
|
||||
|
||||
// Parse the query.
|
||||
parse_str( $query, $permalink_query_vars );
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$post_name = false;
|
||||
$category_name = false;
|
||||
$tax_name = false;
|
||||
|
||||
if ( isset( $permalink_query_vars['pagename'] ) ) {
|
||||
$get_page_by_path = new WPML_Get_Page_By_Path( $wpdb, $sitepress, new WPML_Debug_BackTrace( null, 7 ) );
|
||||
$page_by_path = $get_page_by_path->get( $permalink_query_vars['pagename'], $test_language );
|
||||
|
||||
$post_name = $permalink_query_vars['pagename'];
|
||||
if ( ! empty( $page_by_path->post_type ) ) {
|
||||
$post_type = 'page';
|
||||
} else {
|
||||
$post_type = 'post';
|
||||
}
|
||||
} elseif ( isset( $permalink_query_vars['name'] ) ) {
|
||||
$post_name = $permalink_query_vars['name'];
|
||||
$post_type = 'post';
|
||||
} elseif ( isset( $permalink_query_vars['category_name'] ) ) {
|
||||
$category_name = $permalink_query_vars['category_name'];
|
||||
} elseif ( isset( $permalink_query_vars['p'] ) ) { // Case or /archives/%post_id.
|
||||
list( $post_type, $post_name ) = $wpdb->get_row(
|
||||
$wpdb->prepare( "SELECT post_type, post_name FROM {$wpdb->posts} WHERE id=%d", $permalink_query_vars['p'] ),
|
||||
ARRAY_N
|
||||
);
|
||||
} else {
|
||||
if ( empty( $this->custom_post_query_vars ) || empty( $this->taxonomies_query_vars ) ) {
|
||||
$this->init_query_vars();
|
||||
}
|
||||
foreach ( $this->custom_post_query_vars as $query_vars_key => $query_vars_value ) {
|
||||
if ( isset( $permalink_query_vars[ $query_vars_value ] ) ) {
|
||||
$post_name = $permalink_query_vars[ $query_vars_value ];
|
||||
$post_type = $query_vars_key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
foreach ( $this->taxonomies_query_vars as $query_vars_value ) {
|
||||
if ( isset( $permalink_query_vars[ $query_vars_value ] ) ) {
|
||||
$tax_name = $permalink_query_vars[ $query_vars_value ];
|
||||
$tax_type = $query_vars_value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $post_name && isset( $post_type ) ) {
|
||||
$get_page_by_path = new WPML_Get_Page_By_Path( $wpdb, $sitepress, new WPML_Debug_BackTrace( null, 7 ) );
|
||||
$p = $get_page_by_path->get( $post_name, $test_language, OBJECT, $post_type );
|
||||
|
||||
if ( empty( $p ) ) { // Fail safe.
|
||||
$switchLang = new WPML_Temporary_Switch_Language( $sitepress, $test_language );
|
||||
remove_filter( 'url_to_postid', array( $sitepress, 'url_to_postid' ) );
|
||||
$post_id = url_to_postid( $home_path . '/' . $post_name );
|
||||
add_filter( 'url_to_postid', array( $sitepress, 'url_to_postid' ) );
|
||||
$switchLang->restore_lang();
|
||||
|
||||
if ( $post_id ) {
|
||||
$p = get_post( $post_id );
|
||||
}
|
||||
}
|
||||
|
||||
if ( $p ) {
|
||||
$offsite_url = get_post_meta( $p->ID, '_cms_nav_offsite_url', true );
|
||||
if ( 'page' === $p->post_type && $offsite_url ) {
|
||||
$def_url = $this->get_regex_replacement_offline(
|
||||
$def_url,
|
||||
$offsite_url,
|
||||
$sitepress_settings['language_negotiation_type'],
|
||||
$lang,
|
||||
$dir_path,
|
||||
$home_url,
|
||||
$anchor_output
|
||||
);
|
||||
} elseif ( ! $this->is_pagination_in_post( $dir_path, $post_name ) ) {
|
||||
$def_url = $this->get_regex_replacement(
|
||||
$def_url,
|
||||
'page' === $p->post_type ? 'page_id' : 'p',
|
||||
$p->ID,
|
||||
$sitepress_settings['language_negotiation_type'],
|
||||
$lang,
|
||||
$dir_path,
|
||||
$home_url,
|
||||
$url_parts,
|
||||
$req_uri_params,
|
||||
$anchor_output
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$alp_broken_links[ $alp_matches[2][ $k ] ] = [];
|
||||
|
||||
$name = wpml_like_escape( $post_name );
|
||||
$p = $this->_get_ids_and_post_types( $name );
|
||||
if ( $p ) {
|
||||
foreach ( $p as $post_suggestion ) {
|
||||
if ( 'page' === $post_suggestion->post_type ) {
|
||||
$qvid = 'page_id';
|
||||
} else {
|
||||
$qvid = 'p';
|
||||
}
|
||||
$alp_broken_links[ $alp_matches[2][ $k ] ]['suggestions'][] = [
|
||||
'absolute' => '/' . ltrim( $url_parts['path'], '/' ) . '?' . $qvid . '=' . $post_suggestion->ID,
|
||||
'perma' => '/' . ltrim( str_replace( site_url(), '', get_permalink( $post_suggestion->ID ) ), '/' ),
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
} elseif ( $category_name ) {
|
||||
if ( false !== strpos( $category_name, '/' ) ) {
|
||||
$splits = explode( '/', $category_name );
|
||||
$category_name = array_pop( $splits );
|
||||
$category_parent = array_pop( $splits );
|
||||
$category_parent_id = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM {$wpdb->terms} WHERE slug=%s", $category_parent ) );
|
||||
$c = $wpdb->get_row( $wpdb->prepare( "SELECT t.term_id FROM {$wpdb->terms} t JOIN {$wpdb->term_taxonomy} x ON x.term_id=t.term_id AND x.taxonomy='category' AND x.parent=%d AND t.slug=%s", $category_parent_id, $category_name ) );
|
||||
} else {
|
||||
$c = $wpdb->get_row( $wpdb->prepare( "SELECT term_id FROM {$wpdb->terms} WHERE slug=%s", $category_name ) );
|
||||
}
|
||||
if ( $c ) {
|
||||
$def_url = $this->get_regex_replacement(
|
||||
$def_url,
|
||||
'cat_ID',
|
||||
$c->term_id,
|
||||
$sitepress_settings['language_negotiation_type'],
|
||||
$lang,
|
||||
$dir_path,
|
||||
$home_url,
|
||||
$url_parts,
|
||||
$req_uri_params,
|
||||
$anchor_output
|
||||
);
|
||||
} elseif ( isset( $name ) ) {
|
||||
$alp_broken_links[ $alp_matches[2][ $k ] ] = [];
|
||||
|
||||
$c = $wpdb->get_results(
|
||||
$wpdb->prepare( "SELECT term_id FROM {$wpdb->terms} WHERE slug LIKE %s", [ $name . '%' ] )
|
||||
);
|
||||
if ( $c ) {
|
||||
foreach ( $c as $cat_suggestion ) {
|
||||
$perma = '/' . ltrim( str_replace( get_home_url(), '', get_category_link( $cat_suggestion->term_id ) ), '/' );
|
||||
|
||||
$alp_broken_links[ $alp_matches[2][ $k ] ]['suggestions'][] = [
|
||||
'absolute' => '?cat_ID=' . $cat_suggestion->term_id,
|
||||
'perma' => $perma,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
} elseif ( $tax_name && isset( $tax_type ) ) {
|
||||
$def_url = $this->get_regex_replacement(
|
||||
$def_url,
|
||||
$tax_type,
|
||||
$tax_name,
|
||||
$sitepress_settings['language_negotiation_type'],
|
||||
$lang,
|
||||
$dir_path,
|
||||
$home_url,
|
||||
$url_parts,
|
||||
$req_uri_params,
|
||||
$anchor_output
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $def_url ) ) {
|
||||
$text = preg_replace( array_keys( $def_url ), array_values( $def_url ), $text );
|
||||
}
|
||||
|
||||
$tx_qvs = ! empty( $this->taxonomies_query_vars ) && is_array( $this->taxonomies_query_vars ) ? '|' . join( '|', $this->taxonomies_query_vars ) : '';
|
||||
$post_qvs = ! empty( $this->custom_posts_query_vars ) && is_array( $this->custom_posts_query_vars ) ? '|' . join( '|', $this->custom_posts_query_vars ) : '';
|
||||
$int = preg_match_all( '@href=[\'"](' . rtrim( get_home_url(), '/' ) . '/?\?(p|page_id' . $tx_qvs . $post_qvs . ')=([0-9a-z-]+)(#.+)?)[\'"]@i', $text, $matches2 );
|
||||
if ( $int ) {
|
||||
$url_parts = wp_parse_url( rtrim( get_home_url(), '/' ) . '/' );
|
||||
$text = preg_replace( '@href=[\'"](' . rtrim( get_home_url(), '/' ) . '/?\?(p|page_id' . $tx_qvs . $post_qvs . ')=([0-9a-z-]+)(#.+)?)[\'"]@i', 'href="/' . ltrim( $url_parts['path'], '/' ) . '?$2=$3$4"', $text );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$text = $block_protector->unProtect( $text );
|
||||
|
||||
WPML_Non_Persistent_Cache::set( $cache_key, $text, $cache_group );
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
private function get_home_url_with_no_lang_directory() {
|
||||
global $sitepress, $sitepress_settings;
|
||||
$sitepress_settings = $sitepress->get_settings();
|
||||
|
||||
$home_url = rtrim( get_home_url(), '/' );
|
||||
if ( 1 === $sitepress_settings['language_negotiation_type'] ) {
|
||||
// Strip lang directory from end if it's there.
|
||||
$exp = explode( '/', $home_url );
|
||||
$lang = end( $exp );
|
||||
|
||||
if ( $this->does_lang_exist( $lang ) ) {
|
||||
$home_url = substr( $home_url, 0, strlen( $home_url ) - strlen( $lang ) );
|
||||
}
|
||||
}
|
||||
|
||||
return $home_url;
|
||||
}
|
||||
|
||||
private function does_lang_exist( $lang ) {
|
||||
return in_array( $lang, $this->active_languages, true );
|
||||
}
|
||||
|
||||
public function _get_ids_and_post_types( $name ) {
|
||||
global $wpdb;
|
||||
static $cache = [];
|
||||
|
||||
$name = rawurlencode( $name );
|
||||
if ( ! isset( $cache[ $name ] ) ) {
|
||||
$cache[ $name ] = $wpdb->get_results( $wpdb->prepare( "SELECT ID, post_type FROM {$wpdb->posts} WHERE post_name LIKE %s AND post_type IN('post','page')", $name . '%' ) );
|
||||
}
|
||||
|
||||
return $cache[ $name ];
|
||||
}
|
||||
|
||||
private function initialize_rewrite( $current_language, $default_language, $sitepress ) {
|
||||
global $wp_rewrite;
|
||||
|
||||
$key = $current_language . $default_language;
|
||||
$found = false;
|
||||
$rewrite = WPML_Non_Persistent_Cache::get( $key, __CLASS__, $found );
|
||||
if ( $found ) {
|
||||
return $rewrite;
|
||||
}
|
||||
|
||||
if ( ! isset( $wp_rewrite ) ) {
|
||||
require_once ABSPATH . WPINC . '/rewrite.php';
|
||||
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
|
||||
$wp_rewrite = new WP_Rewrite();
|
||||
}
|
||||
|
||||
if ( $current_language === $default_language ) {
|
||||
$rewrite = $wp_rewrite->wp_rewrite_rules();
|
||||
} else {
|
||||
remove_filter( 'option_rewrite_rules', [ $sitepress, 'rewrite_rules_filter' ] );
|
||||
add_filter( 'wpml_st_disable_rewrite_rules', '__return_true' );
|
||||
|
||||
$rewrite = $wp_rewrite->wp_rewrite_rules();
|
||||
|
||||
remove_filter( 'wpml_st_disable_rewrite_rules', '__return_true' );
|
||||
}
|
||||
|
||||
$rewrite = $this->all_rewrite_rules( $rewrite );
|
||||
WPML_Non_Persistent_Cache::set( $key, $rewrite, __CLASS__ );
|
||||
|
||||
return $rewrite;
|
||||
}
|
||||
|
||||
public function all_rewrite_rules( $rewrite ) {
|
||||
global $sitepress;
|
||||
|
||||
if ( ! class_exists( 'WPML\ST\SlugTranslation\Hooks\Hooks' ) ) {
|
||||
return $rewrite;
|
||||
}
|
||||
|
||||
$active_languages = $sitepress->get_active_languages();
|
||||
$current_language = $sitepress->get_current_language();
|
||||
$default_language = $sitepress->get_default_language();
|
||||
|
||||
$cache_keys = [ $current_language, $default_language ];
|
||||
$cache_keys[] = md5( wp_json_encode( $active_languages ) );
|
||||
$cache_keys[] = md5( wp_json_encode( $rewrite ) );
|
||||
$cache_key = implode( ':', $cache_keys );
|
||||
$cache_group = 'all_rewrite_rules';
|
||||
$cache_found = false;
|
||||
|
||||
$final_rules = WPML_Non_Persistent_Cache::get( $cache_key, $cache_group, $cache_found );
|
||||
|
||||
if ( $cache_found ) {
|
||||
return $final_rules;
|
||||
}
|
||||
|
||||
$final_rules = $rewrite;
|
||||
|
||||
foreach ( $active_languages as $next_language ) {
|
||||
|
||||
if ( $next_language['code'] === $default_language ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$sitepress->switch_lang( $next_language['code'] );
|
||||
|
||||
$translated_rules = ( new \WPML\ST\SlugTranslation\Hooks\HooksFactory() )->create()->filter( $final_rules );
|
||||
|
||||
if ( is_array( $translated_rules ) && is_array( $final_rules ) ) {
|
||||
$new_rules = array_diff_assoc( $translated_rules, $final_rules );
|
||||
|
||||
$final_rules = array_merge( $new_rules, $final_rules );
|
||||
}
|
||||
}
|
||||
|
||||
$sitepress->switch_lang( $current_language );
|
||||
|
||||
WPML_Non_Persistent_Cache::set( $cache_key, $final_rules, $cache_group );
|
||||
|
||||
return $final_rules;
|
||||
|
||||
}
|
||||
|
||||
private function get_regex_replacement(
|
||||
$def_url,
|
||||
$type,
|
||||
$type_id,
|
||||
$lang_negotiation,
|
||||
$lang,
|
||||
$dir_path,
|
||||
$home_url,
|
||||
$url_parts,
|
||||
$req_uri_params,
|
||||
$anchor_output
|
||||
) {
|
||||
|
||||
$type_id = $this->maybeStripParentTerm( $type_id );
|
||||
|
||||
if ( 1 === $lang_negotiation && $lang ) {
|
||||
$langprefix = '/' . $lang;
|
||||
} else {
|
||||
$langprefix = '';
|
||||
}
|
||||
$perm_url = '(' . rtrim( $home_url, '/' ) . ')?' . $langprefix . '/' . str_replace( '?', '\?', $dir_path );
|
||||
$regk = '@href=[\'"](' . self::escapePlusSign( $perm_url ) . ')[\'"]@i';
|
||||
$regv = 'href="/' . ltrim( $url_parts['path'], '/' ) . '?' . $type . '=' . $type_id;
|
||||
if ( '' !== $req_uri_params ) {
|
||||
$regv .= '&' . $req_uri_params;
|
||||
}
|
||||
$regv .= $anchor_output . '"';
|
||||
|
||||
$def_url[ $regk ] = $regv;
|
||||
|
||||
return $def_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split parent/child term slug and get only the last part.
|
||||
*
|
||||
* @see https://onthegosystems.myjetbrains.com/youtrack/issue/wpmlcore-7036
|
||||
*
|
||||
* If $typeId is a child term of some taxonomy, then it comes here as `parent/child'
|
||||
* in next stages WordPress will use it in url like `?category=parent/child` and will try to resolve
|
||||
* what category has slug `parent/child'. WordPress must actually try to find just `child` so the code
|
||||
* below gets only last part of slash containing $typeId
|
||||
*
|
||||
* @param string $typeId Type slug.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function maybeStripParentTerm( $typeId ) {
|
||||
return Lst::nth( -1, Str::split( '/', $typeId ) );
|
||||
}
|
||||
|
||||
private function get_regex_replacement_offline(
|
||||
$def_url,
|
||||
$offsite_url,
|
||||
$lang_negotiation,
|
||||
$lang,
|
||||
$dir_path,
|
||||
$home_url,
|
||||
$anchor_output
|
||||
) {
|
||||
if ( 1 === $lang_negotiation && $lang ) {
|
||||
$langprefix = '/' . $lang;
|
||||
} else {
|
||||
$langprefix = '';
|
||||
}
|
||||
$perm_url = '(' . rtrim( $home_url, '/' ) . ')?' . $langprefix . '/' . str_replace( '?', '\?', $dir_path );
|
||||
$regk = '@href=["\'](' . self::escapePlusSign( $perm_url ) . ')["\']@i';
|
||||
$regv = 'href="' . $offsite_url . $anchor_output . '"';
|
||||
|
||||
$def_url[ $regk ] = $regv;
|
||||
|
||||
return $def_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private static function escapePlusSign( $url ) {
|
||||
return str_replace( '+', '\+', $url );
|
||||
}
|
||||
|
||||
private function extract_lang_from_path( $sitepress_settings, $default_language, $dir_path ) {
|
||||
$lang = false;
|
||||
|
||||
if ( 1 === $sitepress_settings['language_negotiation_type'] ) {
|
||||
$exp = explode( '/', $dir_path, 2 );
|
||||
$lang = $exp[0];
|
||||
if ( $this->does_lang_exist( $lang ) ) {
|
||||
$dir_path = isset( $exp[1] ) ? $exp[1] : '';
|
||||
} else {
|
||||
$lang = false;
|
||||
}
|
||||
}
|
||||
|
||||
return [ $lang, $dir_path ];
|
||||
}
|
||||
|
||||
|
||||
public function process_string( $st_id ) {
|
||||
global $wpdb;
|
||||
if ( $st_id ) {
|
||||
|
||||
$table = $wpdb->prefix . 'icl_string_translations';
|
||||
|
||||
$data = $wpdb->get_row( $wpdb->prepare( "SELECT value, string_id, language FROM {$table} WHERE id=%d", $st_id ) );
|
||||
$string_value = $data->value;
|
||||
$string_type = $wpdb->get_var( $wpdb->prepare( "SELECT type FROM {$wpdb->prefix}icl_strings WHERE id=%d", $data->string_id ) );
|
||||
|
||||
if ( 'LINK' === $string_type ) {
|
||||
$string_value_up = $this->convert_url( $string_value, $data->language );
|
||||
} else {
|
||||
$string_value_up = $this->convert_text( $string_value );
|
||||
}
|
||||
|
||||
if ( $string_value_up !== $string_value ) {
|
||||
$wpdb->update(
|
||||
$table,
|
||||
[
|
||||
'value' => $string_value_up,
|
||||
'status' => ICL_STRING_TRANSLATION_COMPLETE,
|
||||
],
|
||||
[ 'id' => $st_id ]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function process_post( $post_id ) {
|
||||
global $wpdb, $sitepress;
|
||||
|
||||
delete_post_meta( $post_id, '_alp_broken_links' );
|
||||
|
||||
$post = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->posts} WHERE ID = %s", $post_id ) );
|
||||
|
||||
$this_post_language = $sitepress->get_language_for_element( $post_id, 'post_' . $post->post_type );
|
||||
$current_language = $sitepress->get_current_language();
|
||||
$sitepress->switch_lang( $this_post_language );
|
||||
|
||||
$post_content = $this->convert_text( $post->post_content );
|
||||
|
||||
$sitepress->switch_lang( $current_language );
|
||||
|
||||
if ( $post_content !== $post->post_content ) {
|
||||
$wpdb->update( $wpdb->posts, [ 'post_content' => $post_content ], [ 'ID' => $post_id ] );
|
||||
}
|
||||
|
||||
update_post_meta( $post_id, '_alp_processed', time() );
|
||||
}
|
||||
|
||||
public function convert_text( $text ) {
|
||||
$alp_broken_links = [];
|
||||
|
||||
return $this->_process_generic_text( $text, $alp_broken_links );
|
||||
}
|
||||
|
||||
public function convert_url( $url, $lang = null ) {
|
||||
global $sitepress;
|
||||
|
||||
if ( $this->is_home( $url ) ) {
|
||||
$absolute_url = $sitepress->convert_url( $url, $lang );
|
||||
} else {
|
||||
|
||||
$html = '<a href="' . $url . '">removeit</a>';
|
||||
$html = $this->convert_text( $html );
|
||||
$absolute_url = str_replace( [ '<a href="', '">removeit</a>' ], [ '', '' ], $html );
|
||||
}
|
||||
|
||||
return $absolute_url;
|
||||
}
|
||||
|
||||
public function is_home( $url ) {
|
||||
return untrailingslashit( get_home_url() ) === untrailingslashit( $url );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the link is the pagination inside the post.
|
||||
*
|
||||
* @param string $url
|
||||
* @param string $post_name
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_pagination_in_post( $url, $post_name ) {
|
||||
$is_pagination_url_in_post = false !== mb_strpos( $url, $post_name . '/page/' );
|
||||
|
||||
/**
|
||||
* Check if the given URL is the pagination inside the post.
|
||||
*
|
||||
* @param bool $is_pagination_url_in_post
|
||||
* @param string $url
|
||||
* @param string $post_name
|
||||
*/
|
||||
return apply_filters( 'wpml_is_pagination_url_in_post', $is_pagination_url_in_post, $url, $post_name );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
|
||||
class WPML_TM_Action_Helper {
|
||||
|
||||
public function get_tm_instance() {
|
||||
|
||||
return wpml_load_core_tm();
|
||||
}
|
||||
|
||||
public function create_translation_package( $post ) {
|
||||
$package_helper = new WPML_Element_Translation_Package();
|
||||
|
||||
return $package_helper->create_translation_package( $post );
|
||||
}
|
||||
|
||||
public function add_translation_job( $rid, $translator_id, $translation_package, $batch_options = array() ) {
|
||||
|
||||
return $this->get_update_translation_action( $translation_package )
|
||||
->add_translation_job( $rid, $translator_id, $translation_package, $batch_options );
|
||||
}
|
||||
|
||||
/**
|
||||
* calculate post md5
|
||||
*
|
||||
* @param object|int $post
|
||||
*
|
||||
* @return string
|
||||
* @todo full support for custom posts and custom taxonomies
|
||||
*/
|
||||
public function post_md5( $post ) {
|
||||
$post_key = '';
|
||||
|
||||
// TODO: [WPML 3.2] Make it work with PackageTranslation: this is not the right way anymore
|
||||
if ( isset( $post->external_type ) && $post->external_type ) {
|
||||
foreach ( $post->string_data as $key => $value ) {
|
||||
$post_key .= $key . $value;
|
||||
}
|
||||
} else {
|
||||
if ( is_numeric( $post ) ) {
|
||||
$post = get_post( $post );
|
||||
}
|
||||
|
||||
$post_tags = $this->get_post_terms( $post, 'post_tag' );
|
||||
$post_categories = $this->get_post_terms( $post, 'category' );
|
||||
$post_taxonomies = $this->get_post_taxonomies( $post );
|
||||
$custom_fields_values = $this->get_post_custom_fields( $post );
|
||||
|
||||
$content = $post->post_content;
|
||||
$content = apply_filters( 'wpml_pb_shortcode_content_for_translation', $content, $post->ID );
|
||||
|
||||
/**
|
||||
* Filters the post content used to build the post md5.
|
||||
*
|
||||
* @since 2.10.0
|
||||
* @internal
|
||||
*
|
||||
* @param string $content
|
||||
* @param WP_Post $post
|
||||
*/
|
||||
$content = apply_filters( 'wpml_tm_post_md5_content', $content, $post );
|
||||
|
||||
$post_key = $post->post_title . ';' . $content . ';' . $post->post_excerpt . ';' . implode( ',', $post_tags ) . ';' . implode( ',', $post_categories ) . ';' . implode( ',', $custom_fields_values );
|
||||
|
||||
if ( ! empty( $post_taxonomies ) ) {
|
||||
$post_key .= ';' . implode( ';', $post_taxonomies );
|
||||
}
|
||||
if ( wpml_get_setting_filter( false, 'translated_document_page_url' ) === 'translate' ) {
|
||||
$post_key .= $post->post_name . ';';
|
||||
}
|
||||
}
|
||||
|
||||
$post_key = apply_filters( 'wpml_post_md5_key', $post_key, $post );
|
||||
|
||||
return md5( $post_key );
|
||||
}
|
||||
|
||||
private function get_post_terms( $post, $taxonomy, $sort = false ) {
|
||||
global $sitepress;
|
||||
|
||||
$terms = array();
|
||||
// we shouldn't adjust term by current language need get terms by post_id
|
||||
$hasFilter = remove_filter( 'get_term', array( $sitepress, 'get_term_adjust_id' ), 1 );
|
||||
|
||||
$post_taxonomy_terms = wp_get_object_terms( $post->ID, $taxonomy );
|
||||
if ( ! is_wp_error( $post_taxonomy_terms ) ) {
|
||||
foreach ( $post_taxonomy_terms as $trm ) {
|
||||
$terms[] = $trm->name;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $terms ) {
|
||||
sort( $terms, SORT_STRING );
|
||||
}
|
||||
|
||||
if ( $hasFilter ) {
|
||||
add_filter( 'get_term', array( $sitepress, 'get_term_adjust_id' ), 1, 1 );
|
||||
}
|
||||
|
||||
return $terms;
|
||||
}
|
||||
|
||||
private function get_post_taxonomies( $post ) {
|
||||
global $wpdb, $sitepress_settings;
|
||||
|
||||
$post_taxonomies = array();
|
||||
|
||||
// get custom taxonomies
|
||||
$taxonomies = $wpdb->get_col(
|
||||
$wpdb->prepare(
|
||||
"
|
||||
SELECT DISTINCT tx.taxonomy
|
||||
FROM {$wpdb->term_taxonomy} tx JOIN {$wpdb->term_relationships} tr ON tx.term_taxonomy_id = tr.term_taxonomy_id
|
||||
WHERE tr.object_id =%d ",
|
||||
$post->ID
|
||||
)
|
||||
);
|
||||
sort( $taxonomies, SORT_STRING );
|
||||
if ( isset( $sitepress_settings['taxonomies_sync_option'] ) ) {
|
||||
foreach ( $taxonomies as $t ) {
|
||||
if ( taxonomy_exists( $t ) && isset( $sitepress_settings['taxonomies_sync_option'][ $t ] ) && $sitepress_settings['taxonomies_sync_option'][ $t ] == 1 ) {
|
||||
$taxs = $this->get_post_terms( $post, $t );
|
||||
|
||||
if ( $taxs ) {
|
||||
$post_taxonomies[] = '[' . $t . ']:' . implode( ',', $taxs );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $post_taxonomies;
|
||||
}
|
||||
|
||||
private function get_post_custom_fields( $post ) {
|
||||
$custom_fields_values = array();
|
||||
|
||||
foreach ( \WPML\TM\Settings\Repository::getCustomFields() as $cf => $op ) {
|
||||
if ( in_array( (int) $op, array( WPML_TRANSLATE_CUSTOM_FIELD, WPML_COPY_ONCE_CUSTOM_FIELD ), true ) ) {
|
||||
$value = get_post_meta( $post->ID, $cf, true );
|
||||
if ( is_scalar( $value ) ) {
|
||||
$custom_fields_values[ $cf ] = $value;
|
||||
} else {
|
||||
$custom_fields_values[ $cf ] = wp_json_encode( $value );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$custom_fields_values = apply_filters( 'wpml_custom_field_values_for_post_signature', $custom_fields_values, $post->ID );
|
||||
return $custom_fields_values;
|
||||
}
|
||||
|
||||
private function get_update_translation_action( $translation_package ) {
|
||||
require_once WPML_TM_PATH . '/inc/translation-jobs/helpers/wpml-update-external-translation-data-action.class.php';
|
||||
require_once WPML_TM_PATH . '/inc/translation-jobs/helpers/wpml-update-post-translation-data-action.class.php';
|
||||
|
||||
return array_key_exists( 'type', $translation_package ) && $translation_package['type'] === 'post'
|
||||
? new WPML_TM_Update_Post_Translation_Data_Action() : new WPML_TM_Update_External_Translation_Data_Action();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
<?php
|
||||
|
||||
class WPML_TM_Post_Actions extends WPML_Translation_Job_Helper {
|
||||
|
||||
/** @var WPML_TM_Action_Helper $action_helper */
|
||||
private $action_helper;
|
||||
|
||||
/** @var WPML_TM_Blog_Translators $blog_translators */
|
||||
private $blog_translators;
|
||||
|
||||
/** @var WPML_TM_Records $tm_records */
|
||||
private $tm_records;
|
||||
|
||||
/**
|
||||
* WPML_TM_Post_Actions constructor.
|
||||
*
|
||||
* @param WPML_TM_Action_Helper $helper
|
||||
* @param WPML_TM_Blog_Translators $blog_translators
|
||||
* @param WPML_TM_Records $tm_records
|
||||
*/
|
||||
public function __construct(
|
||||
WPML_TM_Action_Helper $helper,
|
||||
WPML_TM_Blog_Translators $blog_translators,
|
||||
WPML_TM_Records $tm_records )
|
||||
{
|
||||
$this->action_helper = $helper;
|
||||
$this->blog_translators = $blog_translators;
|
||||
$this->tm_records = $tm_records;
|
||||
}
|
||||
|
||||
public function save_post_actions( $post_id, $post, $force_set_status = false ) {
|
||||
global $wpdb, $sitepress, $current_user;
|
||||
|
||||
$trid = isset( $_POST['icl_trid'] ) && is_numeric( $_POST['icl_trid'] )
|
||||
? $_POST['icl_trid'] : $sitepress->get_element_trid( $post_id, 'post_' . $post->post_type );
|
||||
|
||||
// set trid and lang code if front-end translation creating
|
||||
$trid = apply_filters( 'wpml_tm_save_post_trid_value', isset( $trid ) ? $trid : '', $post_id );
|
||||
$lang = apply_filters( 'wpml_tm_save_post_lang_value', '', $post_id );
|
||||
|
||||
$trid = $this->maybe_retrive_trid_again( $trid, $post );
|
||||
$needs_second_update = array_key_exists( 'needs_second_update', $_POST ) ? (bool) $_POST['needs_second_update'] : false;
|
||||
|
||||
// is this the original document?
|
||||
$is_original = empty( $trid )
|
||||
? false
|
||||
: ! (bool) $this->tm_records
|
||||
->icl_translations_by_element_id_and_type_prefix( $post_id, 'post_' . $post->post_type )
|
||||
->source_language_code();
|
||||
|
||||
if( $is_original ){
|
||||
$this->save_translation_priority( $post_id );
|
||||
}
|
||||
|
||||
if ( ! empty( $trid ) && ! $is_original ) {
|
||||
$lang = $lang ? $lang : $this->get_save_post_lang( $lang, $post_id );
|
||||
$res = $wpdb->get_row( $wpdb->prepare( "
|
||||
SELECT element_id, language_code FROM {$wpdb->prefix}icl_translations WHERE trid=%d AND source_language_code IS NULL
|
||||
",
|
||||
$trid ) );
|
||||
if ( $res ) {
|
||||
$original_post_id = $res->element_id;
|
||||
$from_lang = $res->language_code;
|
||||
$original_post = get_post( $original_post_id );
|
||||
$md5 = $this->action_helper->post_md5( $original_post );
|
||||
$translation_id = $this->tm_records
|
||||
->icl_translations_by_trid_and_lang( $trid, $lang )
|
||||
->translation_id();
|
||||
$user_id = $current_user->ID;
|
||||
$this->maybe_add_as_translator( $user_id, $lang, $from_lang );
|
||||
if ( $translation_id ) {
|
||||
$translation_package = $this->action_helper->create_translation_package( $original_post_id );
|
||||
list( $rid, $update ) = $this->action_helper->get_tm_instance()->update_translation_status( array(
|
||||
'translation_id' => $translation_id,
|
||||
'status' => isset( $force_set_status ) && $force_set_status > 0 ? $force_set_status : ICL_TM_COMPLETE,
|
||||
'translator_id' => $user_id,
|
||||
'needs_update' => $needs_second_update,
|
||||
'md5' => $md5,
|
||||
'translation_service' => 'local',
|
||||
'translation_package' => serialize( $translation_package )
|
||||
) );
|
||||
if ( ! $update ) {
|
||||
$job_id = $this->action_helper->add_translation_job( $rid, $user_id, $translation_package );
|
||||
} else {
|
||||
$job_id = \WPML\TM\API\Job\Map::fromRid( $rid );
|
||||
if ( ! $job_id ) {
|
||||
$job_id = $this->action_helper->add_translation_job(
|
||||
$rid,
|
||||
$user_id,
|
||||
$translation_package
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
wpml_tm_load_old_jobs_editor()->set( $job_id, WPML_TM_Editors::WP );
|
||||
|
||||
// saving the translation
|
||||
do_action( 'wpml_save_job_fields_from_post', $job_id );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $trid ) && empty( $_POST['icl_minor_edit'] ) ) {
|
||||
$is_original = false;
|
||||
$translations = $sitepress->get_element_translations( $trid, 'post_' . $post->post_type );
|
||||
foreach ( $translations as $translation ) {
|
||||
if ( $translation->original == 1 && $translation->element_id == $post_id ) {
|
||||
$is_original = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $is_original ) {
|
||||
$statusesUpdater = $this->get_translation_statuses_updater( $post_id, $translations );
|
||||
|
||||
/**
|
||||
* The filter allows to delegate the status update for translations.
|
||||
*
|
||||
* @param bool false (default) if we should update immediately or true if done at a different stage.
|
||||
* @param int $post_id The original post ID.
|
||||
* @param callable The updater function to execute.
|
||||
*
|
||||
* @since 2.11.0
|
||||
*
|
||||
*/
|
||||
if ( ! apply_filters( 'wpml_tm_delegate_translation_statuses_update', false, $post_id, $statusesUpdater ) ) {
|
||||
call_user_func( $statusesUpdater );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
* @param stdClass[] $translations
|
||||
*
|
||||
* @return Closure
|
||||
*/
|
||||
public function get_translation_statuses_updater( $post_id, $translations ) {
|
||||
return function () use ( $post_id, $translations ) {
|
||||
$needsUpdate = false;
|
||||
$md5 = $this->action_helper->post_md5( $post_id );
|
||||
foreach ( $translations as $translation ) {
|
||||
if ( ! $translation->original ) {
|
||||
$statusRecord = $this->tm_records->icl_translation_status_by_translation_id( $translation->translation_id );
|
||||
if ( $md5 !== $statusRecord->md5() ) {
|
||||
$needsUpdate = true;
|
||||
$status = $statusRecord->status();
|
||||
$translation_package = $this->action_helper->create_translation_package( $post_id );
|
||||
$data = [
|
||||
'translation_id' => $translation->translation_id,
|
||||
'needs_update' => 1,
|
||||
'md5' => $md5,
|
||||
'translation_package' => serialize( $translation_package ),
|
||||
'status' => $status === ICL_TM_ATE_CANCELLED ? ICL_TM_NOT_TRANSLATED : $status,
|
||||
];
|
||||
$this->action_helper->get_tm_instance()->update_translation_status( $data );
|
||||
}
|
||||
}
|
||||
}
|
||||
return $needsUpdate;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given language pair to the user.
|
||||
*
|
||||
* @param int $user_id
|
||||
* @param string $target_lang
|
||||
* @param string $source_lang
|
||||
*
|
||||
* @used-by \WPML_TM_Post_Actions::save_post_actions to add language pairs to admin users automatically when saving
|
||||
* a translation in a given language pair.
|
||||
*/
|
||||
private function maybe_add_as_translator( $user_id, $target_lang, $source_lang ) {
|
||||
|
||||
$user = new WP_User( $user_id );
|
||||
if ( $user->has_cap( 'manage_options' ) && $target_lang && ! $this->blog_translators->is_translator( $user_id,
|
||||
array(
|
||||
'lang_from' => $source_lang,
|
||||
'lang_to' => $target_lang,
|
||||
'admin_override' => false
|
||||
) )
|
||||
) {
|
||||
global $wpdb;
|
||||
|
||||
$user->add_cap( WPML_Translator_Role::CAPABILITY );
|
||||
|
||||
$language_pair_records = new WPML_Language_Pair_Records( $wpdb, new WPML_Language_Records( $wpdb ) );
|
||||
$language_pair_records->store( $user_id, array( $source_lang => array( $target_lang ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
private function get_save_post_lang( $lang, $post_id ) {
|
||||
if ( ( ! isset( $lang ) || ! $lang ) && ! empty( $_POST['icl_post_language'] ) ) {
|
||||
$lang = $_POST['icl_post_language'];
|
||||
} else {
|
||||
global $wpml_post_translations;
|
||||
|
||||
$lang = $wpml_post_translations->get_element_lang_code( $post_id );
|
||||
}
|
||||
|
||||
return $lang;
|
||||
}
|
||||
|
||||
private function maybe_retrive_trid_again( $trid, $post ) {
|
||||
global $wpdb, $sitepress;
|
||||
$element_type_from_trid = $wpdb->get_var( $wpdb->prepare( "SELECT element_type FROM {$wpdb->prefix}icl_translations WHERE trid=%d", $trid ) );
|
||||
if ( $element_type_from_trid && $post->post_type !== $element_type_from_trid ) {
|
||||
$trid = $sitepress->get_element_trid( $post->ID, 'post_' . $post->post_type );
|
||||
}
|
||||
|
||||
return $trid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
*/
|
||||
public function save_translation_priority( $post_id ) {
|
||||
$translation_priority = (int) filter_var(
|
||||
( isset( $_POST['icl_translation_priority'] ) ? $_POST['icl_translation_priority'] : '' ),
|
||||
FILTER_SANITIZE_NUMBER_INT );
|
||||
|
||||
if ( ! $translation_priority ) {
|
||||
$assigned_priority = $this->get_term_obj( $post_id );
|
||||
|
||||
if ( $assigned_priority ) {
|
||||
$translation_priority = $assigned_priority->term_id;
|
||||
} else {
|
||||
$term = \WPML_TM_Translation_Priorities::get_default_term();
|
||||
if ( $term ) {
|
||||
$translation_priority = $term->term_id;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if ( $translation_priority ) {
|
||||
wp_set_post_terms( $post_id, array( $translation_priority ), \WPML_TM_Translation_Priorities::TAXONOMY );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $element_id
|
||||
*
|
||||
* @return WP_Term|null
|
||||
*/
|
||||
private function get_term_obj( $element_id ) {
|
||||
$terms = wp_get_object_terms( $element_id, \WPML_TM_Translation_Priorities::TAXONOMY );
|
||||
if ( is_wp_error( $terms ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return empty( $terms ) ? null : $terms[0];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
global $wpdb;
|
||||
|
||||
$basket_ajax = new WPML_Basket_Tab_Ajax(
|
||||
TranslationProxy::get_current_project(),
|
||||
wpml_tm_load_basket_networking(),
|
||||
new WPML_Translation_Basket( $wpdb )
|
||||
);
|
||||
add_action( 'init', array( $basket_ajax, 'init' ) );
|
||||
189
wp-content/plugins/sitepress-multilingual-cms/inc/cache.php
Normal file
189
wp-content/plugins/sitepress-multilingual-cms/inc/cache.php
Normal file
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ICL_DISABLE_CACHE' ) ) {
|
||||
define( 'ICL_DISABLE_CACHE', false );
|
||||
}
|
||||
|
||||
// phpcs:disable PEAR.NamingConventions.ValidClassName.Invalid
|
||||
// phpcs:disable PEAR.NamingConventions.ValidClassName.StartWithCapital
|
||||
|
||||
/**
|
||||
* Class icl_cache
|
||||
*/
|
||||
class icl_cache {
|
||||
|
||||
/** @var array */
|
||||
protected $data;
|
||||
|
||||
/** @var string */
|
||||
protected $name;
|
||||
|
||||
/** @var bool */
|
||||
protected $cache_to_option;
|
||||
|
||||
/** @var bool */
|
||||
protected $cache_needs_saving;
|
||||
|
||||
public function __construct( $name = '', $cache_to_option = false ) {
|
||||
$this->data = [];
|
||||
$this->name = $name;
|
||||
$this->cache_to_option = $cache_to_option;
|
||||
$this->cache_needs_saving = false;
|
||||
|
||||
$this->init();
|
||||
}
|
||||
|
||||
public function init() {
|
||||
if ( $this->cache_to_option ) {
|
||||
$this->data = icl_cache_get( $this->name . '_cache_class' );
|
||||
if ( false === $this->data ) {
|
||||
$this->data = [];
|
||||
}
|
||||
|
||||
add_action( 'shutdown', [ $this, 'save_cache_if_required' ] );
|
||||
}
|
||||
}
|
||||
|
||||
public function save_cache_if_required() {
|
||||
if ( $this->cache_needs_saving ) {
|
||||
icl_cache_set( $this->name . '_cache_class', $this->data );
|
||||
$this->cache_needs_saving = false;
|
||||
}
|
||||
}
|
||||
|
||||
public function get( $key ) {
|
||||
if ( ICL_DISABLE_CACHE ) {
|
||||
return null;
|
||||
}
|
||||
return isset( $this->data[ $key ] ) ? $this->data[ $key ] : false;
|
||||
}
|
||||
|
||||
public function has_key( $key ) {
|
||||
if ( ICL_DISABLE_CACHE ) {
|
||||
return false;
|
||||
}
|
||||
return array_key_exists( $key, (array) $this->data );
|
||||
}
|
||||
|
||||
public function set( $key, $value ) {
|
||||
if ( ICL_DISABLE_CACHE ) {
|
||||
return;
|
||||
}
|
||||
if ( $this->cache_to_option ) {
|
||||
$old_value = null;
|
||||
if ( isset( $this->data[ $key ] ) ) {
|
||||
$old_value = $this->data[ $key ];
|
||||
}
|
||||
if ( $old_value !== $value ) {
|
||||
$this->data[ $key ] = $value;
|
||||
$this->cache_needs_saving = true;
|
||||
}
|
||||
} else {
|
||||
$this->data[ $key ] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
public function clear() {
|
||||
$this->data = array();
|
||||
if ( $this->cache_to_option ) {
|
||||
icl_cache_clear( $this->name . '_cache_class' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'icl_disable_cache' ) ) {
|
||||
function icl_disable_cache() {
|
||||
return defined( 'ICL_DISABLE_CACHE' ) && ICL_DISABLE_CACHE;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'icl_cache_get' ) ) {
|
||||
function icl_cache_get( $key ) {
|
||||
$result = false;
|
||||
if ( ! icl_disable_cache() ) {
|
||||
$icl_cache = get_option( '_icl_cache' );
|
||||
|
||||
$result = isset( $icl_cache[ $key ] ) ? $icl_cache[ $key ] : false;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'icl_cache_set' ) ) {
|
||||
function icl_cache_set( $key, $value = null ) {
|
||||
|
||||
global $switched;
|
||||
if ( empty( $switched ) && ! icl_disable_cache() ) {
|
||||
$icl_cache = get_option( '_icl_cache' );
|
||||
if ( false === $icl_cache ) {
|
||||
$icl_cache = [];
|
||||
delete_option( '_icl_cache' );
|
||||
}
|
||||
|
||||
if ( ! isset( $icl_cache[ $key ] ) || $icl_cache[ $key ] !== $value ) {
|
||||
if ( ! is_null( $value ) ) {
|
||||
$icl_cache[ $key ] = $value;
|
||||
} elseif ( isset( $icl_cache[ $key ] ) ) {
|
||||
unset( $icl_cache[ $key ] );
|
||||
}
|
||||
|
||||
update_option( '_icl_cache', $icl_cache, 'no' );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'icl_cache_clear' ) ) {
|
||||
function icl_cache_clear( $key = false, $key_as_prefix = false ) {
|
||||
if ( ! icl_disable_cache() ) {
|
||||
/**
|
||||
* @var WPML_Term_Translation $wpml_term_translations
|
||||
* @var WPML_Post_Translation $wpml_post_translations
|
||||
*/
|
||||
global $wpml_term_translations, $wpml_post_translations;
|
||||
|
||||
$wpml_term_translations->reload();
|
||||
$wpml_post_translations->reload();
|
||||
|
||||
if ( false === $key ) {
|
||||
delete_option( '_icl_cache' );
|
||||
} else {
|
||||
/** @var array $icl_cache */
|
||||
$icl_cache = get_option( '_icl_cache' );
|
||||
|
||||
if ( is_array( $icl_cache ) ) {
|
||||
if ( isset( $icl_cache[ $key ] ) ) {
|
||||
unset( $icl_cache[ $key ] );
|
||||
}
|
||||
|
||||
if ( $key_as_prefix ) {
|
||||
$cache_keys = array_keys( $icl_cache );
|
||||
foreach ( $cache_keys as $cache_key ) {
|
||||
if ( strpos( $cache_key, $key ) === 0 ) {
|
||||
unset( $icl_cache[ $cache_key ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Special cache of 'per language' - clear different statuses.
|
||||
if ( false !== strpos( $key, '_per_language' ) ) {
|
||||
foreach ( $icl_cache as $k => $v ) {
|
||||
if ( false !== strpos( $k, $key . '#' ) ) {
|
||||
unset( $icl_cache[ $k ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
update_option( '_icl_cache', $icl_cache, 'no' );
|
||||
}
|
||||
}
|
||||
}
|
||||
do_action( 'wpml_cache_clear' );
|
||||
}
|
||||
}
|
||||
|
||||
function w3tc_translate_cache_key_filter( $key ) {
|
||||
global $sitepress;
|
||||
|
||||
return $sitepress->get_current_language() . $key;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
define( 'WPML_TM_FOLDER', 'tm' );
|
||||
|
||||
define( 'WPML_TM_URL', plugins_url( '', dirname( __FILE__ ) ) );
|
||||
|
||||
define( 'TP_MIGRATION_NOT_STARTED', 0 );
|
||||
define( 'TP_MIGRATION_REQUESTED', 2 );
|
||||
define( 'TP_MIGRATION_IN_PROGRESS', 3 );
|
||||
define( 'TP_MIGRATION_WAITING_CONFIRMATION', 4 );
|
||||
define( 'TP_MIGRATION_COMPLETED', 1 );
|
||||
|
||||
if ( ! defined( 'TRANSLATION_PROXY_XLIFF_VERSION' ) ) {
|
||||
define( 'TRANSLATION_PROXY_XLIFF_VERSION', '12' );
|
||||
}
|
||||
|
||||
if ( ! defined( 'WPML_XLIFF_TM_URL' ) ) {
|
||||
define( 'WPML_XLIFF_TM_URL', plugins_url( '', dirname( __FILE__ ) ) );
|
||||
}
|
||||
|
||||
if ( ! defined( 'WPML_XLIFF_TM_NEWLINES_REPLACE' ) ) {
|
||||
define( 'WPML_XLIFF_TM_NEWLINES_REPLACE', 1 ); }
|
||||
|
||||
if ( ! defined( 'WPML_XLIFF_TM_NEWLINES_ORIGINAL' ) ) {
|
||||
define( 'WPML_XLIFF_TM_NEWLINES_ORIGINAL', 2 ); }
|
||||
|
||||
if ( ! defined( 'WPML_XLIFF_DEFAULT_VERSION' ) ) {
|
||||
define( 'WPML_XLIFF_DEFAULT_VERSION', '12' );
|
||||
}
|
||||
if ( ! defined( 'TA_URL_ENDPOINT' ) ) {
|
||||
define( 'TA_URL_ENDPOINT', 'https://www.icanlocalize.com' );
|
||||
}
|
||||
|
||||
if ( ! defined( 'TA_SCHEDULE_OCCURENCE' ) ) {
|
||||
define( 'TA_SCHEDULE_OCCURENCE', 'daily' );
|
||||
}
|
||||
|
||||
if ( ! defined( 'JSON_UNESCAPED_UNICODE' ) ) {
|
||||
define( 'JSON_UNESCAPED_UNICODE', 256 );
|
||||
}
|
||||
|
||||
if ( ! defined( 'JSON_UNESCAPED_SLASHES' ) ) {
|
||||
define( 'JSON_UNESCAPED_SLASHES', 64 );
|
||||
}
|
||||
|
||||
global $asian_languages;
|
||||
$asian_languages = array( 'ja', 'ko', 'zh-hans', 'zh-hant', 'mn', 'ne', 'hi', 'pa', 'ta', 'th' );
|
||||
163
wp-content/plugins/sitepress-multilingual-cms/inc/constants.php
Normal file
163
wp-content/plugins/sitepress-multilingual-cms/inc/constants.php
Normal file
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
if ( file_exists( WPML_PLUGIN_PATH . '/inc/sandbox.inc' ) ) {
|
||||
require WPML_PLUGIN_PATH . '/inc/sandbox.inc';
|
||||
define( 'OTG_SANDBOX', true );
|
||||
} else {
|
||||
define( 'OTG_SANDBOX', false );
|
||||
}
|
||||
|
||||
if ( ! defined( 'ICL_API_ENDPOINT' ) ) {
|
||||
define( 'ICL_API_ENDPOINT', 'https://www.icanlocalize.com' );
|
||||
}
|
||||
|
||||
if ( ! defined( 'OTG_TRANSLATION_PROXY_URL' ) ) {
|
||||
define( 'OTG_TRANSLATION_PROXY_URL', 'https://tp.wpml.org' );
|
||||
}
|
||||
|
||||
if ( ! defined( 'ICL_PLUGIN_INACTIVE' ) ) {
|
||||
define( 'ICL_PLUGIN_INACTIVE', false );
|
||||
}
|
||||
|
||||
if ( defined( 'PHP_INT_MIN' ) ) {
|
||||
// phpcs:disable PHPCompatibility.Constants.NewConstants.php_int_minFound -- A check for the presence of the constant is made
|
||||
define( 'WPML_PRIORITY_BEFORE_EVERYTHING', PHP_INT_MIN );
|
||||
// phpcs:enable PHPCompatibility.Constants.NewConstants.php_int_minFound
|
||||
} else {
|
||||
define( 'WPML_PRIORITY_BEFORE_EVERYTHING', ~PHP_INT_MAX );
|
||||
}
|
||||
|
||||
define( 'ICL_TM_NOT_TRANSLATED', 0 );
|
||||
define( 'ICL_TM_WAITING_FOR_TRANSLATOR', 1 );
|
||||
define( 'ICL_TM_IN_PROGRESS', 2 );
|
||||
define( 'ICL_TM_NEEDS_UPDATE', 3 ); // virt. status code (based on needs_update)
|
||||
define( 'ICL_TM_TRANSLATION_READY_TO_DOWNLOAD', 4 ); // when translation is ready in TP
|
||||
define( 'ICL_TM_DUPLICATE', 9 );
|
||||
define( 'ICL_TM_COMPLETE', 10 );
|
||||
define( 'ICL_TM_IN_BASKET', 20 );
|
||||
define( 'ICL_TM_NEEDS_REVIEW', 30 ); // Virtual status - NOT STORE IN DB.
|
||||
define( 'ICL_TM_ATE_NEEDS_RETRY', 40 );
|
||||
|
||||
|
||||
// @since 3.2
|
||||
define( 'ICL_TM_PENDING_TP', 102 );
|
||||
|
||||
define( 'ICL_TM_ATE_CANCELLED', 42 );
|
||||
|
||||
/** @deprecated Use constants in WPML_TM_Emails_Settings instead */
|
||||
define( 'ICL_TM_NOTIFICATION_NONE', 0 );
|
||||
/** @deprecated Use WPML_TM_Emails_Settings::NOTIFY_IMMEDIATELY instead */
|
||||
define( 'ICL_TM_NOTIFICATION_IMMEDIATELY', 1 );
|
||||
/** @deprecated Use WPML_TM_Emails_Settings::NOTIFY_DAILY instead */
|
||||
define( 'ICL_TM_NOTIFICATION_DAILY', 2 );
|
||||
|
||||
define( 'ICL_TM_TMETHOD_MANUAL', 0 );
|
||||
define( 'ICL_TM_TMETHOD_EDITOR', 1 );
|
||||
define( 'ICL_TM_TMETHOD_PRO', 2 );
|
||||
define( 'ICL_TM_TMETHOD_ATE', 'ATE' );
|
||||
|
||||
if ( ! defined( 'ICL_TM_DOCS_PER_PAGE' ) ) {
|
||||
define( 'ICL_TM_DOCS_PER_PAGE', 20 );
|
||||
}
|
||||
|
||||
define( 'ICL_ASIAN_LANGUAGE_CHAR_SIZE', 6 );
|
||||
|
||||
/* legacy? */
|
||||
define( 'CMS_REQUEST_WAITING_FOR_PROJECT_CREATION', 1 );
|
||||
|
||||
define( 'ICL_FINANCE_LINK', '/finance' );
|
||||
|
||||
define( 'MESSAGE_TRANSLATION_IN_PROGRESS', 3 );
|
||||
define( 'MESSAGE_TRANSLATION_COMPLETE', 4 );
|
||||
|
||||
define( 'ICL_LANG_SEL_BLUE_FONT_CURRENT_NORMAL', '#ffffff' );
|
||||
define( 'ICL_LANG_SEL_BLUE_FONT_CURRENT_HOVER', '#000000' );
|
||||
define( 'ICL_LANG_SEL_BLUE_BACKGROUND_CURRENT_NORMAL', '#0099cc' );
|
||||
define( 'ICL_LANG_SEL_BLUE_BACKGROUND_CURRENT_HOVER', '#0099cc' );
|
||||
define( 'ICL_LANG_SEL_BLUE_FONT_OTHER_NORMAL', '#000000' );
|
||||
define( 'ICL_LANG_SEL_BLUE_FONT_OTHER_HOVER', '#000000' );
|
||||
define( 'ICL_LANG_SEL_BLUE_BACKGROUND_OTHER_NORMAL', '#eeeeee' );
|
||||
define( 'ICL_LANG_SEL_BLUE_BACKGROUND_OTHER_HOVER', '#cccccc' );
|
||||
define( 'ICL_LANG_SEL_BLUE_BORDER', '#000000' );
|
||||
define( 'ICL_LANG_SEL_WHITE_FONT_CURRENT_NORMAL', '#444444' );
|
||||
define( 'ICL_LANG_SEL_WHITE_FONT_CURRENT_HOVER', '#000000' );
|
||||
define( 'ICL_LANG_SEL_WHITE_BACKGROUND_CURRENT_NORMAL', '#ffffff' );
|
||||
define( 'ICL_LANG_SEL_WHITE_BACKGROUND_CURRENT_HOVER', '#eeeeee' );
|
||||
define( 'ICL_LANG_SEL_WHITE_FONT_OTHER_NORMAL', '#444444' );
|
||||
define( 'ICL_LANG_SEL_WHITE_FONT_OTHER_HOVER', '#000000' );
|
||||
define( 'ICL_LANG_SEL_WHITE_BACKGROUND_OTHER_NORMAL', '#ffffff' );
|
||||
define( 'ICL_LANG_SEL_WHITE_BACKGROUND_OTHER_HOVER', '#eeeeee' );
|
||||
define( 'ICL_LANG_SEL_WHITE_BORDER', '#aaaaaa' );
|
||||
define( 'ICL_LANG_SEL_GRAY_FONT_CURRENT_NORMAL', '#222222' );
|
||||
define( 'ICL_LANG_SEL_GRAY_FONT_CURRENT_HOVER', '#000000' );
|
||||
define( 'ICL_LANG_SEL_GRAY_BACKGROUND_CURRENT_NORMAL', '#eeeeee' );
|
||||
define( 'ICL_LANG_SEL_GRAY_BACKGROUND_CURRENT_HOVER', '#dddddd' );
|
||||
define( 'ICL_LANG_SEL_GRAY_FONT_OTHER_NORMAL', '#222222' );
|
||||
define( 'ICL_LANG_SEL_GRAY_FONT_OTHER_HOVER', '#000000' );
|
||||
define( 'ICL_LANG_SEL_GRAY_BACKGROUND_OTHER_NORMAL', '#eeeeee' );
|
||||
define( 'ICL_LANG_SEL_GRAY_BACKGROUND_OTHER_HOVER', '#dddddd' );
|
||||
define( 'ICL_LANG_SEL_GRAY_BORDER', '#555555' );
|
||||
|
||||
define( 'ICL_PRO_TRANSLATION_COST_PER_WORD', 0.09 );
|
||||
define( 'ICL_PRO_TRANSLATION_PICKUP_XMLRPC', 0 );
|
||||
define( 'ICL_PRO_TRANSLATION_PICKUP_POLLING', 1 );
|
||||
|
||||
if ( ! defined( 'ICL_REMOTE_WPML_CONFIG_FILES_INDEX' ) ) {
|
||||
define( 'ICL_REMOTE_WPML_CONFIG_FILES_INDEX', 'http://cdn.wpml.org/' );
|
||||
}
|
||||
|
||||
define( 'ICL_ICONS_URL', ICL_PLUGIN_URL . '/res/img/' );
|
||||
|
||||
define( 'WPML_ELEMENT_IS_NOT_TRANSLATED', 0 );
|
||||
define( 'WPML_ELEMENT_IS_TRANSLATED', 1 );
|
||||
define( 'WPML_ELEMENT_IS_DUPLICATED', 2 );
|
||||
define( 'WPML_ELEMENT_IS_A_DUPLICATE', 3 );
|
||||
|
||||
define( 'WPML_STRING_TABLE_NAME_CONTEXT_LENGTH', 160 );
|
||||
|
||||
define( 'WPML_QUERY_IS_ROOT', 1 );
|
||||
define( 'WPML_QUERY_IS_OTHER_THAN_ROOT', 2 );
|
||||
define( 'WPML_QUERY_IS_NOT_FOR_POST', 3 );
|
||||
|
||||
define( 'WPML_XDOMAIN_DATA_OFF', 0 );
|
||||
define( 'WPML_XDOMAIN_DATA_GET', 1 );
|
||||
define( 'WPML_XDOMAIN_DATA_POST', 2 );
|
||||
|
||||
define( 'WPML_TT_TAXONOMIES_NOT_TRANSLATED', 1 );
|
||||
define( 'WPML_TT_TAXONOMIES_ALL', 0 );
|
||||
// This sets the number of rows in the table to be displayed by this class, not the actual number of terms.
|
||||
define( 'WPML_TT_TERMS_PER_PAGE', 10 );
|
||||
define( 'WPML_TRANSLATE_CUSTOM_FIELD', 2 );
|
||||
define( 'WPML_COPY_CUSTOM_FIELD', 1 );
|
||||
define( 'WPML_IGNORE_CUSTOM_FIELD', 0 );
|
||||
define( 'WPML_COPY_ONCE_CUSTOM_FIELD', 3 );
|
||||
|
||||
define( 'WPML_POST_META_CONFIG_INDEX_SINGULAR', 'custom-field' );
|
||||
define( 'WPML_POST_META_SETTING_INDEX_SINGULAR', 'custom_field' );
|
||||
define( 'WPML_POST_META_CONFIG_INDEX_PLURAL', 'custom-fields' );
|
||||
define( 'WPML_POST_META_SETTING_INDEX_PLURAL', 'custom_fields_translation' );
|
||||
|
||||
define( 'WPML_TERM_META_CONFIG_INDEX_SINGULAR', 'custom-term-field' );
|
||||
define( 'WPML_TERM_META_CONFIG_INDEX_PLURAL', 'custom-term-fields' );
|
||||
|
||||
define( 'WPML_TERM_META_SETTING_INDEX_SINGULAR', 'custom_term_field' );
|
||||
define( 'WPML_TERM_META_SETTING_INDEX_PLURAL', 'custom_term_fields_translation' );
|
||||
|
||||
define( 'WPML_POST_META_READONLY_SETTING_INDEX', 'custom_fields_readonly_config' );
|
||||
define( 'WPML_TERM_META_READONLY_SETTING_INDEX', 'custom_term_fields_readonly_config' );
|
||||
|
||||
define( 'WPML_POST_META_UNLOCKED_SETTING_INDEX', 'custom_fields_unlocked_config' );
|
||||
define( 'WPML_TERM_META_UNLOCKED_SETTING_INDEX', 'custom_term_fields_unlocked_config' );
|
||||
|
||||
define( 'WPML_POST_TYPE_READONLY_SETTING_INDEX', 'custom_types_readonly_config' );
|
||||
|
||||
define( 'WPML_LANGUAGE_NEGOTIATION_TYPE_DIRECTORY', 1 );
|
||||
define( 'WPML_LANGUAGE_NEGOTIATION_TYPE_DOMAIN', 2 );
|
||||
define( 'WPML_LANGUAGE_NEGOTIATION_TYPE_PARAMETER', 3 );
|
||||
|
||||
define( 'WPML_ELEMENT_TRANSLATIONS_CACHE_GROUP', 'element_translations' );
|
||||
|
||||
define( 'WEBSITE_DETAILS_TRANSIENT_KEY', 'wpml_icl_query_website_details' );
|
||||
|
||||
define( 'WPML_CONTENT_TYPE_DONT_TRANSLATE', 0 );
|
||||
define( 'WPML_CONTENT_TYPE_TRANSLATE', 1 );
|
||||
define( 'WPML_CONTENT_TYPE_DISPLAY_AS_IF_TRANSLATED', 2 );
|
||||
@@ -0,0 +1,206 @@
|
||||
<?php
|
||||
|
||||
class WPML_TM_Element_Translations extends WPML_TM_Record_User {
|
||||
|
||||
/** @var int[] $trid_cache */
|
||||
private $trid_cache;
|
||||
/** @var int[] $job_id_cache */
|
||||
private $job_id_cache;
|
||||
/** @var int[] $job_id_cache */
|
||||
private $translation_status_cache;
|
||||
/** @var bool[] $update_status_cache */
|
||||
private $update_status_cache;
|
||||
/** @var string[] $element_type_prefix_cache */
|
||||
private $element_type_prefix_cache = array();
|
||||
|
||||
public function init_hooks() {
|
||||
add_action( 'wpml_cache_clear', array( $this, 'reload' ) );
|
||||
add_filter(
|
||||
'wpml_tm_translation_status',
|
||||
array(
|
||||
$this,
|
||||
'get_translation_status_filter',
|
||||
),
|
||||
10,
|
||||
2
|
||||
);
|
||||
}
|
||||
|
||||
public function reload() {
|
||||
$this->trid_cache = array();
|
||||
$this->job_id_cache = array();
|
||||
$this->translation_status_cache = array();
|
||||
$this->update_status_cache = array();
|
||||
$this->element_type_prefix_cache = array();
|
||||
}
|
||||
|
||||
public function is_update_needed( $trid, $language_code ) {
|
||||
if ( isset( $this->update_status_cache[ $trid ][ $language_code ] ) ) {
|
||||
$needs_update = $this->update_status_cache[ $trid ][ $language_code ];
|
||||
} else {
|
||||
$this->init_job_id( $trid, $language_code );
|
||||
$needs_update = isset( $this->update_status_cache[ $trid ][ $language_code ] )
|
||||
? $this->update_status_cache[ $trid ][ $language_code ] : 0;
|
||||
}
|
||||
|
||||
return (bool) $needs_update;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $trid
|
||||
* @param string $language_code
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_element_type_prefix( $trid, $language_code ) {
|
||||
if ( $trid && $language_code && ! isset( $this->element_type_prefix_cache[ $trid ] ) ) {
|
||||
$this->init_job_id( $trid, $language_code );
|
||||
}
|
||||
|
||||
return $trid && array_key_exists( $trid, $this->element_type_prefix_cache ) ? $this->element_type_prefix_cache[ $trid ] : '';
|
||||
}
|
||||
|
||||
public function get_translation_status_filter( $empty, $args ) {
|
||||
$trid = $args['trid'];
|
||||
$language_code = $args['language_code'];
|
||||
|
||||
return $this->get_translation_status( $trid, $language_code );
|
||||
}
|
||||
/**
|
||||
* @param int $trid
|
||||
* @param string $language_code
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_translation_status( $trid, $language_code ) {
|
||||
if ( isset( $this->translation_status_cache[ $trid ][ $language_code ] ) ) {
|
||||
$status = $this->translation_status_cache[ $trid ][ $language_code ];
|
||||
} else {
|
||||
$this->init_job_id( $trid, $language_code );
|
||||
$status = isset( $this->translation_status_cache[ $trid ][ $language_code ] )
|
||||
? $this->translation_status_cache[ $trid ][ $language_code ] : 0;
|
||||
}
|
||||
|
||||
return (int) $status;
|
||||
}
|
||||
|
||||
public function init_job_id( $trid, $target_lang_code ) {
|
||||
global $wpdb, $wpml_language_resolution;
|
||||
|
||||
if ( ! isset( $this->job_id_cache[ $trid ][ $target_lang_code ] ) ) {
|
||||
$jobs = $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
"
|
||||
SELECT
|
||||
tj.job_id,
|
||||
ts.status,
|
||||
ts.needs_update,
|
||||
t.language_code,
|
||||
SUBSTRING_INDEX(t.element_type, '_', 1)
|
||||
AS element_type_prefix
|
||||
FROM {$wpdb->prefix}icl_translate_job tj
|
||||
JOIN {$wpdb->prefix}icl_translation_status ts
|
||||
ON tj.rid = ts.rid
|
||||
JOIN {$wpdb->prefix}icl_translations t
|
||||
ON ts.translation_id = t.translation_id
|
||||
WHERE t.trid = %d
|
||||
",
|
||||
$trid
|
||||
)
|
||||
);
|
||||
$active_langs = $wpml_language_resolution->get_active_language_codes();
|
||||
|
||||
foreach ( $active_langs as $lang_code ) {
|
||||
$this->cache_job_in_lang( $jobs, $lang_code, $trid );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object[] $jobs
|
||||
* @param string $lang
|
||||
* @param string $trid
|
||||
*
|
||||
* @return false|object
|
||||
*/
|
||||
private function cache_job_in_lang( $jobs, $lang, $trid ) {
|
||||
$res = false;
|
||||
foreach ( $jobs as $job ) {
|
||||
if ( $job->language_code === $lang ) {
|
||||
$res = $job;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( (bool) $res === true ) {
|
||||
$job_id = $res->job_id;
|
||||
$status = $res->status;
|
||||
$needs_update = (bool) $res->needs_update;
|
||||
$element_type_prefix = $res->element_type_prefix;
|
||||
} else {
|
||||
$job_id = - 1;
|
||||
$status = 0;
|
||||
$needs_update = false;
|
||||
$element_type_prefix = $this->fallback_type_prefix( $trid );
|
||||
}
|
||||
|
||||
$this->cache_job( $trid, $lang, $job_id, $status, $needs_update, $element_type_prefix );
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
private function fallback_type_prefix( $trid ) {
|
||||
global $wpdb;
|
||||
|
||||
if ( isset( $this->element_type_prefix_cache[ $trid ] ) && (bool) $this->element_type_prefix_cache[ $trid ] === true ) {
|
||||
$prefix = $this->element_type_prefix_cache[ $trid ];
|
||||
} elseif ( (bool) $this->tm_records->get_post_translations()->get_element_translations( null, $trid ) ) {
|
||||
$prefix = 'post';
|
||||
} else {
|
||||
$prefix = $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
"SELECT SUBSTRING_INDEX(element_type, '_', 1)
|
||||
FROM {$wpdb->prefix}icl_translations
|
||||
WHERE trid = %d
|
||||
LIMIT 1",
|
||||
$trid
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $prefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $trid
|
||||
* @param string $language_code
|
||||
* @param int $job_id
|
||||
* @param int $status
|
||||
* @param bool $needs_update
|
||||
* @param string $element_type_prefix
|
||||
*/
|
||||
private function cache_job( $trid, $language_code, $job_id, $status, $needs_update, $element_type_prefix ) {
|
||||
if ( (bool) $job_id === true && (bool) $trid === true && (bool) $language_code === true ) {
|
||||
$this->maybe_init_trid_cache( $trid );
|
||||
$this->job_id_cache[ $trid ][ $language_code ] = $job_id;
|
||||
$this->translation_status_cache[ $trid ][ $language_code ] = $status;
|
||||
$this->update_status_cache[ $trid ][ $language_code ] = $needs_update;
|
||||
$this->element_type_prefix_cache[ $trid ] = isset( $this->element_type_prefix_cache[ $trid ] )
|
||||
&& (bool) $this->element_type_prefix_cache[ $trid ] === true
|
||||
? $this->element_type_prefix_cache[ $trid ] : $element_type_prefix;
|
||||
}
|
||||
}
|
||||
|
||||
private function maybe_init_trid_cache( $trid ) {
|
||||
foreach (
|
||||
array(
|
||||
&$this->job_id_cache,
|
||||
&$this->trid_cache,
|
||||
&$this->translation_status_cache,
|
||||
&$this->update_status_cache,
|
||||
) as $cache
|
||||
) {
|
||||
$cache[ $trid ] = isset( $cache[ $trid ] ) ? $cache[ $trid ] : array();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
function deprecated_icl_data_from_pro_translation( $translation ) {
|
||||
return apply_filters( 'icl_data_from_pro_translation', $translation );
|
||||
}
|
||||
|
||||
add_filter( 'wpml_tm_data_from_pro_translation', 'deprecated_icl_data_from_pro_translation', PHP_INT_MAX, 1 );
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
function get_debug_info() {
|
||||
global $sitepress, $wpdb;
|
||||
|
||||
return new WPML_Debug_Information( $wpdb, $sitepress );
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
if ( ! function_exists( 'object_to_array' ) ) {
|
||||
function object_to_array( $obj ) {
|
||||
return json_decode( json_encode( $obj ), true );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'wpml_get_admin_url' ) ) {
|
||||
/**
|
||||
* A more helpful version of `admin_url`
|
||||
* Is not called it `wpml_admin_url` because there is already a class with the same name
|
||||
*
|
||||
* @param array $args
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function wpml_get_admin_url( array $args = array() ) {
|
||||
if ( ! $args ) {
|
||||
return admin_url();
|
||||
}
|
||||
|
||||
$default_args = array(
|
||||
'path' => '',
|
||||
'scheme' => 'admin',
|
||||
'query' => array(),
|
||||
);
|
||||
|
||||
$args = array_merge( $default_args, $args );
|
||||
|
||||
$admin_url = '';
|
||||
if ( $args['path'] || $args['scheme'] ) {
|
||||
$admin_url = admin_url( $args['path'], $args['scheme'] );
|
||||
}
|
||||
|
||||
if ( $args['query'] ) {
|
||||
$admin_url_parsed = wp_parse_url( $admin_url );
|
||||
|
||||
if ( is_string( $args['query'] ) ) {
|
||||
$admin_url_parsed['query'] = $args['query'];
|
||||
} elseif ( is_array( $args['query'] ) ) {
|
||||
$admin_url_parsed['query'] = http_build_query( $args['query'] );
|
||||
}
|
||||
|
||||
$admin_url = http_build_url( $admin_url_parsed );
|
||||
}
|
||||
|
||||
return $admin_url;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,905 @@
|
||||
<?php
|
||||
|
||||
use WPML\TM\Editor\ClassicEditorActions;
|
||||
use WPML\TM\Jobs\Query\CompositeQuery;
|
||||
use WPML\TM\Jobs\Query\LimitQueryHelper;
|
||||
use WPML\TM\Jobs\Query\OrderQueryHelper;
|
||||
use WPML\TM\Jobs\Query\PackageQuery;
|
||||
use WPML\TM\Jobs\Query\PostQuery;
|
||||
use WPML\TM\Jobs\Query\QueryBuilder;
|
||||
use WPML\TM\Jobs\Query\StringQuery;
|
||||
use WPML\TM\Jobs\Query\StringsBatchQuery;
|
||||
use function WPML\Container\make;
|
||||
use \WPML\Setup\Option as SetupOptions;
|
||||
|
||||
if ( ! \WPML\Plugins::isTMActive() && ( ! wpml_is_setup_complete() || false !== SetupOptions::isTMAllowed() ) ) {
|
||||
|
||||
/**
|
||||
* @return WPML_TM_Element_Translations
|
||||
*/
|
||||
function wpml_tm_load_element_translations() {
|
||||
global $wpml_tm_element_translations, $wpdb, $wpml_post_translations, $wpml_term_translations;
|
||||
|
||||
if ( ! isset( $wpml_tm_element_translations ) ) {
|
||||
require_once WPML_TM_PATH . '/inc/core/wpml-tm-element-translations.class.php';
|
||||
$tm_records = new WPML_TM_Records( $wpdb, $wpml_post_translations, $wpml_term_translations );
|
||||
$wpml_tm_element_translations = new WPML_TM_Element_Translations( $tm_records );
|
||||
$wpml_tm_element_translations->init_hooks();
|
||||
}
|
||||
|
||||
return $wpml_tm_element_translations;
|
||||
}
|
||||
|
||||
function wpml_tm_load_status_display_filter() {
|
||||
global $wpml_tm_status_display_filter, $iclTranslationManagement, $sitepress, $wpdb;
|
||||
|
||||
$blog_translators = wpml_tm_load_blog_translators();
|
||||
$tm_api = new WPML_TM_API( $blog_translators, $iclTranslationManagement );
|
||||
$tm_api->init_hooks();
|
||||
if ( ! isset( $wpml_tm_status_display_filter ) ) {
|
||||
$status_helper = wpml_get_post_status_helper();
|
||||
$job_factory = wpml_tm_load_job_factory();
|
||||
$wpml_tm_status_display_filter = new WPML_TM_Translation_Status_Display(
|
||||
$wpdb,
|
||||
$sitepress,
|
||||
$status_helper,
|
||||
$job_factory,
|
||||
$tm_api
|
||||
);
|
||||
}
|
||||
|
||||
$wpml_tm_status_display_filter->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* @depecated since WPML 4.5.0
|
||||
*
|
||||
* @return \WPML_TM_Page_Builders_Hooks
|
||||
*/
|
||||
function wpml_tm_page_builders_hooks() {
|
||||
static $page_builder_hooks;
|
||||
if ( ! $page_builder_hooks ) {
|
||||
global $sitepress;
|
||||
$page_builder_hooks = new WPML_TM_Page_Builders_Hooks( null, $sitepress );
|
||||
}
|
||||
|
||||
return $page_builder_hooks;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \WPML_Custom_XML_Factory
|
||||
*/
|
||||
function wpml_tm_custom_xml_factory() {
|
||||
static $tm_custom_xml_factory;
|
||||
if ( ! $tm_custom_xml_factory ) {
|
||||
$tm_custom_xml_factory = new WPML_Custom_XML_Factory();
|
||||
}
|
||||
|
||||
return $tm_custom_xml_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \WPML_Custom_XML_UI_Hooks
|
||||
*/
|
||||
function wpml_tm_custom_xml_ui_hooks() {
|
||||
static $tm_custom_xml_ui_hooks;
|
||||
if ( ! $tm_custom_xml_ui_hooks ) {
|
||||
global $sitepress;
|
||||
$factory = wpml_tm_custom_xml_factory();
|
||||
if ( $factory ) {
|
||||
$tm_custom_xml_ui_hooks = new WPML_Custom_XML_UI_Hooks( $factory->create_resources( $sitepress->get_wp_api() ) );
|
||||
}
|
||||
}
|
||||
|
||||
return $tm_custom_xml_ui_hooks;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \WPML_UI_Screen_Options_Factory
|
||||
*/
|
||||
function wpml_ui_screen_options_factory() {
|
||||
static $screen_options_factory;
|
||||
if ( ! $screen_options_factory ) {
|
||||
global $sitepress;
|
||||
$screen_options_factory = new WPML_UI_Screen_Options_Factory( $sitepress );
|
||||
}
|
||||
|
||||
return $screen_options_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \WPML_TM_Loader
|
||||
*/
|
||||
function wpml_tm_loader() {
|
||||
static $tm_loader;
|
||||
if ( ! $tm_loader ) {
|
||||
$tm_loader = new WPML_TM_Loader();
|
||||
}
|
||||
|
||||
return $tm_loader;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \WPML_TP_Translator
|
||||
*/
|
||||
function wpml_tm_translator() {
|
||||
static $tm_translator;
|
||||
if ( ! $tm_translator ) {
|
||||
$tm_translator = new WPML_TP_Translator();
|
||||
}
|
||||
|
||||
return $tm_translator;
|
||||
}
|
||||
|
||||
/**
|
||||
* It returns a single instance of \WPML_Translation_Management.
|
||||
*
|
||||
* @return \WPML_Translation_Management
|
||||
*/
|
||||
function wpml_translation_management() {
|
||||
global $WPML_Translation_Management;
|
||||
if ( ! $WPML_Translation_Management ) {
|
||||
global $sitepress;
|
||||
$WPML_Translation_Management = new WPML_Translation_Management( $sitepress, wpml_tm_loader(), wpml_load_core_tm(), wpml_tm_translator() );
|
||||
}
|
||||
|
||||
return $WPML_Translation_Management;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \WPML_Translation_Basket
|
||||
*/
|
||||
function wpml_translation_basket() {
|
||||
static $translation_basket;
|
||||
if ( ! $translation_basket ) {
|
||||
global $wpdb;
|
||||
$translation_basket = new WPML_Translation_Basket( $wpdb );
|
||||
}
|
||||
|
||||
return $translation_basket;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \WPML_TM_Translate_Independently
|
||||
*/
|
||||
function wpml_tm_translate_independently() {
|
||||
static $translate_independently;
|
||||
if ( ! $translate_independently ) {
|
||||
global $sitepress;
|
||||
|
||||
$translate_independently = new WPML_TM_Translate_Independently( wpml_load_core_tm(), wpml_translation_basket(), $sitepress );
|
||||
}
|
||||
|
||||
return $translate_independently;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_Translation_Proxy_Basket_Networking
|
||||
*/
|
||||
function wpml_tm_load_basket_networking() {
|
||||
global $iclTranslationManagement, $wpdb;
|
||||
|
||||
require_once WPML_TM_PATH . '/inc/translation-proxy/wpml-translationproxy-basket-networking.class.php';
|
||||
|
||||
$basket = new WPML_Translation_Basket( $wpdb );
|
||||
|
||||
return new WPML_Translation_Proxy_Basket_Networking( $basket, $iclTranslationManagement );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_Translation_Proxy_Networking
|
||||
*/
|
||||
function wpml_tm_load_tp_networking() {
|
||||
global $wpml_tm_tp_networking;
|
||||
|
||||
if ( ! isset( $wpml_tm_tp_networking ) ) {
|
||||
$tp_lock_factory = new WPML_TP_Lock_Factory();
|
||||
$wpml_tm_tp_networking = new WPML_Translation_Proxy_Networking( new WP_Http(), $tp_lock_factory->create() );
|
||||
}
|
||||
|
||||
return $wpml_tm_tp_networking;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_TM_Blog_Translators
|
||||
*/
|
||||
function wpml_tm_load_blog_translators() {
|
||||
global $wpdb, $sitepress, $wpml_post_translations, $wpml_term_translations, $wpml_cache_factory;
|
||||
static $instance;
|
||||
|
||||
if ( ! $instance ) {
|
||||
$tm_records = new WPML_TM_Records( $wpdb, $wpml_post_translations, $wpml_term_translations );
|
||||
$translator_records = new WPML_Translator_Records( $wpdb, new WPML_WP_User_Query_Factory(), wp_roles() );
|
||||
|
||||
$instance = new WPML_TM_Blog_Translators( $sitepress, $tm_records, $translator_records, $wpml_cache_factory );
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_TM_Translators_Dropdown
|
||||
*/
|
||||
function wpml_tm_get_translators_dropdown() {
|
||||
static $instance;
|
||||
|
||||
if ( ! $instance ) {
|
||||
$instance = new WPML_TM_Translators_Dropdown( wpml_tm_load_blog_translators() );
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_TM_Mail_Notification
|
||||
*/
|
||||
function wpml_tm_init_mail_notifications() {
|
||||
global $wpml_tm_mailer, $sitepress, $wpdb, $iclTranslationManagement, $wp_api;
|
||||
|
||||
if ( null === $wp_api ) {
|
||||
$wp_api = new WPML_WP_API();
|
||||
}
|
||||
|
||||
if ( is_admin() ) {
|
||||
$blog_translators = wpml_tm_load_blog_translators();
|
||||
$email_twig_factory = new WPML_TM_Email_Twig_Template_Factory();
|
||||
$batch_report = new WPML_TM_Batch_Report( $blog_translators );
|
||||
$batch_report_email_template = new WPML_TM_Email_Jobs_Summary_View(
|
||||
$email_twig_factory->create(),
|
||||
$blog_translators,
|
||||
$sitepress
|
||||
);
|
||||
$batch_report_email_builder = new WPML_TM_Batch_Report_Email_Builder(
|
||||
$batch_report,
|
||||
$batch_report_email_template
|
||||
);
|
||||
$batch_report_email_process = new WPML_TM_Batch_Report_Email_Process(
|
||||
$batch_report,
|
||||
$batch_report_email_builder
|
||||
);
|
||||
$batch_report_hooks = new WPML_TM_Batch_Report_Hooks( $batch_report, $batch_report_email_process );
|
||||
$batch_report_hooks->add_hooks();
|
||||
|
||||
$wpml_tm_unsent_jobs = new WPML_TM_Unsent_Jobs( $blog_translators, $sitepress );
|
||||
$wpml_tm_unsent_jobs->add_hooks();
|
||||
|
||||
$wpml_tm_unsent_jobs_notice = new WPML_TM_Unsent_Jobs_Notice( $wp_api );
|
||||
$wpml_tm_unsent_jobs_notice_hooks = new WPML_TM_Unsent_Jobs_Notice_Hooks(
|
||||
$wpml_tm_unsent_jobs_notice,
|
||||
$wp_api,
|
||||
WPML_Notices::DISMISSED_OPTION_KEY
|
||||
);
|
||||
$wpml_tm_unsent_jobs_notice_hooks->add_hooks();
|
||||
|
||||
$user_jobs_notification_settings = new WPML_User_Jobs_Notification_Settings();
|
||||
$user_jobs_notification_settings->add_hooks();
|
||||
|
||||
$email_twig_factory = new WPML_Twig_Template_Loader( array( WPML_TM_PATH . '/templates/user-profile/' ) );
|
||||
$notification_template = new WPML_User_Jobs_Notification_Settings_Template( $email_twig_factory->get_template() );
|
||||
|
||||
$user_jobs_notification_settings_render = new WPML_User_Jobs_Notification_Settings_Render( $notification_template );
|
||||
$user_jobs_notification_settings_render->add_hooks();
|
||||
}
|
||||
|
||||
if ( ! isset( $wpml_tm_mailer ) ) {
|
||||
$iclTranslationManagement = $iclTranslationManagement ? $iclTranslationManagement : wpml_load_core_tm();
|
||||
if ( empty( $iclTranslationManagement->settings ) ) {
|
||||
$iclTranslationManagement->init();
|
||||
}
|
||||
$settings = isset( $iclTranslationManagement->settings['notification'] ) ? $iclTranslationManagement->settings['notification'] : array();
|
||||
|
||||
$email_twig_factory = new WPML_TM_Email_Twig_Template_Factory();
|
||||
$email_notification_view = new WPML_TM_Email_Notification_View( $email_twig_factory->create() );
|
||||
|
||||
$has_active_remote_service = TranslationProxy::is_current_service_active_and_authenticated();
|
||||
|
||||
$wpml_tm_mailer = new WPML_TM_Mail_Notification(
|
||||
$sitepress,
|
||||
$wpdb,
|
||||
wpml_tm_load_job_factory(),
|
||||
$email_notification_view,
|
||||
$settings,
|
||||
$has_active_remote_service
|
||||
);
|
||||
}
|
||||
$wpml_tm_mailer->init();
|
||||
|
||||
return $wpml_tm_mailer;
|
||||
}
|
||||
|
||||
/**
|
||||
* It returns a single instance of the class.
|
||||
*
|
||||
* @return WPML_Dashboard_Ajax
|
||||
*/
|
||||
function wpml_tm_load_tm_dashboard_ajax() {
|
||||
global $wpml_tm_dashboard_ajax, $sitepress;
|
||||
|
||||
if ( ! isset( $wpml_tm_dashboard_ajax ) ) {
|
||||
require_once WPML_TM_PATH . '/menu/dashboard/wpml-tm-dashboard-ajax.class.php';
|
||||
$wpml_tm_dashboard_ajax = new WPML_Dashboard_Ajax( new WPML_Super_Globals_Validation() );
|
||||
|
||||
if ( defined( 'OTG_TRANSLATION_PROXY_URL' ) && defined( 'ICL_SITEPRESS_VERSION' ) ) {
|
||||
$wpml_tp_api = wpml_tm_get_tp_project_api();
|
||||
|
||||
$wpml_tp_api_ajax = new WPML_TP_Refresh_Language_Pairs( $wpml_tp_api );
|
||||
$wpml_tp_api_ajax->add_hooks();
|
||||
|
||||
$sync_jobs_ajax_handler = new WPML_TP_Sync_Ajax_Handler(
|
||||
wpml_tm_get_tp_sync_jobs(),
|
||||
new WPML_TM_Last_Picked_Up( $sitepress )
|
||||
);
|
||||
$sync_jobs_ajax_handler->add_hooks();
|
||||
}
|
||||
}
|
||||
|
||||
return $wpml_tm_dashboard_ajax;
|
||||
}
|
||||
|
||||
function wpml_tm_load_and_intialize_dashboard_ajax() {
|
||||
if ( defined( 'ICL_SITEPRESS_VERSION' ) ) {
|
||||
if ( defined( 'DOING_AJAX' ) ) {
|
||||
$wpml_tm_dashboard_ajax = wpml_tm_load_tm_dashboard_ajax();
|
||||
add_action( 'init', array( $wpml_tm_dashboard_ajax, 'init_ajax_actions' ) );
|
||||
} elseif (
|
||||
defined( 'WPML_TM_FOLDER' ) && is_admin() && isset( $_GET['page'] ) && WPML_TM_FOLDER . '/menu/main.php' === $_GET['page'] && ( ! isset( $_GET['sm'] ) || $_GET['sm'] === 'dashboard' )
|
||||
) {
|
||||
$wpml_tm_dashboard_ajax = wpml_tm_load_tm_dashboard_ajax();
|
||||
add_action( 'wpml_tm_scripts_enqueued', array( $wpml_tm_dashboard_ajax, 'enqueue_js' ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
add_action( 'plugins_loaded', 'wpml_tm_load_and_intialize_dashboard_ajax' );
|
||||
|
||||
/**
|
||||
* It returns a single instance of the class.
|
||||
*
|
||||
* @return WPML_Translation_Job_Factory
|
||||
*/
|
||||
function wpml_tm_load_job_factory() {
|
||||
global $wpml_translation_job_factory, $wpdb, $wpml_post_translations, $wpml_term_translations;
|
||||
|
||||
if ( ! $wpml_translation_job_factory ) {
|
||||
$tm_records = new WPML_TM_Records( $wpdb, $wpml_post_translations, $wpml_term_translations );
|
||||
$wpml_translation_job_factory = new WPML_Translation_Job_Factory( $tm_records );
|
||||
$wpml_translation_job_factory->init_hooks();
|
||||
}
|
||||
|
||||
return $wpml_translation_job_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* It returns a single instance of the class.
|
||||
*
|
||||
* @return WPML_TM_XLIFF_Factory
|
||||
*/
|
||||
function wpml_tm_xliff_factory() {
|
||||
static $xliff_factory;
|
||||
|
||||
if ( ! $xliff_factory ) {
|
||||
$xliff_factory = new WPML_TM_XLIFF_Factory();
|
||||
}
|
||||
|
||||
return $xliff_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* It returns a single instance of the class.
|
||||
*
|
||||
* @return WPML_TM_XLIFF_Shortcodes
|
||||
*/
|
||||
function wpml_tm_xliff_shortcodes() {
|
||||
static $xliff_shortcodes;
|
||||
|
||||
if ( ! $xliff_shortcodes ) {
|
||||
$xliff_shortcodes = new WPML_TM_XLIFF_Shortcodes();
|
||||
}
|
||||
|
||||
return $xliff_shortcodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* It returns an instance of the class.
|
||||
*
|
||||
* @return \WPML_TM_Old_Jobs_Editor
|
||||
*/
|
||||
function wpml_tm_load_old_jobs_editor() {
|
||||
static $instance;
|
||||
|
||||
if ( ! $instance ) {
|
||||
$instance = new WPML_TM_Old_Jobs_Editor( wpml_tm_load_job_factory() );
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
function tm_after_load() {
|
||||
global $wpml_tm_translation_status, $wpdb, $wpml_post_translations, $wpml_term_translations;
|
||||
|
||||
if ( ! isset( $wpml_tm_translation_status ) ) {
|
||||
require_once WPML_TM_PATH . '/inc/translation-proxy/translationproxy.class.php';
|
||||
require_once WPML_TM_PATH . '/inc/ajax.php';
|
||||
|
||||
( new ClassicEditorActions() )->addHooks();
|
||||
|
||||
wpml_tm_load_job_factory();
|
||||
wpml_tm_init_mail_notifications();
|
||||
wpml_tm_load_element_translations();
|
||||
$wpml_tm_translation_status = make( WPML_TM_Translation_Status::class );
|
||||
$wpml_tm_translation_status->init();
|
||||
add_action( 'wpml_pre_status_icon_display', 'wpml_tm_load_status_display_filter' );
|
||||
require_once WPML_TM_PATH . '/inc/wpml-private-actions-tm.php';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* It returns an instance of the class.
|
||||
*
|
||||
* @return WPML_TM_Records
|
||||
*/
|
||||
function wpml_tm_get_records() {
|
||||
global $wpdb, $wpml_post_translations, $wpml_term_translations;
|
||||
|
||||
return new WPML_TM_Records( $wpdb, $wpml_post_translations, $wpml_term_translations );
|
||||
}
|
||||
|
||||
/**
|
||||
* It returns an instance of the class.
|
||||
*
|
||||
* @return WPML_TM_Xliff_Frontend
|
||||
*/
|
||||
function setup_xliff_frontend() {
|
||||
global $xliff_frontend;
|
||||
|
||||
$xliff_factory = new WPML_TM_XLIFF_Factory();
|
||||
$xliff_frontend = $xliff_factory->create_frontend();
|
||||
|
||||
add_action( 'init', array( $xliff_frontend, 'init' ), $xliff_frontend->get_init_priority() );
|
||||
|
||||
return $xliff_frontend;
|
||||
}
|
||||
|
||||
/**
|
||||
* It returns an instance of the class.
|
||||
*
|
||||
* @param int $job_id The ID of the job.
|
||||
*
|
||||
* @return WPML_TM_ATE_Models_Job_Create
|
||||
*/
|
||||
function wpml_tm_create_ATE_job_creation_model( $job_id ) {
|
||||
$job_factory = wpml_tm_load_job_factory();
|
||||
$translation_job = $job_factory->get_translation_job( $job_id, false, 0, true );
|
||||
|
||||
$rid = \WPML\TM\API\Job\Map::fromJobId( $job_id );
|
||||
|
||||
$job = new WPML_TM_ATE_Models_Job_Create();
|
||||
$job->id = $job_id;
|
||||
$job->source_id = $rid;
|
||||
|
||||
$previousStatus = \WPML_TM_ICL_Translation_Status::makeByRid( $rid )->previous();
|
||||
if ( $previousStatus->map( \WPML\FP\Obj::prop( 'status' ) )->getOrElse( null ) === (string) ICL_TM_ATE_CANCELLED ) {
|
||||
wpml_tm_load_job_factory()->update_job_data( $job_id, array( 'editor' => WPML_TM_Editors::ATE ) );
|
||||
$job->existing_ate_id = make( \WPML\TM\ATE\JobRecords::class )->get_ate_job_id( $job_id );
|
||||
} else {
|
||||
|
||||
$job->source_language->code = $translation_job->get_source_language_code();
|
||||
$job->source_language->name = $translation_job->get_source_language_code( true );
|
||||
$job->target_language->code = $translation_job->get_language_code();
|
||||
$job->target_language->name = $translation_job->get_language_code( true );
|
||||
$job->deadline = strtotime( $translation_job->get_deadline_date() );
|
||||
|
||||
$job->permalink = '#';
|
||||
if ( 'Post' === $translation_job->get_type() ) {
|
||||
$job->permalink = get_permalink( $translation_job->get_original_element_id() );
|
||||
}
|
||||
|
||||
$job->notify_enabled = true;
|
||||
$job->notify_url = \WPML\TM\ATE\REST\PublicReceive::get_receive_ate_job_url( $job_id );
|
||||
|
||||
$job->site_identifier = wpml_get_site_id( WPML_TM_ATE::SITE_ID_SCOPE );
|
||||
|
||||
$encoded_xliff = base64_encode( wpml_tm_get_job_xliff( $job_id ) );
|
||||
|
||||
$job->file->type = 'data:application/x-xliff;base64';
|
||||
$job->file->name = $translation_job->get_title();
|
||||
|
||||
$job->file->content = $encoded_xliff;
|
||||
}
|
||||
|
||||
return $job;
|
||||
}
|
||||
|
||||
/**
|
||||
* It returns a single instance of the class.
|
||||
*
|
||||
* @param int $job_id The ID of the job.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function wpml_tm_get_job_xliff( $job_id ) {
|
||||
static $xliff_writer;
|
||||
|
||||
if ( ! $xliff_writer ) {
|
||||
$job_factory = wpml_tm_load_job_factory();
|
||||
$xliff_writer = new WPML_TM_Xliff_Writer( $job_factory );
|
||||
}
|
||||
|
||||
return $xliff_writer->generate_job_xliff( $job_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* It returns a single instance of the class.
|
||||
*
|
||||
* @return \WPML_Rest
|
||||
*/
|
||||
function wpml_tm_get_wpml_rest() {
|
||||
static $wpml_rest;
|
||||
|
||||
if ( ! $wpml_rest ) {
|
||||
$http = new WP_Http();
|
||||
$wpml_rest = new WPML_Rest( $http );
|
||||
}
|
||||
|
||||
return $wpml_rest;
|
||||
}
|
||||
|
||||
/**
|
||||
* It returns a single instance of the class.
|
||||
*
|
||||
* @return \WPML_TP_API_Client
|
||||
*/
|
||||
function wpml_tm_get_tp_api_client() {
|
||||
static $client;
|
||||
|
||||
if ( ! $client ) {
|
||||
$client = new WPML_TP_API_Client(
|
||||
OTG_TRANSLATION_PROXY_URL,
|
||||
new WP_Http(),
|
||||
new WPML_TP_Lock( new WPML_WP_API() ),
|
||||
new WPML_TP_HTTP_Request_Filter()
|
||||
);
|
||||
}
|
||||
|
||||
return $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* It returns a single instance of the class.
|
||||
*
|
||||
* @return \WPML_TP_Project
|
||||
*/
|
||||
function wpml_tm_get_tp_project() {
|
||||
static $project;
|
||||
|
||||
if ( ! $project ) {
|
||||
global $sitepress;
|
||||
|
||||
$translation_service = $sitepress->get_setting( 'translation_service' );
|
||||
$translation_projects = $sitepress->get_setting( 'icl_translation_projects' );
|
||||
$project = new WPML_TP_Project( $translation_service, $translation_projects );
|
||||
}
|
||||
|
||||
return $project;
|
||||
}
|
||||
|
||||
/**
|
||||
* It returns a single instance of the class.
|
||||
*
|
||||
* @return \WPML_TP_Jobs_API
|
||||
*/
|
||||
function wpml_tm_get_tp_jobs_api() {
|
||||
static $api;
|
||||
|
||||
if ( ! $api ) {
|
||||
$api = new WPML_TP_Jobs_API(
|
||||
wpml_tm_get_tp_api_client(),
|
||||
wpml_tm_get_tp_project(),
|
||||
new WPML_TM_Log()
|
||||
);
|
||||
}
|
||||
|
||||
return $api;
|
||||
}
|
||||
|
||||
/**
|
||||
* It returns a single instance of the class.
|
||||
*
|
||||
* @return \WPML_TP_Project_API
|
||||
*/
|
||||
function wpml_tm_get_tp_project_api() {
|
||||
static $api;
|
||||
|
||||
if ( ! $api ) {
|
||||
$api = new WPML_TP_Project_API(
|
||||
wpml_tm_get_tp_api_client(),
|
||||
wpml_tm_get_tp_project(),
|
||||
new WPML_TM_Log()
|
||||
);
|
||||
}
|
||||
|
||||
return $api;
|
||||
}
|
||||
|
||||
/**
|
||||
* It returns a single instance of the class.
|
||||
*
|
||||
* @return \WPML_TP_XLIFF_API
|
||||
*/
|
||||
function wpml_tm_get_tp_xliff_api() {
|
||||
static $api;
|
||||
|
||||
if ( ! $api ) {
|
||||
$api = new WPML_TP_XLIFF_API(
|
||||
wpml_tm_get_tp_api_client(),
|
||||
wpml_tm_get_tp_project(),
|
||||
new WPML_TM_Log(),
|
||||
new WPML_TP_Xliff_Parser()
|
||||
);
|
||||
}
|
||||
|
||||
return $api;
|
||||
}
|
||||
|
||||
/**
|
||||
* It returns a single instance of the class.
|
||||
*
|
||||
* @param bool $forceReload
|
||||
* @param bool $loadObsoleteStringQuery
|
||||
* @param bool $dontCache
|
||||
*
|
||||
* @return \WPML_TM_Jobs_Repository
|
||||
*/
|
||||
function wpml_tm_get_jobs_repository( $forceReload = false, $loadObsoleteStringQuery = true, $dontCache = false ) {
|
||||
static $repository;
|
||||
|
||||
if ( ! $repository || $forceReload ) {
|
||||
global $wpdb;
|
||||
|
||||
$limit_helper = new LimitQueryHelper();
|
||||
$order_helper = new OrderQueryHelper();
|
||||
|
||||
$subqueries = array(
|
||||
new PostQuery( $wpdb, new QueryBuilder( $limit_helper, $order_helper ) ),
|
||||
);
|
||||
if ( defined( 'WPML_ST_VERSION' ) && get_option( 'wpml-package-translation-db-updates-run' ) ) {
|
||||
$subqueries[] = new PackageQuery(
|
||||
$wpdb,
|
||||
new QueryBuilder( $limit_helper, $order_helper )
|
||||
);
|
||||
|
||||
if ( $loadObsoleteStringQuery ) {
|
||||
$subqueries[] = new StringQuery(
|
||||
$wpdb,
|
||||
new QueryBuilder( $limit_helper, $order_helper )
|
||||
);
|
||||
}
|
||||
$subqueries[] = new StringsBatchQuery(
|
||||
$wpdb,
|
||||
new QueryBuilder( $limit_helper, $order_helper )
|
||||
);
|
||||
}
|
||||
|
||||
$result = new WPML_TM_Jobs_Repository(
|
||||
$wpdb,
|
||||
new CompositeQuery(
|
||||
$subqueries,
|
||||
$limit_helper,
|
||||
$order_helper
|
||||
),
|
||||
new WPML_TM_Job_Elements_Repository( $wpdb )
|
||||
);
|
||||
|
||||
if ( $dontCache ) {
|
||||
return $result;
|
||||
} else {
|
||||
$repository = $result;
|
||||
}
|
||||
}
|
||||
|
||||
return $repository;
|
||||
}
|
||||
|
||||
function wpml_tm_reload_jobs_repository() {
|
||||
wpml_tm_get_jobs_repository( true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloading Jobs Repository when WPML String Translation finishes setup.
|
||||
*/
|
||||
add_action( 'wpml_register_string_packages', 'wpml_tm_reload_jobs_repository' );
|
||||
|
||||
/**
|
||||
* It returns an instance of the class.
|
||||
*
|
||||
* @return WPML_TM_ATE_Job_Repository
|
||||
*/
|
||||
function wpml_tm_get_ate_jobs_repository() {
|
||||
static $instance;
|
||||
|
||||
if ( ! $instance ) {
|
||||
return new WPML_TM_ATE_Job_Repository( wpml_tm_get_jobs_repository() );
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \WPML\TM\ATE\JobRecords
|
||||
*/
|
||||
function wpml_tm_get_ate_job_records() {
|
||||
global $wpdb;
|
||||
static $instance;
|
||||
|
||||
if ( ! $instance ) {
|
||||
$instance = new WPML\TM\ATE\JobRecords( $wpdb );
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* It returns a single instance of the class.
|
||||
*
|
||||
* @return \WPML_TP_Sync_Jobs
|
||||
*/
|
||||
function wpml_tm_get_tp_sync_jobs() {
|
||||
static $sync_jobs;
|
||||
|
||||
if ( ! $sync_jobs ) {
|
||||
global $wpdb, $sitepress;
|
||||
|
||||
$sync_jobs = new WPML_TP_Sync_Jobs(
|
||||
new WPML_TM_Sync_Jobs_Status( wpml_tm_get_jobs_repository(), wpml_tm_get_tp_jobs_api() ),
|
||||
new WPML_TM_Sync_Jobs_Revision( wpml_tm_get_jobs_repository(), wpml_tm_get_tp_jobs_api() ),
|
||||
new WPML_TP_Sync_Update_Job( $wpdb, $sitepress )
|
||||
);
|
||||
}
|
||||
|
||||
return $sync_jobs;
|
||||
}
|
||||
|
||||
/**
|
||||
* It returns a single instance of the class.
|
||||
*
|
||||
* @return \WPML_TP_Translations_Repository
|
||||
*/
|
||||
function wpml_tm_get_tp_translations_repository() {
|
||||
static $repository;
|
||||
|
||||
if ( ! $repository ) {
|
||||
$repository = new WPML_TP_Translations_Repository(
|
||||
wpml_tm_get_tp_xliff_api(),
|
||||
wpml_tm_get_jobs_repository()
|
||||
);
|
||||
}
|
||||
|
||||
return $repository;
|
||||
}
|
||||
|
||||
/**
|
||||
* It returns a single instance of the class.
|
||||
*
|
||||
* @return \WPML_WP_User_Query_Factory
|
||||
*/
|
||||
function wpml_tm_get_wp_user_query_factory() {
|
||||
static $wp_user_query_factory;
|
||||
|
||||
if ( ! $wp_user_query_factory ) {
|
||||
$wp_user_query_factory = new WPML_WP_User_Query_Factory();
|
||||
}
|
||||
|
||||
return $wp_user_query_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* It returns a single instance of the class.
|
||||
*
|
||||
* @return \WPML_WP_User_Factory
|
||||
*/
|
||||
function wpml_tm_get_wp_user_factory() {
|
||||
static $wp_user_factory;
|
||||
|
||||
if ( ! $wp_user_factory ) {
|
||||
$wp_user_factory = new WPML_WP_User_Factory();
|
||||
}
|
||||
|
||||
return $wp_user_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* It returns a single instance of the class.
|
||||
*
|
||||
* @return \WPML_TM_Email_Twig_Template_Factory
|
||||
*/
|
||||
function wpml_tm_get_email_twig_template_factory() {
|
||||
static $email_twig_template_factory;
|
||||
|
||||
if ( ! $email_twig_template_factory ) {
|
||||
$email_twig_template_factory = new WPML_TM_Email_Twig_Template_Factory();
|
||||
}
|
||||
|
||||
return $email_twig_template_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* It returns a single instance of the class.
|
||||
*
|
||||
* @return \WPML_TM_AMS_ATE_Factories
|
||||
*/
|
||||
function wpml_tm_ams_ate_factories() {
|
||||
static $tm_ams_ate_factories;
|
||||
|
||||
if ( ! $tm_ams_ate_factories ) {
|
||||
$tm_ams_ate_factories = new WPML_TM_AMS_ATE_Factories();
|
||||
}
|
||||
|
||||
return $tm_ams_ate_factories;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws \Auryn\InjectionException
|
||||
*/
|
||||
function wpml_tm_get_ams_ate_console_url() {
|
||||
/** @var WPML_TM_Admin_Sections $admin_sections */
|
||||
$admin_sections = WPML\Container\make( 'WPML_TM_Admin_Sections' );
|
||||
|
||||
return $admin_sections->get_item_url( WPML_TM_AMS_ATE_Console_Section::SLUG );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WPML\TM\ATE\Log\Entry $entry
|
||||
* @param bool $avoidDuplication
|
||||
*
|
||||
* @throws \WPML\Auryn\InjectionException
|
||||
*/
|
||||
function wpml_tm_ate_ams_log( WPML\TM\ATE\Log\Entry $entry, $avoidDuplication = false ) {
|
||||
make( WPML\TM\ATE\Log\Storage::class )->add( $entry, $avoidDuplication );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WPML\TM\ATE\Log\Entry $entry
|
||||
*
|
||||
* @throws \WPML\Auryn\InjectionException
|
||||
*/
|
||||
function wpml_tm_ate_ams_log_remove( WPML\TM\ATE\Log\Entry $entry ) {
|
||||
make( WPML\TM\ATE\Log\Storage::class )->remove( $entry );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $original
|
||||
* @param string $translation
|
||||
* @param bool $finished_state
|
||||
*
|
||||
* @return WPML_TM_Translated_Field
|
||||
*/
|
||||
function wpml_tm_create_translated_field( $original, $translation, $finished_state ) {
|
||||
return new WPML_TM_Translated_Field( $original, $translation, $finished_state );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
* @param \WP_Post $post
|
||||
* @param bool $force_set_status
|
||||
*/
|
||||
function wpml_tm_save_post( $post_id, $post, $force_set_status = false ) {
|
||||
global $wpdb, $wpml_post_translations, $wpml_term_translations;
|
||||
|
||||
if ( false === $force_set_status && get_post_meta( $post_id, '_icl_lang_duplicate_of', true ) ) {
|
||||
$force_set_status = ICL_TM_DUPLICATE;
|
||||
}
|
||||
|
||||
$action_helper = new WPML_TM_Action_Helper();
|
||||
$blog_translators = wpml_tm_load_blog_translators();
|
||||
$tm_records = new WPML_TM_Records( $wpdb, $wpml_post_translations, $wpml_term_translations );
|
||||
$save_post_action = new WPML_TM_Post_Actions( $action_helper, $blog_translators, $tm_records );
|
||||
if ( 'revision' === $post->post_type || 'auto-draft' === $post->post_status || isset( $_POST['autosave'] ) ) {
|
||||
return;
|
||||
}
|
||||
$save_post_action->save_post_actions( $post_id, $post, $force_set_status );
|
||||
}
|
||||
|
||||
add_action( 'wpml_tm_save_post', 'wpml_tm_save_post', 10, 3 );
|
||||
|
||||
}
|
||||
@@ -0,0 +1,437 @@
|
||||
<?php
|
||||
/**
|
||||
* @global \WPML_Term_Translation $wpml_language_resolution
|
||||
* @global \WPML_Slug_Filter $wpml_slug_filter
|
||||
* @global \WPML_Term_Translation $wpml_term_translations
|
||||
*/
|
||||
|
||||
use WPML\FP\Obj;
|
||||
use WPML\LIB\WP\WPDB as WpWPDB;
|
||||
use function WPML\Container\make;
|
||||
|
||||
require_once __DIR__ . '/wpml_load_request_handler.php';
|
||||
|
||||
function wpml_is_setup_complete() {
|
||||
return (bool) Obj::prop( 'setup_complete', get_option( 'icl_sitepress_settings', [] ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads global variables providing functionality that is used throughout the plugin.
|
||||
*
|
||||
* @param null|bool $is_admin If set to `null` it will read from `is_admin()`
|
||||
*/
|
||||
function load_essential_globals( $is_admin = null ) {
|
||||
global $wpml_language_resolution, $wpml_term_translations, $wpdb;
|
||||
|
||||
$settings = get_option( 'icl_sitepress_settings' );
|
||||
if ( (bool) $settings === false ) {
|
||||
icl_sitepress_activate();
|
||||
} else {
|
||||
|
||||
if ( wpml_is_setup_complete() ) {
|
||||
$active_plugins = get_option( 'active_plugins' );
|
||||
$wpmu_sitewide_plugins = (array) maybe_unserialize( get_site_option( 'active_sitewide_plugins' ) );
|
||||
|
||||
if ( in_array(
|
||||
WPML_PLUGIN_BASENAME,
|
||||
$active_plugins,
|
||||
true
|
||||
) === false &&
|
||||
in_array(
|
||||
WPML_PLUGIN_BASENAME,
|
||||
array_keys( $wpmu_sitewide_plugins ),
|
||||
true
|
||||
) === false
|
||||
) {
|
||||
|
||||
// The plugin has just be reactivated.
|
||||
|
||||
// reset ajx_health_flag
|
||||
// set the just_reactivated flag so any posts created while
|
||||
// WPML was not activate will get the default language
|
||||
// https://onthegosystems.myjetbrains.com/youtrack/issue/wpmlcore-1924
|
||||
$settings['ajx_health_checked'] = 0;
|
||||
$settings['just_reactivated'] = 1;
|
||||
update_option( 'icl_sitepress_settings', $settings );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$active_language_codes = isset( $settings['active_languages'] ) ? $settings['active_languages']
|
||||
: array();
|
||||
$active_language_codes = (bool) $active_language_codes === true
|
||||
? $active_language_codes : wpml_reload_active_languages_setting();
|
||||
$default_lang_code = isset( $settings['default_language'] ) ? $settings['default_language']
|
||||
: false;
|
||||
$wpml_language_resolution = new WPML_Language_Resolution( $active_language_codes, $default_lang_code );
|
||||
$admin = $is_admin === null ? is_admin() : $is_admin;
|
||||
|
||||
wpml_load_post_translation( $admin, $settings );
|
||||
$wpml_term_translations = new WPML_Term_Translation( $wpdb );
|
||||
$domain_validation = filter_input( INPUT_GET, '____icl_validate_domain' ) ? 1 : false;
|
||||
$domain_validation = filter_input( INPUT_GET, '____icl_validate_directory' ) ? 2 : $domain_validation;
|
||||
$url_converter = load_wpml_url_converter( $settings, $domain_validation, $default_lang_code );
|
||||
$directory = $domain_validation === 2 || ( is_multisite() && ! is_subdomain_install() );
|
||||
if ( $domain_validation ) {
|
||||
echo wpml_validate_host( $_SERVER['REQUEST_URI'], $url_converter, $directory );
|
||||
exit;
|
||||
}
|
||||
if ( $admin ) {
|
||||
wpml_load_admin_files();
|
||||
}
|
||||
}
|
||||
|
||||
function wpml_load_post_translation( $is_admin, $settings ) {
|
||||
global $wpml_post_translations, $wpdb;
|
||||
|
||||
$http_referer = make( WPML_URL_HTTP_Referer::class );
|
||||
|
||||
if (
|
||||
$is_admin === true
|
||||
|| $http_referer->is_rest_request_called_from_post_edit_page()
|
||||
|| ( defined( 'WP_CLI' ) && WP_CLI )
|
||||
) {
|
||||
$wpml_post_translations = new WPML_Admin_Post_Actions( $settings, $wpdb );
|
||||
} else {
|
||||
$wpml_post_translations = new WPML_Frontend_Post_Actions( $settings, $wpdb );
|
||||
wpml_load_frontend_tax_filters();
|
||||
}
|
||||
|
||||
$wpml_post_translations->init();
|
||||
}
|
||||
|
||||
function wpml_load_query_filter( $installed ) {
|
||||
global $wpml_query_filter, $sitepress, $wpdb, $wpml_post_translations, $wpml_term_translations;
|
||||
|
||||
$wpml_query_filter = $wpml_query_filter ? $wpml_query_filter : new WPML_Query_Filter( $sitepress, $wpdb, $wpml_post_translations, $wpml_term_translations );
|
||||
if ( $installed ) {
|
||||
if ( ! has_filter( 'posts_join', array( $wpml_query_filter, 'posts_join_filter' ) ) ) {
|
||||
add_filter( 'posts_join', array( $wpml_query_filter, 'posts_join_filter' ), 10, 2 );
|
||||
add_filter( 'posts_where', array( $wpml_query_filter, 'posts_where_filter' ), 10, 2 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function load_wpml_url_converter( $settings, $domain_validation, $default_lang_code ) {
|
||||
/**
|
||||
* @var WPML_URL_Converter $wpml_url_converter
|
||||
* @var WPML_Language_Resolution $wpml_language_resolution
|
||||
*/
|
||||
global $wpml_url_converter, $wpml_language_resolution;
|
||||
|
||||
$url_type = isset( $settings['language_negotiation_type'] ) ? $settings['language_negotiation_type'] : false;
|
||||
$url_type = $domain_validation ? $domain_validation : $url_type;
|
||||
$active_language_codes = $wpml_language_resolution->get_active_language_codes();
|
||||
|
||||
WPML_URL_Converter_Factory::remove_previous_hooks();
|
||||
$factory = new WPML_URL_Converter_Factory( $settings, $default_lang_code, $active_language_codes );
|
||||
$wpml_url_converter = $factory->create( (int) $url_type );
|
||||
|
||||
return $wpml_url_converter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $req_uri
|
||||
* @param WPML_URL_Converter $wpml_url_converter
|
||||
* @param bool $directory
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function wpml_validate_host( $req_uri, $wpml_url_converter, $directory = true ) {
|
||||
if ( $directory === true ) {
|
||||
$req_uri_parts = array_filter( explode( '/', $req_uri ) );
|
||||
$lang_slug = array_pop( $req_uri_parts );
|
||||
if ( strpos( $lang_slug, '?' ) === 0 ) {
|
||||
$lang_slug = array_pop( $req_uri_parts );
|
||||
} elseif ( strpos( $lang_slug, '?' ) !== false ) {
|
||||
$parts = explode( '?', $lang_slug );
|
||||
$lang_slug = array_shift( $parts );
|
||||
}
|
||||
} else {
|
||||
$lang_slug = '';
|
||||
}
|
||||
|
||||
return '<!--' . esc_url( untrailingslashit( trailingslashit( $wpml_url_converter->get_abs_home() ) . $lang_slug ) ) . '-->';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given taxonomy is currently translated
|
||||
*
|
||||
* @param string $taxonomy name/slug of a taxonomy
|
||||
* @return bool true if the taxonomy is currently set to being translatable in WPML
|
||||
*/
|
||||
function is_taxonomy_translated( $taxonomy ) {
|
||||
|
||||
return in_array( $taxonomy, array( 'category', 'post_tag', 'nav_menu' ), true )
|
||||
|| in_array(
|
||||
$taxonomy,
|
||||
array_keys( array_filter( icl_get_setting( 'taxonomies_sync_option', array() ) ) )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given post_type is currently translated
|
||||
*
|
||||
* @param string $post_type name/slug of a post_type
|
||||
* @return bool true if the post_type is currently set to being translatable in WPML
|
||||
*/
|
||||
function is_post_type_translated( $post_type ) {
|
||||
|
||||
return 'nav_menu_item' === $post_type ||
|
||||
in_array(
|
||||
$post_type,
|
||||
array_keys( array_filter( icl_get_setting( 'custom_posts_sync_option', array() ) ) )
|
||||
);
|
||||
}
|
||||
|
||||
function setup_admin_menus() {
|
||||
global $pagenow, $sitepress;
|
||||
|
||||
if ( $pagenow === 'edit-tags.php' || $pagenow === 'term.php' ) {
|
||||
maybe_load_translated_tax_screen();
|
||||
$wpml_term_translation_help_notice = new WPML_Taxonomy_Translation_Help_Notice( wpml_get_admin_notices(), $sitepress );
|
||||
$wpml_term_translation_help_notice->add_hooks();
|
||||
}
|
||||
}
|
||||
|
||||
function maybe_load_translated_tax_screen() {
|
||||
$taxonomy_get = (string) filter_input( INPUT_GET, 'taxonomy' );
|
||||
$taxonomy_get = $taxonomy_get ? $taxonomy_get : 'post_tag';
|
||||
if ( is_taxonomy_translated( $taxonomy_get ) ) {
|
||||
global $wpdb, $sitepress;
|
||||
require WPML_PLUGIN_PATH . '/menu/term-taxonomy-menus/wpml-tax-menu-loader.class.php';
|
||||
new WPML_Tax_Menu_Loader( $wpdb, $sitepress, $taxonomy_get );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $override
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function wpml_reload_active_languages_setting( $override = false ) {
|
||||
global $wpdb, $sitepress_settings;
|
||||
|
||||
if ( true === (bool) $sitepress_settings
|
||||
&& ( $override || wpml_is_setup_complete() )
|
||||
) {
|
||||
// This won't output any MySQL error if `icl_languages` is missing on the
|
||||
// current site, and it will return an empty array in that case.
|
||||
$active_languages = WpWPDB::withoutError( function() use ( $wpdb ) {
|
||||
return $wpdb->get_col( "
|
||||
SELECT code
|
||||
FROM {$wpdb->prefix}icl_languages
|
||||
WHERE active = 1
|
||||
" );
|
||||
} );
|
||||
|
||||
$sitepress_settings['active_languages'] = $active_languages;
|
||||
icl_set_setting( 'active_languages', $active_languages, true );
|
||||
} else {
|
||||
$active_languages = [];
|
||||
}
|
||||
|
||||
return (array) $active_languages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns and if necessary instantiates an instance of the WPML_Installation Class
|
||||
*
|
||||
* @return \WPML_Installation
|
||||
*/
|
||||
function wpml_get_setup_instance() {
|
||||
global $wpml_installation, $wpdb, $sitepress;
|
||||
|
||||
if ( ! isset( $wpml_installation ) ) {
|
||||
$wpml_installation = new WPML_Installation( $wpdb, $sitepress );
|
||||
}
|
||||
|
||||
return $wpml_installation;
|
||||
}
|
||||
|
||||
function wpml_load_admin_files() {
|
||||
require_once WPML_PLUGIN_PATH . '/menu/wpml-troubleshooting-terms-menu.class.php';
|
||||
require_once WPML_PLUGIN_PATH . '/inc/wpml-post-edit-ajax.class.php';
|
||||
require_once WPML_PLUGIN_PATH . '/menu/wpml-post-status-display.class.php';
|
||||
require_once WPML_PLUGIN_PATH . '/inc/utilities/wpml-color-picker.class.php';
|
||||
}
|
||||
|
||||
function wpml_get_post_status_helper() {
|
||||
global $wpml_post_status, $wpdb, $sitepress;
|
||||
|
||||
if ( ! isset( $wpml_post_status ) ) {
|
||||
$wpml_post_status = new WPML_Post_Status( $wpdb, $sitepress->get_wp_api() );
|
||||
}
|
||||
|
||||
return $wpml_post_status;
|
||||
}
|
||||
|
||||
function wpml_get_create_post_helper() {
|
||||
global $sitepress;
|
||||
|
||||
return new WPML_Create_Post_Helper( $sitepress );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \TranslationManagement
|
||||
*/
|
||||
function wpml_load_core_tm() {
|
||||
global $iclTranslationManagement;
|
||||
|
||||
if ( ! isset( $iclTranslationManagement ) ) {
|
||||
require_once WPML_PLUGIN_PATH . '/inc/translation-management/translation-management.class.php';
|
||||
$iclTranslationManagement = new TranslationManagement();
|
||||
}
|
||||
|
||||
return $iclTranslationManagement;
|
||||
}
|
||||
|
||||
function wpml_get_langs_in_dirs_val( $wpml_url_converter ) {
|
||||
global $sitepress;
|
||||
|
||||
return new WPML_Lang_URL_Validator( $wpml_url_converter, $sitepress );
|
||||
}
|
||||
|
||||
function wpml_get_root_page_actions_obj() {
|
||||
global $wpml_root_page_actions, $sitepress_settings;
|
||||
|
||||
if ( ! isset( $wpml_root_page_actions ) ) {
|
||||
require_once WPML_PLUGIN_PATH . '/inc/post-translation/wpml-root-page-actions.class.php';
|
||||
$wpml_root_page_actions = new WPML_Root_Page_Actions( $sitepress_settings );
|
||||
}
|
||||
|
||||
return $wpml_root_page_actions;
|
||||
}
|
||||
|
||||
function wpml_get_hierarchy_sync_helper( $type = 'post' ) {
|
||||
global $wpdb;
|
||||
|
||||
if ( $type === 'post' ) {
|
||||
require_once WPML_PLUGIN_PATH . '/inc/post-translation/wpml-post-hierarchy-sync.class.php';
|
||||
$hierarchy_helper = new WPML_Post_Hierarchy_Sync( $wpdb );
|
||||
} elseif ( $type === 'term' ) {
|
||||
require_once WPML_PLUGIN_PATH . '/inc/taxonomy-term-translation/wpml-term-hierarchy-sync.class.php';
|
||||
$hierarchy_helper = new WPML_Term_Hierarchy_Sync( $wpdb );
|
||||
} else {
|
||||
$hierarchy_helper = false;
|
||||
}
|
||||
|
||||
return $hierarchy_helper;
|
||||
}
|
||||
|
||||
function wpml_maybe_setup_post_edit() {
|
||||
global $pagenow, $sitepress, $post_edit_screen;
|
||||
|
||||
if (
|
||||
in_array( $pagenow, [ 'post.php', 'post-new.php', 'edit.php' ], true ) ||
|
||||
defined( 'DOING_AJAX' ) ||
|
||||
apply_filters( 'wpml_enable_language_meta_box', false )
|
||||
) {
|
||||
$post_edit_screen = new WPML_Post_Edit_Screen( $sitepress );
|
||||
add_action( 'admin_head', [ $sitepress, 'post_edit_language_options' ] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \WPML_Frontend_Tax_Filters
|
||||
*/
|
||||
function wpml_load_frontend_tax_filters() {
|
||||
global $wpml_term_filters;
|
||||
|
||||
if ( ! isset( $wpml_term_filters ) ) {
|
||||
require WPML_PLUGIN_PATH . '/inc/taxonomy-term-translation/wpml-frontend-tax-filters.class.php';
|
||||
$wpml_term_filters = new WPML_Frontend_Tax_Filters();
|
||||
}
|
||||
|
||||
return $wpml_term_filters;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \WPML_Settings_Helper
|
||||
*/
|
||||
function wpml_load_settings_helper() {
|
||||
global $wpml_settings_helper, $sitepress, $wpml_post_translations;
|
||||
|
||||
if ( ! isset( $wpml_settings_helper ) ) {
|
||||
$wpml_settings_helper = new WPML_Settings_Helper( $wpml_post_translations, $sitepress );
|
||||
}
|
||||
|
||||
return $wpml_settings_helper;
|
||||
}
|
||||
|
||||
function wpml_get_term_translation_util() {
|
||||
global $sitepress;
|
||||
require_once WPML_PLUGIN_PATH . '/inc/taxonomy-term-translation/wpml-term-translation-utils.class.php';
|
||||
|
||||
return new WPML_Term_Translation_Utils( $sitepress );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \WPML_Term_Filters
|
||||
*/
|
||||
function wpml_load_term_filters() {
|
||||
global $wpml_term_filters_general, $sitepress, $wpdb;
|
||||
|
||||
if ( ! isset( $wpml_term_filters_general ) ) {
|
||||
require WPML_PLUGIN_PATH . '/inc/taxonomy-term-translation/wpml-term-filters.class.php';
|
||||
$wpml_term_filters_general = new WPML_Term_Filters( $wpdb, $sitepress );
|
||||
$wpml_term_filters_general->init();
|
||||
}
|
||||
|
||||
return $wpml_term_filters_general;
|
||||
}
|
||||
|
||||
function wpml_show_user_options() {
|
||||
global $sitepress, $current_user, $user_id, $pagenow;
|
||||
|
||||
if ( ! isset( $user_id ) && 'profile.php' === $pagenow ) {
|
||||
$user_id = $current_user->ID;
|
||||
}
|
||||
|
||||
$user = new WP_User( $user_id );
|
||||
$user_options_menu = new WPML_User_Options_Menu( $sitepress, $user );
|
||||
echo $user_options_menu->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \WPML_Upgrade_Command_Factory
|
||||
*/
|
||||
function wpml_get_upgrade_command_factory() {
|
||||
static $factory;
|
||||
if ( ! $factory ) {
|
||||
$factory = new WPML_Upgrade_Command_Factory();
|
||||
}
|
||||
|
||||
return $factory;
|
||||
}
|
||||
|
||||
function wpml_get_upgrade_schema() {
|
||||
global $wpdb;
|
||||
static $instance;
|
||||
|
||||
if ( ! $instance ) {
|
||||
$instance = new WPML_Upgrade_Schema( $wpdb );
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $class_name A class implementing \IWPML_Upgrade_Command.
|
||||
* @param array $dependencies An array of dependencies passed to the `$class_name`'s constructor.
|
||||
* @param array $scopes An array of scope values. Accepted values are: `\WPML_Upgrade::SCOPE_ADMIN`, `\WPML_Upgrade::SCOPE_AJAX`, and `\WPML_Upgrade::SCOPE_FRONT_END`.
|
||||
* @param string|null $method The method to call to run the upgrade (otherwise, it calls the "run" method),
|
||||
*
|
||||
* @return \WPML_Upgrade_Command_Definition
|
||||
*/
|
||||
function wpml_create_upgrade_command_definition( $class_name, array $dependencies, array $scopes, $method = null ) {
|
||||
return wpml_get_upgrade_command_factory()->create_command_definition( $class_name, $dependencies, $scopes, $method );
|
||||
}
|
||||
|
||||
if ( is_admin() ) {
|
||||
add_action( 'personal_options', 'wpml_show_user_options' );
|
||||
}
|
||||
|
||||
|
||||
// TM
|
||||
require_once 'functions-load-tm.php';
|
||||
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
wp_cache_add_global_groups( array( 'sitepress_ms' ) );
|
||||
|
||||
$filtered_action = filter_input( INPUT_POST, 'action', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_NULL_ON_FAILURE );
|
||||
$filtered_action = $filtered_action ? $filtered_action : filter_input( INPUT_GET, 'action', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_NULL_ON_FAILURE );
|
||||
if ( 0 === strcmp( $filtered_action, 'resetwpml' ) ) {
|
||||
include_once WPML_PLUGIN_PATH . '/inc/functions-troubleshooting.php';
|
||||
}
|
||||
|
||||
add_action( 'network_admin_menu', 'icl_network_administration_menu' );
|
||||
add_action( 'wpmuadminedit', 'icl_wpmuadminedit' );
|
||||
|
||||
function icl_wpmuadminedit() {
|
||||
if ( ! isset( $_REQUEST['action'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$filtered_action = filter_input( INPUT_POST, 'action', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_NULL_ON_FAILURE );
|
||||
$filtered_action = $filtered_action ? $filtered_action : filter_input( INPUT_GET, 'action', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_NULL_ON_FAILURE );
|
||||
|
||||
switch ( $filtered_action ) {
|
||||
case 'resetwpml':
|
||||
icl_network_reset_wpml();
|
||||
break;
|
||||
case 'deactivatewpml':
|
||||
icl_network_deactivate_wpml();
|
||||
break;
|
||||
case 'activatewpml':
|
||||
icl_network_activate_wpml();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function icl_network_administration_menu() {
|
||||
add_menu_page(
|
||||
__( 'WPML', 'sitepress' ),
|
||||
__( 'WPML', 'sitepress' ),
|
||||
'manage_sitess',
|
||||
WPML_PLUGIN_FOLDER . '/menu/network.php',
|
||||
null,
|
||||
ICL_PLUGIN_URL . '/res/img/icon16.png'
|
||||
);
|
||||
add_submenu_page(
|
||||
WPML_PLUGIN_FOLDER . '/menu/network.php',
|
||||
__( 'Network settings', 'sitepress' ),
|
||||
__( 'Network settings', 'sitepress' ),
|
||||
'manage_sites',
|
||||
WPML_PLUGIN_FOLDER . '/menu/network.php'
|
||||
);
|
||||
}
|
||||
|
||||
function icl_network_reset_wpml() {
|
||||
|
||||
icl_reset_wpml();
|
||||
|
||||
wp_redirect( network_admin_url( 'admin.php?page=' . WPML_PLUGIN_FOLDER . '/menu/network.php&updated=true&action=resetwpml' ) );
|
||||
}
|
||||
|
||||
function icl_network_deactivate_wpml( $blog_id = false ) {
|
||||
global $wpdb;
|
||||
|
||||
$filtered_action = filter_input( INPUT_POST, 'action', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_NULL_ON_FAILURE );
|
||||
$filtered_action = $filtered_action ? $filtered_action : filter_input( INPUT_GET, 'action', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_NULL_ON_FAILURE );
|
||||
|
||||
if ( 0 === strcmp( $filtered_action, 'deactivatewpml' ) ) {
|
||||
if ( empty( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'deactivatewpml' ) ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $blog_id ) ) {
|
||||
$filtered_id = filter_input( INPUT_POST, 'id', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_NULL_ON_FAILURE );
|
||||
$filtered_id = $filtered_id ? $filtered_id : filter_input( INPUT_GET, 'id', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_NULL_ON_FAILURE );
|
||||
$blog_id = $filtered_id !== false ? $filtered_id : $wpdb->blogid;
|
||||
}
|
||||
|
||||
if ( $blog_id ) {
|
||||
switch_to_blog( $blog_id );
|
||||
update_option( '_wpml_inactive', true );
|
||||
restore_current_blog();
|
||||
}
|
||||
|
||||
wp_redirect( network_admin_url( 'admin.php?page=' . WPML_PLUGIN_FOLDER . '/menu/network.php&updated=true&action=deactivatewpml' ) );
|
||||
}
|
||||
|
||||
function icl_network_activate_wpml( $blog_id = false ) {
|
||||
global $wpdb;
|
||||
|
||||
$filtered_action = filter_input( INPUT_POST, 'action', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_NULL_ON_FAILURE );
|
||||
$filtered_action = $filtered_action ? $filtered_action : filter_input( INPUT_GET, 'action', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_NULL_ON_FAILURE );
|
||||
|
||||
if ( 0 === strcmp( $filtered_action, 'activatewpml' ) ) {
|
||||
if ( empty( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'activatewpml' ) ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $blog_id ) ) {
|
||||
$filtered_id = filter_input( INPUT_POST, 'id', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_NULL_ON_FAILURE );
|
||||
$filtered_id = $filtered_id ? $filtered_id : filter_input( INPUT_GET, 'id', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_NULL_ON_FAILURE );
|
||||
$blog_id = $filtered_id !== false ? $filtered_id : $wpdb->blogid;
|
||||
}
|
||||
|
||||
if ( $blog_id ) {
|
||||
switch_to_blog( $blog_id );
|
||||
delete_option( '_wpml_inactive' );
|
||||
restore_current_blog();
|
||||
}
|
||||
|
||||
wp_redirect( network_admin_url( 'admin.php?page=' . WPML_PLUGIN_FOLDER . '/menu/network.php&updated=true&action=activatewpml' ) );
|
||||
exit();
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
/**
|
||||
* @param string $input
|
||||
* @param string $default_if_invalid
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function wpml_sanitize_hex_color( $input, $default_if_invalid = '' ) {
|
||||
$input = sanitize_text_field( $input );
|
||||
$result = $input;
|
||||
if ( ! is_string( $input ) || ! wpml_is_valid_hex_color( $input ) ) {
|
||||
$result = $default_if_invalid;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
function wpml_sanitize_hex_color_array( $input, $default_if_invalid = '', $bypass_non_strings = true, $recursive = false ) {
|
||||
$result = $input;
|
||||
if ( is_array( $input ) ) {
|
||||
$result = array();
|
||||
foreach ( $input as $key => $value ) {
|
||||
if ( is_array( $value ) && $recursive ) {
|
||||
$result[ $key ] = wpml_sanitize_hex_color_array( $value, $default_if_invalid, $recursive );
|
||||
} elseif ( is_string( $value ) ) {
|
||||
$result[ $key ] = wpml_sanitize_hex_color( $value, $default_if_invalid );
|
||||
} elseif ( $bypass_non_strings ) {
|
||||
$result[ $key ] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $input
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function wpml_is_valid_hex_color( $input ) {
|
||||
if ( 'transparent' === $input || preg_match( '/' . wpml_get_valid_hex_color_pattern() . '/i', $input ) ) {
|
||||
$is_valid = true;
|
||||
} else {
|
||||
$try_rgb2hex = wpml_rgb_to_hex( $input );
|
||||
$is_valid = $try_rgb2hex ? preg_match( '/' . wpml_get_valid_hex_color_pattern() . '/i', $try_rgb2hex ) : false;
|
||||
}
|
||||
|
||||
return $is_valid;
|
||||
}
|
||||
|
||||
function wpml_get_valid_hex_color_pattern() {
|
||||
return '(^#[a-fA-F0-9]{6}$)|(^#[a-fA-F0-9]{3}$)';
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert RGB color code to HEX code.
|
||||
*
|
||||
* @param array $rgb
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
function wpml_rgb_to_hex( $rgb ) {
|
||||
if ( ! is_array( $rgb ) || count( $rgb ) < 3 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$hex = '#';
|
||||
$hex .= str_pad( dechex( $rgb[0] ), 2, '0', STR_PAD_LEFT );
|
||||
$hex .= str_pad( dechex( $rgb[1] ), 2, '0', STR_PAD_LEFT );
|
||||
$hex .= str_pad( dechex( $rgb[2] ), 2, '0', STR_PAD_LEFT );
|
||||
|
||||
return $hex;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
function wpml_get_authenticated_action() {
|
||||
|
||||
$action = filter_input( INPUT_POST, 'icl_ajx_action' );
|
||||
$action = $action ? $action : filter_input( INPUT_POST, 'action' );
|
||||
$nonce = $action ? filter_input( INPUT_POST, '_icl_nonce' ) : null;
|
||||
if ( $nonce === null || $action === null ) {
|
||||
$action = filter_input( INPUT_GET, 'icl_ajx_action' );
|
||||
$nonce = $action ? filter_input( INPUT_GET, '_icl_nonce' ) : null;
|
||||
}
|
||||
|
||||
$authenticated_action = $action && wp_verify_nonce( (string) $nonce, $action . '_nonce' ) ? $action : null;
|
||||
|
||||
return $authenticated_action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a nonce according to the schema also used by \wpml_nonce_field
|
||||
*
|
||||
* @param string $action
|
||||
*
|
||||
* @return false|int
|
||||
*/
|
||||
function wpml_is_action_authenticated( $action ) {
|
||||
$nonce = isset( $_POST['_icl_nonce'] ) ? $_POST['_icl_nonce'] : '';
|
||||
if ( '' !== $nonce ) {
|
||||
$action = $action . '_nonce';
|
||||
} else {
|
||||
$nonce = isset( $_POST['nonce'] ) ? $_POST['nonce'] : '';
|
||||
}
|
||||
|
||||
return wp_verify_nonce( $nonce, $action );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates HTML for the hidden nonce input field following the schema
|
||||
* used by \wpml_is_action_authenticated
|
||||
*
|
||||
* @param string $action
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function wpml_nonce_field( $action ) {
|
||||
return '<input name="_icl_nonce" type="hidden" value="'
|
||||
. wp_create_nonce( $action . '_nonce' ) . '"/>';
|
||||
}
|
||||
|
||||
/**
|
||||
* RFC 4122 compliant UUID version 5.
|
||||
*
|
||||
* @param string $name The name to generate the UUID from.
|
||||
* @param string $ns_uuid Namespace UUID. Default is for the NS when name string is a URL.
|
||||
*
|
||||
* @return string The UUID string.
|
||||
*/
|
||||
if ( ! function_exists( 'uuid_v5' ) ) {
|
||||
function uuid_v5( $name, $ns_uuid = '6ba7b811-9dad-11d1-80b4-00c04fd430c8' ) {
|
||||
$wpml_uuid = new WPML_UUID();
|
||||
return $wpml_uuid->get_uuid_v5( $name, $ns_uuid );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $object_id
|
||||
* @param string $object_type
|
||||
* @param int|null $timestamp If this parameter is `null`, it will be assigned the current time
|
||||
* Set this parameter to 0 if the uuid should not have a time footprint
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function wpml_uuid( $object_id, $object_type, $timestamp = null ) {
|
||||
$wpml_uuid = new WPML_UUID();
|
||||
return $wpml_uuid->get( $object_id, $object_type, $timestamp );
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
<?php
|
||||
|
||||
function icl_reset_wpml( $blog_id = false ) {
|
||||
global $wpdb, $sitepress_settings;
|
||||
|
||||
if ( isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'resetwpml' ) {
|
||||
check_admin_referer( 'resetwpml' );
|
||||
}
|
||||
|
||||
if ( empty( $blog_id ) ) {
|
||||
$filtered_id = filter_input( INPUT_POST, 'id', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_NULL_ON_FAILURE );
|
||||
$filtered_id = $filtered_id ? $filtered_id : filter_input( INPUT_GET, 'id', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_NULL_ON_FAILURE );
|
||||
$blog_id = $filtered_id !== false ? $filtered_id : $wpdb->blogid;
|
||||
}
|
||||
|
||||
if ( $blog_id || ! function_exists( 'is_multisite' ) || ! is_multisite() ) {
|
||||
|
||||
if ( function_exists( 'is_multisite' ) && is_multisite() ) {
|
||||
switch_to_blog( $blog_id );
|
||||
}
|
||||
|
||||
do_action( 'wpml_reset_plugins_before' );
|
||||
|
||||
wp_clear_scheduled_hook( 'update_wpml_config_index' );
|
||||
|
||||
$icl_tables = array(
|
||||
$wpdb->prefix . 'icl_languages',
|
||||
$wpdb->prefix . 'icl_languages_translations',
|
||||
$wpdb->prefix . 'icl_translations',
|
||||
$wpdb->prefix . 'icl_translation_status',
|
||||
$wpdb->prefix . 'icl_translate_job',
|
||||
$wpdb->prefix . 'icl_translate',
|
||||
$wpdb->prefix . 'icl_locale_map',
|
||||
$wpdb->prefix . 'icl_flags',
|
||||
$wpdb->prefix . 'icl_content_status',
|
||||
$wpdb->prefix . 'icl_core_status',
|
||||
$wpdb->prefix . 'icl_node',
|
||||
$wpdb->prefix . 'icl_strings',
|
||||
$wpdb->prefix . 'icl_string_packages',
|
||||
$wpdb->prefix . 'icl_translation_batches',
|
||||
$wpdb->prefix . 'icl_string_translations',
|
||||
$wpdb->prefix . 'icl_string_status',
|
||||
$wpdb->prefix . 'icl_string_positions',
|
||||
$wpdb->prefix . 'icl_message_status',
|
||||
$wpdb->prefix . 'icl_reminders',
|
||||
$wpdb->prefix . 'icl_mo_files_domains',
|
||||
$wpdb->prefix . 'icl_string_pages',
|
||||
$wpdb->prefix . 'icl_string_urls',
|
||||
$wpdb->prefix . 'icl_cms_nav_cache',
|
||||
$wpdb->prefix . 'icl_string_batches',
|
||||
$wpdb->prefix . 'icl_translation_downloads',
|
||||
);
|
||||
$icl_tables = apply_filters( 'wpml_reset_tables', $icl_tables, $blog_id );
|
||||
|
||||
foreach ( $icl_tables as $icl_table ) {
|
||||
$wpdb->query( 'DROP TABLE IF EXISTS ' . $icl_table );
|
||||
}
|
||||
|
||||
$wpml_options = array(
|
||||
'icl_sitepress_settings',
|
||||
'icl_sitepress_version',
|
||||
'_icl_cache',
|
||||
'_icl_admin_option_names',
|
||||
'wp_icl_translators_cached',
|
||||
'wpml32_icl_non_translators_cached',
|
||||
'wpml-package-translation-db-updates-run',
|
||||
'wpml-package-translation-refresh-required',
|
||||
'wpml-package-translation-string-packages-table-updated',
|
||||
'wpml-package-translation-string-table-updated',
|
||||
'icl_translation_jobs_basket',
|
||||
'widget_icl_lang_sel_widget',
|
||||
'icl_admin_messages',
|
||||
'icl_adl_settings',
|
||||
'wpml_tp_com_log',
|
||||
'wpml_config_index',
|
||||
'wpml_config_index_updated',
|
||||
'wpml_config_files_arr',
|
||||
'wpml_language_switcher',
|
||||
'wpml_notices',
|
||||
'wpml_start_version',
|
||||
'wpml_dependencies:installed_plugins',
|
||||
'wpml_translation_services',
|
||||
'wpml_update_statuses',
|
||||
'_wpml_dismissed_notices',
|
||||
'wpml_translation_services_timestamp',
|
||||
'wpml_string_table_ok_for_mo_import',
|
||||
'wpml-charset-validation',
|
||||
'_wpml_media',
|
||||
'wpml_st_display_strings_scan_notices',
|
||||
'wpml-st-all-strings-are-in-english',
|
||||
'wpml_strings_need_links_fixed',
|
||||
'_wpml_batch_report',
|
||||
'wpml_cms_nav_settings',
|
||||
'WPML_CMS_NAV_VERSION',
|
||||
'icl_st_settings',
|
||||
'wpml-tm-custom-xml',
|
||||
'wpml-st-persist-errors',
|
||||
'wpml_base_slug_translation',
|
||||
);
|
||||
$wpml_options = apply_filters( 'wpml_reset_options', $wpml_options, $blog_id );
|
||||
|
||||
foreach ( $wpml_options as $wpml_option ) {
|
||||
delete_option( $wpml_option );
|
||||
}
|
||||
|
||||
$wpml_user_options = array(
|
||||
'language_pairs',
|
||||
);
|
||||
$wpml_user_options = apply_filters( 'wpml_reset_user_options', $wpml_user_options, $blog_id );
|
||||
if ( $wpml_user_options ) {
|
||||
foreach ( $wpml_user_options as $wpml_user_option ) {
|
||||
|
||||
$meta_key = $wpdb->get_blog_prefix( $blog_id ) . $wpml_user_option;
|
||||
$users = get_users(
|
||||
array(
|
||||
'blog_id' => $blog_id,
|
||||
'meta_key' => $meta_key,
|
||||
'fields' => array( 'ID' ),
|
||||
)
|
||||
);
|
||||
|
||||
/** @var WP_User $user */
|
||||
foreach ( $users as $user ) {
|
||||
delete_user_option( $user->ID, $wpml_user_option );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$capabilities = array(
|
||||
'wpml_manage_translation_management',
|
||||
'wpml_manage_languages',
|
||||
'wpml_manage_theme_and_plugin_localization',
|
||||
'wpml_manage_support',
|
||||
'wpml_manage_woocommerce_multilingual',
|
||||
'wpml_operate_woocommerce_multilingual',
|
||||
'wpml_manage_media_translation',
|
||||
'wpml_manage_navigation',
|
||||
'wpml_manage_sticky_links',
|
||||
'wpml_manage_string_translation',
|
||||
'wpml_manage_translation_analytics',
|
||||
'wpml_manage_wp_menus_sync',
|
||||
'wpml_manage_taxonomy_translation',
|
||||
'wpml_manage_troubleshooting',
|
||||
'wpml_manage_translation_options',
|
||||
'manage_translations',
|
||||
'translate',
|
||||
);
|
||||
|
||||
$capabilities = apply_filters( 'wpml_reset_user_capabilities', $capabilities, $blog_id );
|
||||
if ( $capabilities ) {
|
||||
$users = get_users(
|
||||
array(
|
||||
'blog_id' => $blog_id,
|
||||
)
|
||||
);
|
||||
|
||||
/** @var WP_User $user */
|
||||
foreach ( $users as $user ) {
|
||||
foreach ( $capabilities as $capability ) {
|
||||
$user->remove_cap( $capability );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$sitepress_settings = null;
|
||||
wp_cache_init();
|
||||
|
||||
$wpml_cache_directory = new WPML_Cache_Directory( new WPML_WP_API() );
|
||||
$wpml_cache_directory->remove();
|
||||
|
||||
do_action( 'wpml_reset_plugins_after' );
|
||||
|
||||
$wpmu_sitewide_plugins = (array) maybe_unserialize( get_site_option( 'active_sitewide_plugins' ) );
|
||||
if ( ! isset( $wpmu_sitewide_plugins[ WPML_PLUGIN_BASENAME ] ) ) {
|
||||
remove_action( 'deactivate_' . WPML_PLUGIN_BASENAME, 'icl_sitepress_deactivate' );
|
||||
deactivate_plugins( WPML_PLUGIN_BASENAME );
|
||||
$ra = get_option( 'recently_activated' );
|
||||
$ra[ WPML_PLUGIN_BASENAME ] = time();
|
||||
update_option( 'recently_activated', $ra );
|
||||
} else {
|
||||
update_option( '_wpml_inactive', true );
|
||||
}
|
||||
|
||||
$options_to_delete_after_deactivation = array(
|
||||
'wpml_dependencies:needs_validation',
|
||||
'wpml_dependencies:valid_plugins',
|
||||
'wpml_dependencies:invalid_plugins',
|
||||
);
|
||||
$options_to_delete_after_deactivation = apply_filters( 'wpml_reset_options_after_deactivation', $options_to_delete_after_deactivation, $blog_id );
|
||||
|
||||
foreach ( $options_to_delete_after_deactivation as $option ) {
|
||||
delete_option( $option );
|
||||
}
|
||||
|
||||
if ( function_exists( 'is_multisite' ) && is_multisite() ) {
|
||||
restore_current_blog();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax handler for type assignment fix troubleshoot action
|
||||
*/
|
||||
function icl_repair_broken_type_and_language_assignments() {
|
||||
global $sitepress;
|
||||
|
||||
$lang_setter = new WPML_Fix_Type_Assignments( $sitepress );
|
||||
$rows_fixed = $lang_setter->run();
|
||||
|
||||
wp_send_json_success( $rows_fixed );
|
||||
}
|
||||
885
wp-content/plugins/sitepress-multilingual-cms/inc/functions.php
Normal file
885
wp-content/plugins/sitepress-multilingual-cms/inc/functions.php
Normal file
@@ -0,0 +1,885 @@
|
||||
<?php
|
||||
/**
|
||||
* SitePress Template functions
|
||||
*
|
||||
* @package wpml-core
|
||||
*/
|
||||
|
||||
use function WPML\Container\make;
|
||||
|
||||
/**
|
||||
* Returns true if the site uses ICanLocalize.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function wpml_site_uses_icl() {
|
||||
global $wpdb;
|
||||
|
||||
$setting = 'site_does_not_use_icl';
|
||||
|
||||
if ( icl_get_setting( $setting, false ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$cache = new WPML_WP_Cache( 'wpml-checks' );
|
||||
|
||||
$found = false;
|
||||
$site_uses_icl = $cache->get( 'site_uses_icl', $found );
|
||||
|
||||
if ( ! $found ) {
|
||||
$site_uses_icl = false;
|
||||
|
||||
$table_exists = $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->prefix}icl_translation_status'" );
|
||||
|
||||
if ( $table_exists ) {
|
||||
$icl_job_count_query = $wpdb->prepare(
|
||||
"SELECT rid
|
||||
FROM {$wpdb->prefix}icl_translation_status
|
||||
WHERE translation_service = %s
|
||||
LIMIT 1;",
|
||||
'icanlocalize'
|
||||
);
|
||||
|
||||
$site_uses_icl = (bool) $wpdb->get_var( $icl_job_count_query );
|
||||
}
|
||||
$cache->set( 'site_uses_icl', $site_uses_icl );
|
||||
}
|
||||
|
||||
if ( icl_get_setting( 'setup_complete', false ) && ! $site_uses_icl ) {
|
||||
icl_set_setting( $setting, true, true );
|
||||
}
|
||||
|
||||
return $site_uses_icl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a given key setting.
|
||||
*
|
||||
* @param string $key The setting's key.
|
||||
* @param mixed|false $default The value to use if the setting does not exist.
|
||||
*
|
||||
* @return bool|mixed
|
||||
* @since 3.1
|
||||
* @deprecated 3.2 use `\wpml_setting` or 'wpml_get_setting_filter' filter instead
|
||||
*/
|
||||
function icl_get_setting( $key, $default = false ) {
|
||||
return wpml_get_setting( $key, $default );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a WPML setting value.
|
||||
* If the Main SitePress Class cannot be accessed by the function it will read the setting from the database.
|
||||
* It will return `$default` if the requested key is not set.
|
||||
*
|
||||
* @param string $key The setting's key.
|
||||
* @param mixed|null $default Required. The value to return if the settings key does not exist
|
||||
* (typically it's false, but you may want to use something else).
|
||||
*
|
||||
* @return mixed The value of the requested setting, or `$default`
|
||||
* @since 4.1
|
||||
*/
|
||||
function wpml_get_setting( $key, $default = null ) {
|
||||
global $sitepress_settings;
|
||||
$sitepress_settings = isset( $sitepress_settings ) ? $sitepress_settings : get_option( 'icl_sitepress_settings' );
|
||||
|
||||
return isset( $sitepress_settings[ $key ] ) ? $sitepress_settings[ $key ] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a WPML setting value.
|
||||
* If the Main SitePress Class cannot be access to the function will read the setting from the database.
|
||||
* Will return false if the requested key is not set or.
|
||||
* the default value passed in the function's second parameter.
|
||||
*
|
||||
* @param mixed|false $default Required. The value to return if the settings key does not exist
|
||||
* (typically it's false, but you may want to use something else).
|
||||
* @param string $key The setting's key.
|
||||
*
|
||||
* @return mixed The value of the requested setting, or $default
|
||||
* @since 3.2
|
||||
* @uses \SitePress::api_hooks
|
||||
*/
|
||||
function wpml_get_setting_filter( $default, $key ) {
|
||||
$args = func_get_args();
|
||||
if ( count( $args ) > 2 && $args[2] !== null ) {
|
||||
$default = $args[2];
|
||||
}
|
||||
|
||||
return wpml_get_setting( $key, $default );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of a given key sub-setting.
|
||||
*
|
||||
* @param string $key The setting's key.
|
||||
* @param string $sub_key The settings name key to return the value of.
|
||||
* @param mixed|false $default Required. The value to return if the settings key does not exist
|
||||
* (typically it's false, but you may want to use something else).
|
||||
*
|
||||
* @return bool|mixed
|
||||
* @since 3.1
|
||||
* @deprecated 3.2 use 'wpml_sub_setting' filter instead
|
||||
*/
|
||||
function icl_get_sub_setting( $key, $sub_key, $default = false ) {
|
||||
$parent = icl_get_setting( $key, array() );
|
||||
|
||||
return isset( $parent[ $sub_key ] ) ? $parent[ $sub_key ] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a WPML sub setting value.
|
||||
*
|
||||
* @param mixed|false $default Required. The value to return if the settings key does not exist
|
||||
* (typically it's false, but you may want to use something else).
|
||||
* @param string $key The settings name key the sub key belongs to.
|
||||
* @param string $sub_key The sub key to return the value of.
|
||||
* @param mixed $deprecated Deprecated param.
|
||||
*
|
||||
* @return mixed The value of the requested setting, or $default
|
||||
* @todo [WPML 3.3] Remove deprecated argument
|
||||
*
|
||||
* @uses \wpml_get_setting_filter
|
||||
*
|
||||
* @since 3.2
|
||||
* @uses \SitePress::api_hooks
|
||||
*/
|
||||
function wpml_get_sub_setting_filter( $default, $key, $sub_key, $deprecated = null ) {
|
||||
$default = null !== $deprecated && ! $default ? $deprecated : $default;
|
||||
|
||||
$parent = wpml_get_setting_filter( array(), $key );
|
||||
|
||||
return isset( $parent[ $sub_key ] ) ? $parent[ $sub_key ] : $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the value of a given key.
|
||||
*
|
||||
* @param string $key The settings name key the sub key belongs to.
|
||||
* @param mixed $value The value to assign to the given key.
|
||||
* @param bool $save_now Must call icl_save_settings() to permanently store the value.
|
||||
*
|
||||
* @return bool Always True. If `$save_now === true`, it returns the result of `update_option`
|
||||
*/
|
||||
function icl_set_setting( $key, $value, $save_now = false ) {
|
||||
global $sitepress_settings;
|
||||
|
||||
$result = true;
|
||||
|
||||
$sitepress_settings[ $key ] = $value;
|
||||
|
||||
if ( true === $save_now ) {
|
||||
/* We need to save settings anyway, in this case. */
|
||||
$result = update_option( 'icl_sitepress_settings', $sitepress_settings );
|
||||
do_action( 'icl_save_settings', $sitepress_settings );
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the settings in the db.
|
||||
*/
|
||||
function icl_save_settings() {
|
||||
global $sitepress;
|
||||
$sitepress->save_settings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the settings.
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
function icl_get_settings() {
|
||||
global $sitepress;
|
||||
|
||||
return isset( $sitepress ) ? $sitepress->get_settings() : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add settings link to plugin page.
|
||||
*
|
||||
* @param SitePress $sitepress
|
||||
* @param array<string> $links
|
||||
* @param string $file
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function icl_plugin_action_links( SitePress $sitepress, $links, $file ) {
|
||||
if ( $file == WPML_PLUGIN_BASENAME ) {
|
||||
$endpoint = $sitepress->is_setup_complete() ? 'languages.php' : 'setup.php';
|
||||
$links[] = '<a href="admin.php?page=' . WPML_PLUGIN_FOLDER . '/menu/' . $endpoint . '">' . __( 'Configure', 'sitepress' ) . '</a>';
|
||||
}
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
if ( defined( 'ICL_DEBUG_MODE' ) && ICL_DEBUG_MODE ) {
|
||||
add_action( 'admin_notices', '_icl_deprecated_icl_debug_mode' );
|
||||
}
|
||||
|
||||
function _icl_deprecated_icl_debug_mode() {
|
||||
echo '<div class="updated"><p><strong>ICL_DEBUG_MODE</strong> no longer supported. Please use <strong>WP_DEBUG</strong> instead.</p></div>';
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'icl_js_escape' ) ) {
|
||||
function icl_js_escape( $str ) {
|
||||
$str = esc_js( $str );
|
||||
$str = htmlspecialchars_decode( $str );
|
||||
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and, if needed, generate the site ID based on the scope.
|
||||
*
|
||||
* @param string $scope Defaults to "global".
|
||||
* Use a different value when the ID is used for specific scopes.
|
||||
*
|
||||
* @param bool $create_new Forces the creation of a new ID.
|
||||
*
|
||||
* @return string|null The generated/stored ID or null if it wasn't possible to generate/store the value.
|
||||
*/
|
||||
function wpml_get_site_id( $scope = WPML_Site_ID::SITE_SCOPES_GLOBAL, $create_new = false ) {
|
||||
static $site_id;
|
||||
|
||||
if ( ! $site_id ) {
|
||||
$site_id = new WPML_Site_ID();
|
||||
}
|
||||
|
||||
return $site_id->get_site_id( $scope, $create_new );
|
||||
}
|
||||
|
||||
function _icl_tax_has_objects_recursive( $id, $term_id = -1, $rec = 0 ) {
|
||||
// based on the case where two categories were one the parent of another
|
||||
// eliminating the chance of infinite loops by letting this function calling itself too many times
|
||||
// 100 is the default limit in most of teh php configuration
|
||||
//
|
||||
// this limit this function to work only with categories nested up to 60 levels
|
||||
// should enough for most cases
|
||||
if ( $rec > 60 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
|
||||
if ( $term_id === -1 ) {
|
||||
$term_id = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM {$wpdb->term_taxonomy} WHERE term_taxonomy_id=%d", $id ) );
|
||||
}
|
||||
|
||||
$children = $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
"
|
||||
SELECT term_taxonomy_id, term_id, count FROM {$wpdb->term_taxonomy} WHERE parent = %d
|
||||
",
|
||||
$term_id
|
||||
)
|
||||
);
|
||||
|
||||
$count = 0;
|
||||
foreach ( $children as $ch ) {
|
||||
$count += $ch->count;
|
||||
}
|
||||
|
||||
if ( $count ) {
|
||||
return true;
|
||||
} else {
|
||||
foreach ( $children as $ch ) {
|
||||
if ( _icl_tax_has_objects_recursive( $ch->term_taxonomy_id, $ch->term_id, $rec + 1 ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function _icl_trash_restore_prompt() {
|
||||
if ( isset( $_GET['lang'] ) ) {
|
||||
$post = get_post( intval( $_GET['post'] ) );
|
||||
if ( isset( $post->post_status ) && $post->post_status == 'trash' ) {
|
||||
$post_type_object = get_post_type_object( $post->post_type );
|
||||
|
||||
$delete_post_link = '<a href="' . esc_url( get_delete_post_link( $post->ID, '', true ) ) . '">' . esc_html__( 'delete it permanently', 'sitepress' ) . '</a>';
|
||||
$restore_post_link = '<a href="' . wp_nonce_url( admin_url( sprintf( $post_type_object->_edit_link . '&action=untrash', $post->ID ) ), 'untrash-post_' . $post->ID ) . '">' . esc_html__( 'restore', 'sitepress' ) . '</a>';
|
||||
$ret = '<p>' . sprintf( esc_html__( 'This translation is currently in the trash. You need to either %1$s or %2$s it in order to continue.' ), $delete_post_link, $restore_post_link );
|
||||
|
||||
wp_die( $ret );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build or update duplicated posts from a master post.
|
||||
*
|
||||
* @param string $master_post_id The ID of the post to duplicate from. Master post doesn't need to be in the default language.
|
||||
*
|
||||
* @uses SitePress
|
||||
* @uses TranslationManagement
|
||||
* @since unknown
|
||||
* @deprecated 3.2 use 'wpml_admin_make_duplicates' action instead
|
||||
*/
|
||||
function icl_makes_duplicates( $master_post_id ) {
|
||||
wpml_admin_make_post_duplicates_action( $master_post_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Build or update duplicated posts from a master post.
|
||||
* To be used only for admin backend actions
|
||||
*
|
||||
* @param int $master_post_id The ID of the post to duplicate from.
|
||||
* The ID can be that of a post, page or custom post
|
||||
* Master post doesn't need to be in the default language.
|
||||
*
|
||||
* @see $iclTranslationManagement in \SitePress:: __construct
|
||||
*
|
||||
* @uses SitePress
|
||||
* @uses TranslationManagement
|
||||
* @since 3.2
|
||||
* @uses \SitePress::api_hooks
|
||||
*/
|
||||
function wpml_admin_make_post_duplicates_action( $master_post_id ) {
|
||||
$post = get_post( $master_post_id );
|
||||
$post_type = $post->post_type;
|
||||
|
||||
if ( $post->post_status == 'auto-draft' || $post->post_type == 'revision' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
global $sitepress;
|
||||
$iclTranslationManagement = wpml_load_core_tm();
|
||||
if ( $sitepress->is_translated_post_type( $post_type ) ) {
|
||||
$iclTranslationManagement->make_duplicates_all( $master_post_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build duplicated posts from a master post only in case of the duplicate not being present at the time.
|
||||
*
|
||||
* @param string $master_post_id The ID of the post to duplicate from. Master post doesn't need to be in the default language.
|
||||
*
|
||||
* @uses SitePress
|
||||
* @since unknown
|
||||
* @deprecated 3.2 use 'wpml_make_post_duplicates' action instead
|
||||
*/
|
||||
function icl_makes_duplicates_public( $master_post_id ) {
|
||||
wpml_make_post_duplicates_action( $master_post_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Build duplicated posts from a master post only in case of the duplicate not being present at the time.
|
||||
*
|
||||
* @param int $master_post_id The ID of the post to duplicate from.
|
||||
* Master post doesn't need to be in the default language.
|
||||
*
|
||||
* @uses SitePress
|
||||
* @since 3.2
|
||||
* @uses \SitePress::api_hooks
|
||||
*/
|
||||
function wpml_make_post_duplicates_action( $master_post_id ) {
|
||||
|
||||
global $sitepress;
|
||||
|
||||
$master_post = get_post( $master_post_id );
|
||||
|
||||
if ( 'auto-draft' === $master_post->post_status || 'revision' === $master_post->post_type ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$active_langs = $sitepress->get_active_languages();
|
||||
|
||||
foreach ( $active_langs as $lang_to => $one ) {
|
||||
|
||||
$trid = $sitepress->get_element_trid( $master_post->ID, 'post_' . $master_post->post_type );
|
||||
$lang_from = $sitepress->get_source_language_by_trid( $trid );
|
||||
|
||||
if ( $lang_from == $lang_to ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$sitepress->make_duplicate( $master_post_id, $lang_to );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper function for deprecated like_escape() and recommended wpdb::esc_like()
|
||||
*
|
||||
* @global wpdb $wpdb
|
||||
*
|
||||
* @param string $text
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function wpml_like_escape( $text ) {
|
||||
global $wpdb;
|
||||
|
||||
if ( method_exists( $wpdb, 'esc_like' ) ) {
|
||||
return $wpdb->esc_like( $text );
|
||||
}
|
||||
|
||||
/** @noinspection PhpDeprecationInspection */
|
||||
|
||||
return like_escape( $text );
|
||||
}
|
||||
|
||||
function icl_do_not_promote() {
|
||||
return defined( 'ICL_DONT_PROMOTE' ) && ICL_DONT_PROMOTE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $time
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function icl_convert_to_user_time( $time ) {
|
||||
|
||||
// offset between server time and user time in seconds
|
||||
$time_offset = get_option( 'gmt_offset' ) * 3600;
|
||||
$local_time = __( 'Last Update Time could not be determined', 'sitepress' );
|
||||
|
||||
try {
|
||||
// unix time stamp in server time
|
||||
$creation_time = strtotime( $time );
|
||||
// creating dates before 2014 are impossible
|
||||
if ( $creation_time !== false ) {
|
||||
$local_time = date( 'Y-m-d H:i:s', $creation_time + $time_offset );
|
||||
}
|
||||
} catch ( Exception $e ) {
|
||||
// Ignoring the exception, as we already set the default value in $local_time
|
||||
}
|
||||
|
||||
return $local_time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if given language is activated
|
||||
*
|
||||
* @global sitepress $sitepress
|
||||
*
|
||||
* @param string $language 2 letters language code
|
||||
*
|
||||
* @return boolean
|
||||
* @since unknown
|
||||
* @deprecated 3.2 use 'wpml_language_is_active' filter instead
|
||||
*/
|
||||
function icl_is_language_active( $language ) {
|
||||
global $sitepress;
|
||||
|
||||
$active_languages = $sitepress->get_active_languages();
|
||||
|
||||
return isset( $active_languages[ $language ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if given language is enabled
|
||||
*
|
||||
* @param mixed $empty_value This is normally the value the filter will be modifying.
|
||||
* We are not filtering anything here therefore the NULL value
|
||||
* This for the filter function to actually receive the full argument list:
|
||||
* apply_filters('wpml_language_is_active', '', $language_code);
|
||||
* @param string $language_code The language code to check Accepts a 2-letter language code
|
||||
*
|
||||
* @return boolean
|
||||
* @global sitepress $sitepress
|
||||
*
|
||||
* @since 3.2
|
||||
* @uses \SitePress::api_hooks
|
||||
*/
|
||||
function wpml_language_is_active_filter( $empty_value, $language_code ) {
|
||||
global $sitepress;
|
||||
|
||||
return $sitepress->is_active_language( $language_code );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url url either with or without schema
|
||||
* Removes the subdirectory in which WordPress is installed from a url.
|
||||
* If WordPress is not installed in a subdirectory, then the input is returned unaltered.
|
||||
*
|
||||
* @return string the url input without the blog's subdirectory. Potentially existing schemata on the input are kept intact.
|
||||
*/
|
||||
function wpml_strip_subdir_from_url( $url ) {
|
||||
/** @var WPML_URL_Converter $wpml_url_converter */
|
||||
global $wpml_url_converter;
|
||||
|
||||
$subdir = wpml_parse_url( $wpml_url_converter->get_abs_home(), PHP_URL_PATH );
|
||||
$subdir_slugs = ! empty( $subdir ) ? array_values( array_filter( explode( '/', $subdir ) ) ) : [''];
|
||||
|
||||
$url_path_expl = explode( '/', preg_replace( '#^(http|https)://#', '', $url ) );
|
||||
array_shift( $url_path_expl );
|
||||
$url_slugs = array_values( array_filter( $url_path_expl ) );
|
||||
$url_slugs_before = $url_slugs;
|
||||
$url_slugs = array_diff_assoc( $url_slugs, $subdir_slugs );
|
||||
$url = str_replace( '/' . join( '/', $url_slugs_before ), '/' . join( '/', $url_slugs ), $url );
|
||||
|
||||
return untrailingslashit( $url );
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes array of items into string of items, separated by comma and sql-escaped
|
||||
*
|
||||
* @see https://coderwall.com/p/zepnaw
|
||||
* @global wpdb $wpdb
|
||||
*
|
||||
* @param mixed|array $items item(s) to be joined into string
|
||||
* @param string $format %s or %d
|
||||
*
|
||||
* @return string Items separated by comma and sql-escaped
|
||||
*/
|
||||
function wpml_prepare_in( $items, $format = '%s' ) {
|
||||
global $wpdb;
|
||||
|
||||
$items = (array) $items;
|
||||
$how_many = count( $items );
|
||||
if ( $how_many > 0 ) {
|
||||
$placeholders = array_fill( 0, $how_many, $format );
|
||||
$prepared_format = implode( ',', $placeholders );
|
||||
$prepared_in = $wpdb->prepare( $prepared_format, $items );
|
||||
} else {
|
||||
$prepared_in = '';
|
||||
}
|
||||
|
||||
return $prepared_in;
|
||||
}
|
||||
|
||||
function is_not_installing_plugins() {
|
||||
global $sitepress;
|
||||
|
||||
$checked = isset( $_REQUEST['checked'] ) ? (array) $_REQUEST['checked'] : array();
|
||||
|
||||
if ( ! isset( $_REQUEST['action'] ) ) {
|
||||
return true;
|
||||
} elseif ( $_REQUEST['action'] != 'activate' && $_REQUEST['action'] != 'activate-selected' ) {
|
||||
return true;
|
||||
} elseif ( ( ! isset( $_REQUEST['plugin'] ) || $_REQUEST['plugin'] != WPML_PLUGIN_FOLDER . '/' . basename( __FILE__ ) ) && ! in_array( WPML_PLUGIN_FOLDER . '/' . basename( __FILE__ ), $checked ) ) {
|
||||
return true;
|
||||
} elseif ( in_array( WPML_PLUGIN_FOLDER . '/' . basename( __FILE__ ), $checked ) && ! isset( $sitepress ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function wpml_mb_strtolower( $string ) {
|
||||
if ( function_exists( 'mb_strtolower' ) ) {
|
||||
return mb_strtolower( $string );
|
||||
}
|
||||
|
||||
return strtolower( $string );
|
||||
}
|
||||
|
||||
function wpml_mb_strpos( $haystack, $needle, $offset = 0 ) {
|
||||
if ( function_exists( 'mb_strpos' ) ) {
|
||||
return mb_strpos( $haystack, $needle, $offset );
|
||||
}
|
||||
|
||||
return strpos( $haystack, $needle, $offset );
|
||||
}
|
||||
|
||||
function wpml_set_plugin_as_inactive() {
|
||||
global $icl_plugin_inactive;
|
||||
if ( ! defined( 'ICL_PLUGIN_INACTIVE' ) ) {
|
||||
define( 'ICL_PLUGIN_INACTIVE', true );
|
||||
}
|
||||
$icl_plugin_inactive = true;
|
||||
}
|
||||
|
||||
function wpml_version_is( $version_to_check, $comparison = '==' ) {
|
||||
return version_compare( ICL_SITEPRESS_VERSION, $version_to_check, $comparison ) && function_exists( 'wpml_site_uses_icl' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Interrupts the plugin activation process if the WPML Core Plugin could not be activated
|
||||
*/
|
||||
function icl_suppress_activation() {
|
||||
$active_plugins = get_option( 'active_plugins' );
|
||||
$icl_sitepress_idx = array_search( WPML_PLUGIN_BASENAME, $active_plugins );
|
||||
if ( false !== $icl_sitepress_idx ) {
|
||||
unset( $active_plugins[ $icl_sitepress_idx ] );
|
||||
update_option( 'active_plugins', $active_plugins );
|
||||
unset( $_GET['activate'] );
|
||||
$recently_activated = get_option( 'recently_activated' );
|
||||
if ( ! isset( $recently_activated[ WPML_PLUGIN_BASENAME ] ) ) {
|
||||
$recently_activated[ WPML_PLUGIN_BASENAME ] = time();
|
||||
update_option( 'recently_activated', $recently_activated );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param SitePress $sitepress
|
||||
*/
|
||||
function activate_installer( $sitepress = null ) {
|
||||
// installer hook - start
|
||||
include_once WPML_PLUGIN_PATH . '/vendor/otgs/installer/loader.php'; // produces global variable $wp_installer_instance
|
||||
$args = array(
|
||||
'plugins_install_tab' => 1,
|
||||
);
|
||||
|
||||
if ( $sitepress ) {
|
||||
$args['site_key_nags'] = array(
|
||||
array(
|
||||
'repository_id' => 'wpml',
|
||||
'product_name' => 'WPML',
|
||||
'condition_cb' => array( $sitepress, 'setup' ),
|
||||
),
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @var WP_Installer $wp_installer_instance
|
||||
*/
|
||||
/** @phpstan-ignore-next-line */
|
||||
WP_Installer_Setup( $wp_installer_instance, $args );
|
||||
// installer hook - end
|
||||
}
|
||||
|
||||
function wpml_missing_filter_input_notice() {
|
||||
?>
|
||||
<div class="message error">
|
||||
<h3><?php esc_html_e( "WPML can't be functional because it requires a disabled PHP extension!", 'sitepress' ); ?></h3>
|
||||
|
||||
<p><?php esc_html_e( 'To ensure and improve the security of your website, WPML makes use of the ', 'sitepress' ); ?><a href="http://php.net/manual/en/book.filter.php">PHP Data Filtering</a> extension.<br><br>
|
||||
<?php
|
||||
esc_html_e(
|
||||
'The filter extension is enabled by default as of PHP 5.2.0. Before this time an experimental PECL extension was
|
||||
used, however, the PECL version is no longer recommended to be used or updated. (source: ',
|
||||
'sitepress'
|
||||
);
|
||||
?>
|
||||
<a href="http://php.net/manual/en/filter.installation.php">PHP Manual Function Reference Variable and
|
||||
Type Related Extensions Filter
|
||||
Installing/Configuring</a>)<br>
|
||||
<br>
|
||||
<?php esc_html_e( 'The filter extension is enabled by default as of PHP 5.2, therefore it must have been disabled by either you or your host.', 'sitepress' ); ?>
|
||||
<br><?php esc_html_e( "To enable it, either you or your host will need to open your website's php.ini file and either:", 'sitepress' ); ?><br>
|
||||
<ol>
|
||||
<li><?php esc_html_e( "Remove the 'filter_var' string from the 'disable_functions' directive or...", 'sitepress' ); ?>
|
||||
</li>
|
||||
<li><?php esc_html_e( 'Add the following line:', 'sitepress' ); ?> <code class="inline-code">extension=filter.so</code></li>
|
||||
</ol>
|
||||
<?php
|
||||
$ini_location = php_ini_loaded_file();
|
||||
if ( $ini_location !== false ) {
|
||||
?>
|
||||
<strong><?php esc_html_e( 'Your php.ini file is located at', 'sitepress' ) . ' ' . esc_html( $ini_location ); ?>.</strong>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
function repair_el_type_collate() {
|
||||
global $wpdb;
|
||||
|
||||
$correct_collate = $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
"SELECT collation_name
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_NAME = '%s'
|
||||
AND COLUMN_NAME = 'post_type'
|
||||
AND table_schema = (SELECT DATABASE())
|
||||
LIMIT 1",
|
||||
$wpdb->posts
|
||||
)
|
||||
);
|
||||
|
||||
// translations
|
||||
$table_name = $wpdb->prefix . 'icl_translations';
|
||||
$sql = $wpdb->prepare(
|
||||
"ALTER TABLE `$table_name` CHANGE `element_type` `element_type` VARCHAR( 36 ) NOT NULL DEFAULT 'post_post' COLLATE %s",
|
||||
$correct_collate
|
||||
);
|
||||
|
||||
if ( $wpdb->query( $sql ) === false ) {
|
||||
throw new Exception( $wpdb->last_error );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for `parse_url` using `wp_parse_url`
|
||||
*
|
||||
* @param string $url
|
||||
* @param int $component
|
||||
*
|
||||
* @return array|string|int|null
|
||||
*/
|
||||
function wpml_parse_url( $url, $component = -1 ) {
|
||||
$ret = null;
|
||||
|
||||
$component_map = array(
|
||||
PHP_URL_SCHEME => 'scheme',
|
||||
PHP_URL_HOST => 'host',
|
||||
PHP_URL_PORT => 'port',
|
||||
PHP_URL_USER => 'user',
|
||||
PHP_URL_PASS => 'pass',
|
||||
PHP_URL_PATH => 'path',
|
||||
PHP_URL_QUERY => 'query',
|
||||
PHP_URL_FRAGMENT => 'fragment',
|
||||
);
|
||||
|
||||
if ( $component === -1 ) {
|
||||
$ret = wp_parse_url( $url );
|
||||
} elseif ( isset( $component_map[ $component ] ) ) {
|
||||
$key = $component_map[ $component ];
|
||||
$parsed = wp_parse_url( $url );
|
||||
$ret = isset( $parsed[ $key ] ) ? $parsed[ $key ] : null;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper function to prevent ampersand to be encoded (depending on some PHP versions)
|
||||
*
|
||||
* @link http://php.net/manual/en/function.http-build-query.php#102324
|
||||
*
|
||||
* @param array|object $query_data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function wpml_http_build_query( $query_data ) {
|
||||
return http_build_query( $query_data, '', '&' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $array
|
||||
* @param int $sort_flags
|
||||
*
|
||||
* @uses \wpml_array_unique_fallback
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function wpml_array_unique( $array, $sort_flags = SORT_REGULAR ) {
|
||||
if ( version_compare( phpversion(), '5.2.9', '>=' ) ) {
|
||||
// phpcs:disable PHPCompatibility.FunctionUse.NewFunctionParameters.array_unique_sort_flagsFound -- This statement is preceded by a version check
|
||||
return array_unique( $array, $sort_flags );
|
||||
// phpcs:enable PHPCompatibility.FunctionUse.NewFunctionParameters.array_unique_sort_flagsFound
|
||||
}
|
||||
|
||||
return wpml_array_unique_fallback( $array, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<mixed> $array
|
||||
* @param bool $keep_key_assoc
|
||||
*
|
||||
* @return array
|
||||
* @see \wpml_array_unique
|
||||
*/
|
||||
function wpml_array_unique_fallback( $array, $keep_key_assoc ) {
|
||||
$duplicate_keys = array();
|
||||
$tmp = array();
|
||||
|
||||
foreach ( $array as $key => $val ) {
|
||||
// convert objects to arrays, in_array() does not support objects
|
||||
if ( is_object( $val ) ) {
|
||||
$val = (array) $val;
|
||||
}
|
||||
|
||||
if ( ! in_array( $val, $tmp ) ) {
|
||||
$tmp[] = $val;
|
||||
} else {
|
||||
$duplicate_keys[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $duplicate_keys as $key ) {
|
||||
unset( $array[ $key ] );
|
||||
}
|
||||
|
||||
return $keep_key_assoc ? $array : array_values( $array );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
function wpml_is_rest_request() {
|
||||
return make( WPML_REST_Request_Analyze::class )->is_rest_request();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
function wpml_is_rest_enabled() {
|
||||
return make( \WPML\Core\REST\Status::class )->isEnabled();
|
||||
}
|
||||
|
||||
function wpml_is_cli() {
|
||||
return defined( 'WP_CLI' ) && WP_CLI;
|
||||
}
|
||||
|
||||
function wpml_sticky_post_sync( SitePress $sitepress = null ) {
|
||||
static $instance;
|
||||
|
||||
if ( ! $instance ) {
|
||||
global $wpml_post_translations;
|
||||
|
||||
if ( ! $sitepress ) {
|
||||
global $sitepress;
|
||||
}
|
||||
|
||||
$instance = new WPML_Sticky_Posts_Sync(
|
||||
$sitepress,
|
||||
$wpml_post_translations,
|
||||
new WPML_Sticky_Posts_Lang_Filter(
|
||||
$sitepress,
|
||||
$wpml_post_translations
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WP_Filesystem_Direct
|
||||
*/
|
||||
function wpml_get_filesystem_direct() {
|
||||
static $instance;
|
||||
|
||||
if ( ! $instance ) {
|
||||
$wp_api = new WPML_WP_API();
|
||||
$instance = $wp_api->get_wp_filesystem_direct();
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $postarray It will be escaped inside the function
|
||||
* @param string|null $lang
|
||||
* @param bool $wp_error
|
||||
*
|
||||
* @return int|\WP_Error
|
||||
*/
|
||||
function wpml_update_escaped_post( array $postarray, $lang = null, $wp_error = false ) {
|
||||
return wpml_get_create_post_helper()->insert_post( $postarray, $lang, $wp_error );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $group
|
||||
*
|
||||
* @return WPML_WP_Cache
|
||||
*/
|
||||
function wpml_get_cache( $group = '' ) {
|
||||
return new WPML_WP_Cache( $group );
|
||||
}
|
||||
|
||||
|
||||
if ( ! function_exists( 'wpml_is_ajax' ) ) {
|
||||
/**
|
||||
* wpml_is_ajax - Returns true when the page is loaded via ajax.
|
||||
*
|
||||
* @since 3.1.5
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function wpml_is_ajax() {
|
||||
if ( defined( 'DOING_AJAX' ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return ( isset( $_SERVER['HTTP_X_REQUESTED_WITH'] ) && wpml_mb_strtolower( $_SERVER['HTTP_X_REQUESTED_WITH'] ) == 'xmlhttprequest' ) ? true : false;
|
||||
}
|
||||
}
|
||||
30
wp-content/plugins/sitepress-multilingual-cms/inc/hacks.php
Normal file
30
wp-content/plugins/sitepress-multilingual-cms/inc/hacks.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
// using this file to handle particular situations that would involve more ellaborate solutions
|
||||
|
||||
add_action( 'init', 'icl_load_hacks' );
|
||||
|
||||
function icl_dev_mode_warning() {
|
||||
?>
|
||||
<div class="error message">
|
||||
<p>This is a development version of WPML, provided for evaluation purposes only. The code you are using did not
|
||||
go through any testing or QA. Do not use it in production sites.</strong></p>
|
||||
<p>To obtain production versions of WPML, visit: <a href="https://wpml.org">wpml.org</a>.</p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
function icl_load_hacks() {
|
||||
if ( file_exists( WPML_PLUGIN_PATH . '/inc/hacks/misc-constants.php' ) ) {
|
||||
include WPML_PLUGIN_PATH . '/inc/hacks/misc-constants.php';
|
||||
}
|
||||
include WPML_PLUGIN_PATH . '/inc/hacks/language-canonical-redirects.php';
|
||||
|
||||
if ( is_admin() && ! defined( 'ICL_PRODUCTION_MODE' ) ) {
|
||||
add_action( 'admin_notices', 'icl_dev_mode_warning' );
|
||||
icl_dev_mode_warning();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
require WPML_PLUGIN_PATH . '/inc/hacks/missing-php-functions.php';
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
if ( defined( 'WP_ADMIN' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_action( 'template_redirect', 'icl_language_canonical_redirects', 1 );
|
||||
|
||||
function icl_language_canonical_redirects() {
|
||||
global $wp_query, $sitepress_settings;
|
||||
if ( 3 == $sitepress_settings['language_negotiation_type'] && is_singular() && empty( $wp_query->posts ) ) {
|
||||
$pid = get_query_var( 'p' );
|
||||
$permalink = html_entity_decode( get_permalink( $pid ) );
|
||||
if ( $permalink ) {
|
||||
wp_redirect( $permalink, 301 );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
define( 'ICL_PRODUCTION_MODE', '2.1.1' );
|
||||
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
|
||||
if ( ! function_exists( '_cleanup_header_comment' ) ) {
|
||||
function _cleanup_header_comment( $str ) {
|
||||
return trim( preg_replace( '/\s*(?:\*\/|\?>).*/', '', $str ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! defined( 'E_DEPRECATED' ) ) {
|
||||
define( 'E_DEPRECATED', 8192 ); }
|
||||
|
||||
if ( ! function_exists( 'esc_textarea' ) ) :
|
||||
|
||||
function esc_textarea( $text ) {
|
||||
$safe_text = esc_html( $text );
|
||||
return apply_filters( 'esc_textarea', $safe_text, $text );
|
||||
}
|
||||
|
||||
endif;
|
||||
|
||||
/**
|
||||
* This file is part of the array_column library
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*
|
||||
* @copyright Copyright (c) 2013 Ben Ramsey <http://benramsey.com>
|
||||
* @license http://opensource.org/licenses/MIT MIT
|
||||
*/
|
||||
|
||||
if ( ! function_exists( 'array_column' ) ) {
|
||||
|
||||
/**
|
||||
* Returns the values from a single column of the input array, identified by
|
||||
* the $columnKey.
|
||||
*
|
||||
* Optionally, you may provide an $indexKey to index the values in the returned
|
||||
* array by the values from the $indexKey column in the input array.
|
||||
*
|
||||
* @param array $input A multi-dimensional array (record set) from which to pull
|
||||
* a column of values.
|
||||
* @param mixed $columnKey The column of values to return. This value may be the
|
||||
* integer key of the column you wish to retrieve, or it
|
||||
* may be the string key name for an associative array.
|
||||
* @param mixed $indexKey (Optional.) The column to use as the index/keys for
|
||||
* the returned array. This value may be the integer key
|
||||
* of the column, or it may be the string key name.
|
||||
* @return array|false
|
||||
*/
|
||||
function array_column( $input = null, $columnKey = null, $indexKey = null ) {
|
||||
// Using func_get_args() in order to check for proper number of
|
||||
// parameters and trigger errors exactly as the built-in array_column()
|
||||
// does in PHP 5.5.
|
||||
$argc = func_num_args();
|
||||
$params = func_get_args();
|
||||
|
||||
if ( $argc < 2 ) {
|
||||
trigger_error( "array_column() expects at least 2 parameters, {$argc} given", E_USER_WARNING );
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( ! is_array( $params[0] ) ) {
|
||||
trigger_error( 'array_column() expects parameter 1 to be array, ' . gettype( $params[0] ) . ' given', E_USER_WARNING );
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( ! is_int( $params[1] )
|
||||
&& ! is_float( $params[1] )
|
||||
&& ! is_string( $params[1] )
|
||||
&& $params[1] !== null
|
||||
&& ! ( is_object( $params[1] ) && method_exists( $params[1], '__toString' ) )
|
||||
) {
|
||||
trigger_error( 'array_column(): The column key should be either a string or an integer', E_USER_WARNING );
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( isset( $params[2] )
|
||||
&& ! is_int( $params[2] )
|
||||
&& ! is_float( $params[2] )
|
||||
&& ! is_string( $params[2] )
|
||||
&& ! ( is_object( $params[2] ) && method_exists( $params[2], '__toString' ) )
|
||||
) {
|
||||
trigger_error( 'array_column(): The index key should be either a string or an integer', E_USER_WARNING );
|
||||
return false;
|
||||
}
|
||||
|
||||
$paramsInput = $params[0];
|
||||
$paramsColumnKey = ( $params[1] !== null ) ? (string) $params[1] : null;
|
||||
|
||||
$paramsIndexKey = null;
|
||||
if ( isset( $params[2] ) ) {
|
||||
if ( is_float( $params[2] ) || is_int( $params[2] ) ) {
|
||||
$paramsIndexKey = (int) $params[2];
|
||||
} else {
|
||||
$paramsIndexKey = (string) $params[2];
|
||||
}
|
||||
}
|
||||
|
||||
$resultArray = array();
|
||||
|
||||
foreach ( $paramsInput as $row ) {
|
||||
|
||||
$key = $value = null;
|
||||
$keySet = $valueSet = false;
|
||||
|
||||
if ( $paramsIndexKey !== null && array_key_exists( $paramsIndexKey, $row ) ) {
|
||||
$keySet = true;
|
||||
$key = (string) $row[ $paramsIndexKey ];
|
||||
}
|
||||
|
||||
if ( $paramsColumnKey === null ) {
|
||||
$valueSet = true;
|
||||
$value = $row;
|
||||
} elseif ( is_array( $row ) && array_key_exists( $paramsColumnKey, $row ) ) {
|
||||
$valueSet = true;
|
||||
$value = $row[ $paramsColumnKey ];
|
||||
}
|
||||
|
||||
if ( $valueSet ) {
|
||||
if ( $keySet ) {
|
||||
$resultArray[ $key ] = $value;
|
||||
} else {
|
||||
$resultArray[] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $resultArray;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'array_replace_recursive' ) ) {
|
||||
function array_replace_recursive( $array, $array1 ) {
|
||||
// handle the arguments, merge one by one
|
||||
$args = func_get_args();
|
||||
$array = $args[0];
|
||||
if ( ! is_array( $array ) ) {
|
||||
return $array;
|
||||
}
|
||||
$args_count = count( $args );
|
||||
for ( $i = 1; $i < $args_count; $i ++ ) {
|
||||
if ( is_array( $args[ $i ] ) ) {
|
||||
$array = array_replace_recursive_recurse( $array, $args[ $i ] );
|
||||
}
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
function array_replace_recursive_recurse( $array, $array1 ) {
|
||||
foreach ( $array1 as $key => $value ) {
|
||||
// create new key in $array, if it is empty or not an array
|
||||
if ( ! isset( $array[ $key ] ) || ( isset( $array[ $key ] ) && ! is_array( $array[ $key ] ) ) ) {
|
||||
$array[ $key ] = array();
|
||||
}
|
||||
|
||||
// overwrite the value in the base array
|
||||
if ( is_array( $value ) ) {
|
||||
$value = array_replace_recursive_recurse( $array[ $key ], $value );
|
||||
}
|
||||
$array[ $key ] = $value;
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
/*
|
||||
$_pingback_url_parts = parse_url(get_bloginfo('pingback_url'));
|
||||
if($_SERVER['REQUEST_URI'] == $_pingback_url_parts['path']){
|
||||
function __icl_void_error_handler($errno, $errstr, $errfile, $errline){
|
||||
throw new Exception ($errstr . ' [' . $errno . '] in '. $errfile . ':' . $errline);
|
||||
}
|
||||
set_error_handler('__icl_void_error_handler',E_ALL);
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
global $PHP_SELF;
|
||||
if ( is_admin() ) {
|
||||
// wp-admin pages are checked more carefully
|
||||
if ( is_network_admin() ) {
|
||||
preg_match( '#/wp-admin/network/?(.*?)$#i', $PHP_SELF, $self_matches );
|
||||
} elseif ( is_user_admin() ) {
|
||||
preg_match( '#/wp-admin/user/?(.*?)$#i', $PHP_SELF, $self_matches );
|
||||
} else {
|
||||
preg_match( '#/wp-admin/?(.*?)$#i', $PHP_SELF, $self_matches );
|
||||
}
|
||||
$pagenow = $self_matches[1];
|
||||
$pagenow = trim( $pagenow, '/' );
|
||||
$pagenow = preg_replace( '#\?.*?$#', '', $pagenow );
|
||||
if ( '' === $pagenow || 'index' === $pagenow || 'index.php' === $pagenow ) {
|
||||
$pagenow = 'index.php';
|
||||
} else {
|
||||
preg_match( '#(.*?)(/|$)#', $pagenow, $self_matches );
|
||||
$pagenow = strtolower( $self_matches[1] );
|
||||
if ( '.php' !== substr( $pagenow, -4, 4 ) ) {
|
||||
$pagenow .= '.php'; // for Options +Multiviews: /wp-admin/themes/index.php (themes.php is queried)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ( preg_match( '#([^/]+\.php)([?/].*?)?$#i', $PHP_SELF, $self_matches ) ) {
|
||||
$pagenow = strtolower( $self_matches[1] );
|
||||
} else {
|
||||
$pagenow = 'index.php';
|
||||
}
|
||||
}
|
||||
unset( $self_matches );
|
||||
|
||||
@@ -0,0 +1,814 @@
|
||||
<?php
|
||||
/**
|
||||
* @package wpml-core
|
||||
*/
|
||||
|
||||
/**
|
||||
* Admin Notifier Class
|
||||
*
|
||||
* Manages Admin Notices
|
||||
*/
|
||||
|
||||
add_action( 'init', array( 'ICL_AdminNotifier', 'init' ) );
|
||||
|
||||
if ( ! class_exists( 'ICL_AdminNotifier' ) ) {
|
||||
class ICL_AdminNotifier {
|
||||
public static function init() {
|
||||
if ( is_admin() ) {
|
||||
add_action( 'wp_ajax_icl-hide-admin-message', array( __CLASS__, 'hide_message' ) );
|
||||
add_action( 'wp_ajax_icl-show-admin-message', array( __CLASS__, 'show_message' ) );
|
||||
if ( ! defined( 'DOING_AJAX' ) ) {
|
||||
add_action( 'admin_enqueue_scripts', array( __CLASS__, 'add_script' ) );
|
||||
|
||||
add_action( 'admin_notices', array( __CLASS__, 'admin_notices' ) );
|
||||
}
|
||||
|
||||
add_filter( 'troubleshooting_js_data', array( __CLASS__, 'troubleshooting_js_data' ) );
|
||||
add_action( 'wpml_troubleshooting_cleanup', array( __CLASS__, 'troubleshooting' ) );
|
||||
add_action( 'wp_ajax_icl_restore_notifications', array( __CLASS__, 'restore_notifications' ) );
|
||||
add_action( 'wp_ajax_icl_remove_notifications', array( __CLASS__, 'remove_notifications' ) );
|
||||
}
|
||||
}
|
||||
|
||||
public static function add_script() {
|
||||
wp_enqueue_script( 'icl-admin-notifier', ICL_PLUGIN_URL . '/res/js/icl-admin-notifier.js', array( 'jquery' ), ICL_SITEPRESS_VERSION );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param string $type
|
||||
*/
|
||||
public static function add_instant_message( $message, $type = '' ) {
|
||||
$messages = self::get_messages();
|
||||
$messages['instant_messages'][] = array(
|
||||
'text' => $message,
|
||||
'type' => $type,
|
||||
);
|
||||
self::save_messages( $messages );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $message_id
|
||||
*
|
||||
* @return bool|array
|
||||
*/
|
||||
public static function get_message( $message_id ) {
|
||||
$messages = self::get_messages();
|
||||
|
||||
return isset( $messages['messages'][ $message_id ] ) ? $messages['messages'][ $message_id ] : false;
|
||||
}
|
||||
|
||||
public static function message_id_exists( $message_id ) {
|
||||
$message = self::get_message( $message_id );
|
||||
|
||||
return $message !== false;
|
||||
}
|
||||
|
||||
private static function get_messages() {
|
||||
$messages = get_option( 'icl_admin_messages' );
|
||||
if ( ! ( isset( $messages ) && $messages != false ) ) {
|
||||
return array(
|
||||
'messages' => array(),
|
||||
'instant_messages' => array(),
|
||||
);
|
||||
}
|
||||
if ( ! isset( $messages['messages'] ) || ! isset( $messages['instant_messages'] ) ) {
|
||||
$messages = array(
|
||||
'messages' => array(),
|
||||
'instant_messages' => array(),
|
||||
);
|
||||
}
|
||||
|
||||
return (array) $messages;
|
||||
}
|
||||
|
||||
private static function save_messages( $messages ) {
|
||||
if ( isset( $messages ) ) {
|
||||
update_option( 'icl_admin_messages', (array) $messages );
|
||||
}
|
||||
self::get_messages();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<mixed> $args
|
||||
* Args attributes:
|
||||
* string id - An unique identifier for the message
|
||||
* string msg - The actual message
|
||||
* string type (optional) - Any string: it will be used as css class fro the message container. A typical value is 'error', but the following strings can be also used: icl-admin-message-information, icl-admin-message-warning
|
||||
* array classes (optional) - Display the notice only on specific url(s)
|
||||
* bool hide (optional) - Enable the toggle link to permanently hide the notice
|
||||
* bool hide_per_user (optional) - Enable the toggle link per user basis (overrides hide option)
|
||||
* bool dismiss (optional) - Enable the dismiss option
|
||||
* bool dismiss_per_user (optional) - Enable the dismiss option per user basis (overrides dismiss option)
|
||||
* bool|string fallback_text (optional) - A message to show when the notice gets hidden
|
||||
* bool|string fallback_type (optional) - The message type to use in the fallback message (@see $type)
|
||||
* array fallback_classes (optional) - The message type to use in the fallback message (@see $type)
|
||||
* bool|string group (optional) - A way to group messages: when displaying messages stored with this method, it's possible to filter them by group (@see ICL_AdminNotifier::displayMessages)
|
||||
* bool admin_notice (optional) - Hook the rendering to the 'admin_notice' action
|
||||
* string|array limit_to_page (optional) - Display the notice only on specific page(s)
|
||||
*/
|
||||
public static function add_message( $args ) {
|
||||
$defaults = array(
|
||||
'type' => '',
|
||||
'classes' => array(),
|
||||
'hide' => false,
|
||||
'hide_per_user' => false,
|
||||
'dismiss' => false,
|
||||
'dismiss_per_user' => false,
|
||||
'fallback_text' => false,
|
||||
'fallback_type' => false,
|
||||
'fallback_classes' => array(),
|
||||
'group' => false,
|
||||
'admin_notice' => false,
|
||||
'hidden' => false,
|
||||
'dismissed' => false,
|
||||
'limit_to_page' => false,
|
||||
'show_once' => false,
|
||||
'capability' => '',
|
||||
);
|
||||
|
||||
$args = self::sanitize_message_args( $args );
|
||||
|
||||
$args = array_merge( $defaults, $args );
|
||||
|
||||
$id = $args['id'];
|
||||
|
||||
// Check if existing message has been set as dismissed or hidden
|
||||
if ( self::message_id_exists( $id ) ) {
|
||||
$temp_msg = self::get_message( $id );
|
||||
|
||||
if ( $temp_msg ) {
|
||||
$current_user_id = get_current_user_id();
|
||||
$message_user_data = isset( $temp_msg['users'][ $current_user_id ] ) ? $temp_msg['users'][ $current_user_id ] : false;
|
||||
|
||||
if ( self::is_user_dismissed( $temp_msg ) || self::is_globally_dismissed( $temp_msg ) || self::is_globally_hidden( $temp_msg ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( isset( $message_user_data['hidden'] ) ) {
|
||||
$args['hidden'] = $message_user_data['hidden'] ? false : $args['hidden'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$id = $id ? $id : md5( wp_json_encode( $args ) );
|
||||
$messages = self::get_messages();
|
||||
|
||||
$message = array(
|
||||
'id' => $id,
|
||||
'text' => $args['text'],
|
||||
'type' => $args['type'],
|
||||
'classes' => $args['classes'],
|
||||
'hide' => $args['hide'],
|
||||
'hide_per_user' => $args['hide_per_user'],
|
||||
'dismiss' => $args['dismiss'],
|
||||
'dismiss_per_user' => $args['dismiss_per_user'],
|
||||
'fallback_text' => $args['fallback_text'],
|
||||
'fallback_type' => $args['fallback_type'],
|
||||
'fallback_classes' => $args['classes'],
|
||||
'group' => $args['group'],
|
||||
'admin_notice' => $args['admin_notice'],
|
||||
'hidden' => false,
|
||||
'dismissed' => false,
|
||||
'limit_to_page' => $args['limit_to_page'],
|
||||
'show_once' => $args['show_once'],
|
||||
'capability' => $args['capability'],
|
||||
);
|
||||
|
||||
$message_md5 = md5( wp_json_encode( $message ) );
|
||||
|
||||
if ( isset( $messages['messages'][ $id ] ) ) {
|
||||
$existing_message_md5 = md5( wp_json_encode( $messages['messages'][ $id ] ) );
|
||||
if ( $message_md5 != $existing_message_md5 ) {
|
||||
unset( $messages['messages'][ $id ] );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! isset( $messages['messages'][ $id ] ) ) {
|
||||
$messages['messages'][ $id ] = $message;
|
||||
self::save_messages( $messages );
|
||||
}
|
||||
}
|
||||
|
||||
public static function is_user_dismissed( $message_data ) {
|
||||
$current_user_id = get_current_user_id();
|
||||
$message_user_data = isset( $message_data['users'][ $current_user_id ] ) ? $message_data['users'][ $current_user_id ] : false;
|
||||
|
||||
return ! empty( $message_data['dismiss_per_user'] ) && ! empty( $message_user_data['dismissed'] );
|
||||
}
|
||||
|
||||
public static function is_globally_dismissed( $message_data ) {
|
||||
return ! empty( $message_data['dismiss'] ) && $message_data['dismissed'];
|
||||
}
|
||||
|
||||
public static function is_globally_hidden( $message_data ) {
|
||||
return ! empty( $message_data['hide'] ) && $message_data['hidden'];
|
||||
}
|
||||
|
||||
public static function hide_message() {
|
||||
|
||||
$message_id = self::get_message_id();
|
||||
$dismiss = isset( $_POST['dismiss'] ) ? $_POST['dismiss'] : false;
|
||||
if ( ! self::message_id_exists( $message_id ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
self::set_message_display( $message_id, false, 'hide', 'hidden', 'hide_per_user' );
|
||||
|
||||
if ( $dismiss ) {
|
||||
self::set_message_display( $message_id, false, 'dismiss', 'dismissed', 'dismiss_per_user' );
|
||||
} else {
|
||||
$messages = self::get_messages();
|
||||
$message = $messages['messages'][ $message_id ];
|
||||
if ( $message && isset( $message['fallback_text'] ) && $message['fallback_text'] ) {
|
||||
echo self::display_message( $message_id, $message['fallback_text'], $message['fallback_type'], $message['fallback_classes'], false, false, true, true );
|
||||
}
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
public static function get_message_id() {
|
||||
$message_id = '';
|
||||
if ( isset( $_POST['icl-admin-message-id'] ) ) {
|
||||
$message_id = filter_var( $_POST['icl-admin-message-id'], FILTER_SANITIZE_FULL_SPECIAL_CHARS );
|
||||
}
|
||||
$message_id = $message_id ? $message_id : '';
|
||||
$message_id = preg_replace( '/^icl-id-/', '', $message_id );
|
||||
|
||||
return $message_id;
|
||||
}
|
||||
|
||||
public static function show_message() {
|
||||
$message_id = self::get_message_id();
|
||||
if ( ! self::message_id_exists( $message_id ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
self::set_message_display( $message_id, true, 'hide', 'hidden', 'hide_per_user' );
|
||||
|
||||
$messages = self::get_messages();
|
||||
$message = $messages['messages'][ $message_id ];
|
||||
if ( $message ) {
|
||||
echo self::display_message( $message_id, $message['text'], $message['type'], $message['classes'], $message['hide'] || $message['hide_per_user'], $message['dismiss'] || $message['dismiss_per_user'], true, true );
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
public static function engage_message() {
|
||||
$message_id = self::get_message_id();
|
||||
if ( ! self::message_id_exists( $message_id ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
self::set_message_display( $message_id, true, 'dismiss', 'dismissed', 'dismiss_per_user' );
|
||||
}
|
||||
|
||||
private static function set_message_display( $message_id, $show, $action, $action_past, $action_user ) {
|
||||
if ( $message_id === null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$messages = self::get_messages();
|
||||
|
||||
if ( ! isset( $messages['messages'][ $message_id ] ) ) {
|
||||
return;
|
||||
}
|
||||
$message = $messages['messages'][ $message_id ];
|
||||
$current_user_id = get_current_user_id();
|
||||
if ( $message[ $action_user ] && $current_user_id ) {
|
||||
$message['users'][ $current_user_id ][ $action_past ] = ! $show;
|
||||
} elseif ( $message[ $action ] ) {
|
||||
$message[ $action_past ] = ! $show;
|
||||
}
|
||||
$messages['messages'][ $message_id ] = $message;
|
||||
self::save_messages( $messages );
|
||||
}
|
||||
|
||||
public static function remove_message( $message_id ) {
|
||||
if ( ! $message_id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$messages = self::get_messages();
|
||||
|
||||
if ( ! isset( $messages['messages'][ $message_id ] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
unset( $messages['messages'][ $message_id ] );
|
||||
|
||||
self::save_messages( $messages );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function remove_message_group( $message_group ) {
|
||||
if ( ! $message_group ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$all_messages = self::get_messages();
|
||||
|
||||
if ( ! isset( $all_messages['messages'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$messages = $all_messages['messages'];
|
||||
|
||||
$ids_to_remove = array();
|
||||
foreach ( $messages as $id => $message_data ) {
|
||||
if ( isset( $message_data['group'] ) && $message_data['group'] == $message_group ) {
|
||||
$ids_to_remove[] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $ids_to_remove as $id_to_remove ) {
|
||||
self::remove_message( $id_to_remove );
|
||||
}
|
||||
}
|
||||
|
||||
public static function display_messages( $group = false ) {
|
||||
if ( is_admin() ) {
|
||||
$messages = self::get_messages();
|
||||
|
||||
foreach ( $messages['messages'] as $id => $msg ) {
|
||||
if ( ! $group || ( isset( $msg['group'] ) && $msg['group'] == $group ) ) {
|
||||
if ( isset( $msg['admin_notice'] ) && ! $msg['admin_notice'] ) {
|
||||
if ( ! isset( $msg['capability'] ) || ( $msg['capability'] == '' ) || current_user_can( $msg['capability'] ) ) {
|
||||
if ( array_key_exists( 'limit_to_page', $msg ) ) {
|
||||
foreach ( $msg['limit_to_page'] as $page ) {
|
||||
if ( array_key_exists( 'page', $_GET ) && $_GET['page'] === $page ) {
|
||||
self::display_message( $id, $msg['text'], $msg['type'], $msg['classes'], $msg['hide'] || $msg['hide_per_user'], $msg['dismiss'] || $msg['dismiss_per_user'], true );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self::display_message( $id, $msg['text'], $msg['type'], $msg['classes'], $msg['hide'] || $msg['hide_per_user'], $msg['dismiss'] || $msg['dismiss_per_user'], true );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $messages['instant_messages'] as $msg ) {
|
||||
self::display_instant_message( $msg['text'], $msg['type'] );
|
||||
}
|
||||
// delete instant messages
|
||||
$messages['instant_messages'] = array();
|
||||
self::save_messages( $messages );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated deprecated @since version 3.2. Use ICL_AdminNotifier::display_message()
|
||||
*
|
||||
* @param bool $group
|
||||
*/
|
||||
public static function displayMessages( $group = false ) {
|
||||
self::display_messages( $group );
|
||||
}
|
||||
|
||||
public static function admin_notices() {
|
||||
$messages = self::get_messages();
|
||||
if ( isset( $messages['messages'] ) ) {
|
||||
foreach ( $messages['messages'] as $id => $msg ) {
|
||||
|
||||
if ( isset( $msg['limit_to_page'] ) && $msg['limit_to_page'] ) {
|
||||
if ( ! is_array( $msg['limit_to_page'] ) ) {
|
||||
$msg['limit_to_page'] = (array) $msg['limit_to_page'];
|
||||
}
|
||||
if ( ! isset( $_REQUEST['page'] ) || ! in_array( $_REQUEST['page'], $msg['limit_to_page'] ) ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $msg['admin_notice'] ) {
|
||||
$current_user_id = get_current_user_id();
|
||||
$display = true;
|
||||
$display_fallback = false;
|
||||
|
||||
$message_user_data = isset( $msg['users'][ $current_user_id ] ) ? $msg['users'][ $current_user_id ] : false;
|
||||
|
||||
if ( $msg['dismiss_per_user'] && isset( $message_user_data['dismissed'] ) && $message_user_data['dismissed'] ) {
|
||||
$display = false;
|
||||
} elseif ( $msg['dismiss'] && isset( $msg['dismissed'] ) && $msg['dismissed'] ) {
|
||||
$display = false;
|
||||
}
|
||||
|
||||
if ( $display ) {
|
||||
if ( $msg['hide_per_user'] && isset( $message_user_data['hidden'] ) && $message_user_data['hidden'] ) {
|
||||
$display = false;
|
||||
$display_fallback = $msg['fallback_text'];
|
||||
} elseif ( $msg['hide'] && isset( $msg['hidden'] ) && $msg['hidden'] ) {
|
||||
$display = false;
|
||||
$display_fallback = $msg['fallback_text'];
|
||||
}
|
||||
}
|
||||
|
||||
$msg['classes'] = isset( $msg['classes'] ) ? $msg['classes'] : array();
|
||||
$msg['fallback_classes'] = isset( $msg['fallback_classes'] ) ? $msg['fallback_classes'] : array();
|
||||
if ( $display ) {
|
||||
self::display_message( $id, $msg['text'], $msg['type'], $msg['classes'], $msg['hide'] || $msg['hide_per_user'], $msg['dismiss'] || $msg['dismiss_per_user'], true );
|
||||
if ( $msg['show_once'] && ! $display_fallback ) {
|
||||
self::remove_message( $msg['id'] );
|
||||
}
|
||||
} elseif ( $display_fallback ) {
|
||||
self::display_message( $id, $msg['fallback_text'], $msg['fallback_type'], $msg['fallback_classes'], false, false, true );
|
||||
if ( $msg['show_once'] ) {
|
||||
self::remove_message( $msg['id'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $id
|
||||
* @param string $message
|
||||
* @param string $type
|
||||
* @param string|array $classes
|
||||
* @param bool $hide
|
||||
* @param bool $dismiss
|
||||
* @param bool $admin_notice
|
||||
* @param bool $echo
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private static function display_message( $id, $message, $type = '', $classes = array(), $hide = true, $dismiss = false, $admin_notice = false, $echo = false ) {
|
||||
$result = '';
|
||||
$temp_classes = array();
|
||||
if ( strpos( $type, 'icl-admin-message' ) ) {
|
||||
$type = str_replace( 'icl-admin-message-', '', $type );
|
||||
}
|
||||
if ( $admin_notice ) {
|
||||
$temp_classes[] = 'icl-admin-message';
|
||||
}
|
||||
$temp_types = explode( ' ', $type );
|
||||
$temp_types = array_unique( $temp_types );
|
||||
foreach ( $temp_types as $temp_type ) {
|
||||
if ( $admin_notice ) {
|
||||
$temp_classes[] = 'icl-admin-message-' . $temp_type;
|
||||
}
|
||||
$temp_classes[] = $temp_type;
|
||||
}
|
||||
|
||||
if ( $classes ) {
|
||||
if ( ! is_array( $classes ) ) {
|
||||
$classes = explode( ' ', $classes );
|
||||
}
|
||||
foreach ( $classes as $class ) {
|
||||
$temp_classes[] = $class;
|
||||
}
|
||||
}
|
||||
if ( $hide or $dismiss ) {
|
||||
$temp_classes[] = 'otgs-is-dismissible';
|
||||
}
|
||||
|
||||
$temp_classes = array_unique( $temp_classes );
|
||||
|
||||
$class = implode( ' ', $temp_classes );
|
||||
|
||||
$result .= '<div class="' . $class . '" id="icl-id-' . $id . '"';
|
||||
|
||||
if ( $hide ) {
|
||||
$result .= ' data-hide-text="' . __( 'Hide', 'sitepress' ) . '" ';
|
||||
}
|
||||
$result .= '>';
|
||||
|
||||
$result .= '<p>' . self::sanitize_and_format_message( $message ) . '</p>';
|
||||
if ( $hide ) {
|
||||
$result .= ' <span class="icl-admin-message-hide notice-dismiss"><span class="screen-reader-text">' . __( 'Hide this notice.', 'sitepress' ) . '</span></span>';
|
||||
}
|
||||
|
||||
if ( $dismiss ) {
|
||||
$result .= ' <span class="icl-admin-message-dismiss notice-dismiss">';
|
||||
$result .= '<span class="screen-reader-text"><input class="icl-admin-message-dismiss-check" type="checkbox" value="1" />';
|
||||
$result .= __( 'Dismiss this notice.', 'sitepress' );
|
||||
$result .= '</span></span>';
|
||||
}
|
||||
|
||||
$result .= '</div>';
|
||||
|
||||
if ( ! $echo ) {
|
||||
echo $result;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function display_instant_message( $message, $type = 'information', $class = false, $return = false, $fadeout = false ) {
|
||||
$classes = array();
|
||||
if ( ! $class && $type ) {
|
||||
$classes[] = $type;
|
||||
}
|
||||
$classes[] = 'instant-message';
|
||||
$classes[] = 'message';
|
||||
$classes[] = 'message-' . $type;
|
||||
|
||||
foreach ( $classes as $class ) {
|
||||
$classes[] = 'icl-admin-' . $class;
|
||||
}
|
||||
|
||||
if ( $fadeout ) {
|
||||
$classes[] = 'js-icl-fadeout';
|
||||
}
|
||||
|
||||
$classes = array_unique( $classes );
|
||||
|
||||
if ( in_array( 'error', $classes ) ) {
|
||||
$key = array_search( 'error', $classes );
|
||||
if ( $key !== false ) {
|
||||
unset( $classes[ $key ] );
|
||||
}
|
||||
}
|
||||
|
||||
$result = '<div class="' . implode( ' ', $classes ) . '">';
|
||||
$result .= self::sanitize_and_format_message( $message );
|
||||
$result .= '</div>';
|
||||
|
||||
if ( ! $return ) {
|
||||
echo $result;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<mixed> $args
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private static function sanitize_message_args( $args ) {
|
||||
if ( isset( $args['msg'] ) ) {
|
||||
$args['text'] = $args['msg'];
|
||||
unset( $args['msg'] );
|
||||
}
|
||||
|
||||
if ( isset( $args['fallback'] ) ) {
|
||||
$args['fallback_message'] = $args['fallback'];
|
||||
unset( $args['fallback'] );
|
||||
}
|
||||
|
||||
if ( isset( $args['message_fallback'] ) ) {
|
||||
$args['fallback_message'] = $args['message_fallback'];
|
||||
unset( $args['message_fallback'] );
|
||||
}
|
||||
|
||||
if ( isset( $args['type_fallback'] ) ) {
|
||||
$args['fallback_type'] = $args['type_fallback'];
|
||||
unset( $args['type_fallback'] );
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
if ( ! isset( $args['classes'] ) ) {
|
||||
$args['classes'] = array();
|
||||
} elseif ( ! is_array( $args['classes'] ) ) {
|
||||
$args['classes'] = (array) $args['classes'];
|
||||
}
|
||||
|
||||
if ( ! isset( $args['limit_to_page'] ) ) {
|
||||
$args['limit_to_page'] = array();
|
||||
} elseif ( ! is_array( $args['limit_to_page'] ) ) {
|
||||
$args['limit_to_page'] = (array) $args['limit_to_page'];
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
static function troubleshooting_js_data( $data ) {
|
||||
$data['nonce']['icl_restore_notifications'] = wp_create_nonce( 'icl_restore_notifications' );
|
||||
$data['nonce']['icl_remove_notifications'] = wp_create_nonce( 'icl_remove_notifications' );
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
static function has_hidden_messages() {
|
||||
$messages = self::get_messages();
|
||||
$no_hidden_messages = true;
|
||||
foreach ( $messages as $group => $message_group ) {
|
||||
foreach ( $message_group as $id => $msg ) {
|
||||
if ( ( isset( $msg['hidden'] ) && $msg['hidden'] ) || ( isset( $msg['dismissed'] ) && $msg['dismissed'] ) ) {
|
||||
$no_hidden_messages = false;
|
||||
} else {
|
||||
$current_user_id = get_current_user_id();
|
||||
$message_user_data = isset( $msg['users'][ $current_user_id ] ) ? $msg['users'][ $current_user_id ] : false;
|
||||
if ( $message_user_data && $msg['dismiss_per_user'] && isset( $message_user_data['dismissed'] ) && $message_user_data['dismissed'] ) {
|
||||
$no_hidden_messages = false;
|
||||
} elseif ( $message_user_data && $msg['dismiss'] && isset( $msg['dismissed'] ) && $msg['dismissed'] ) {
|
||||
$no_hidden_messages = false;
|
||||
}
|
||||
|
||||
if ( $no_hidden_messages ) {
|
||||
if ( isset( $msg['hide_per_user'] ) && $msg['hide_per_user'] && isset( $message_user_data['hidden'] ) && $message_user_data['hidden'] ) {
|
||||
$no_hidden_messages = ! $msg['fallback_text'];
|
||||
} elseif ( $msg['hide'] && isset( $msg['hidden'] ) && $msg['hidden'] ) {
|
||||
$no_hidden_messages = ! $msg['fallback_text'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $no_hidden_messages ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static function troubleshooting() {
|
||||
?>
|
||||
<h4><?php _e( 'Messages and notifications', 'sitepress' ); ?></h4>
|
||||
<?php
|
||||
if ( self::has_hidden_messages() ) {
|
||||
|
||||
?>
|
||||
<p>
|
||||
<input id="icl_restore_notifications" type="button" class="button-secondary" value="<?php echo __( 'Restore messages and notification', 'sitepress' ); ?>"/>
|
||||
<br/>
|
||||
<br/>
|
||||
<input id="icl_restore_notifications_all_users" name="icl_restore_notifications_all_users" type="checkbox" value="1"/><label for="icl_restore_notifications_all_users"><?php echo __( 'Apply to all users', 'sitepress' ); ?></label>
|
||||
<br/>
|
||||
<br/>
|
||||
<small style="margin-left:10px;"><?php echo __( 'Restore dismissed and hidden messages and notifications.', 'sitepress' ); ?></small>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<p>
|
||||
<input id="icl_remove_notifications" type="button" class="button-secondary" value="<?php echo __( 'Remove all messages and notifications', 'sitepress' ); ?>"/>
|
||||
<br/>
|
||||
<small style="margin-left:10px;"><?php echo __( 'Remove all messages and notifications, for all users.', 'sitepress' ); ?></small>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
|
||||
static function remove_notifications() {
|
||||
self::save_messages( array() );
|
||||
echo wp_json_encode(
|
||||
array(
|
||||
'errors' => 0,
|
||||
'message' => __( 'Done', 'sitepress' ),
|
||||
'cont' => 0,
|
||||
'reload' => 1,
|
||||
)
|
||||
);
|
||||
die();
|
||||
}
|
||||
|
||||
static function restore_notifications() {
|
||||
$all_users = $_POST['all_users'];
|
||||
|
||||
$messages = self::get_messages();
|
||||
$dirty = 0;
|
||||
foreach ( $messages as $group => $message_group ) {
|
||||
foreach ( $message_group as $id => $msg ) {
|
||||
if ( $msg['hidden'] ) {
|
||||
$msg['hidden'] = false;
|
||||
$dirty ++;
|
||||
}
|
||||
if ( $msg['dismissed'] ) {
|
||||
$msg['dismissed'] = false;
|
||||
$dirty ++;
|
||||
}
|
||||
|
||||
$current_user_id = get_current_user_id();
|
||||
foreach ( $msg['users'] as $user_id => $message_user_data ) {
|
||||
if ( $current_user_id == $user_id || $all_users ) {
|
||||
if ( $message_user_data['hidden'] ) {
|
||||
$message_user_data['hidden'] = false;
|
||||
$dirty ++;
|
||||
}
|
||||
if ( $message_user_data['dismissed'] ) {
|
||||
$message_user_data['dismissed'] = false;
|
||||
$dirty ++;
|
||||
}
|
||||
}
|
||||
$msg['users'][ $user_id ] = $message_user_data;
|
||||
}
|
||||
|
||||
$message_group[ $id ] = $msg;
|
||||
}
|
||||
$messages[ $group ] = $message_group;
|
||||
}
|
||||
|
||||
if ( $dirty ) {
|
||||
self::save_messages( $messages );
|
||||
}
|
||||
|
||||
echo wp_json_encode(
|
||||
array(
|
||||
'errors' => 0,
|
||||
'message' => __( 'Done', 'sitepress' ),
|
||||
'cont' => $dirty,
|
||||
'reload' => 1,
|
||||
)
|
||||
);
|
||||
die();
|
||||
}
|
||||
|
||||
/** Deprecated methods */
|
||||
|
||||
/**
|
||||
* @param int $message_id
|
||||
*
|
||||
* @return bool
|
||||
* @deprecated deprecated @since version 3.2. Use ICL_AdminNotifier::remove_message()
|
||||
*
|
||||
*/
|
||||
public static function removeMessage( $message_id ) {
|
||||
return self::remove_message( $message_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated deprecated @since version 3.2
|
||||
*/
|
||||
public static function hideMessage() {
|
||||
self::hide_message();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated deprecated @since version 3.2
|
||||
*
|
||||
* @param string $message
|
||||
* @param string $type
|
||||
*/
|
||||
public static function addInstantMessage( $message, $type = '' ) {
|
||||
self::add_instant_message( $message, $type );
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated deprecated @since version 3.2
|
||||
*/
|
||||
public static function addScript() {
|
||||
self::add_script();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated deprecated @since version 3.2
|
||||
*
|
||||
* @param string $id An unique identifier for the message
|
||||
* @param string $msg The actual message
|
||||
* @param string $type (optional) Any string: it will be used as css class fro the message container. A typical value is 'error', but the following strings can be also used: icl-admin-message-information, icl-admin-message-warning
|
||||
* @param bool $hide (optional) Enable the toggle link to permanently hide the notice
|
||||
* @param bool $fallback_message (optional) A message to show when the notice gets hidden
|
||||
* @param bool $fallback_type (optional) The message type to use in the fallback message (@see $type)
|
||||
* @param bool $group (optional) A way to group messages: when displaying messages stored with this method, it's possible to filter them by group (@see ICL_AdminNotifier::displayMessages)
|
||||
* @param bool $admin_notice (optional) Hook the rendering to the 'admin_notice' action
|
||||
*/
|
||||
public static function addMessage( $id, $msg, $type = '', $hide = true, $fallback_message = false, $fallback_type = false, $group = false, $admin_notice = false ) {
|
||||
$args = array(
|
||||
'id' => $id,
|
||||
'msg' => $msg,
|
||||
'type' => $type,
|
||||
'hide' => $hide,
|
||||
'message_fallback' => $fallback_message,
|
||||
'fallback_type' => $fallback_type,
|
||||
'group' => $group,
|
||||
'admin_notice' => $admin_notice,
|
||||
);
|
||||
|
||||
self::add_message( $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param string $type
|
||||
* @param bool $class
|
||||
* @param bool $return
|
||||
*
|
||||
* @return string
|
||||
* @deprecated deprecated @since version 3.2. Use ICL_AdminNotifier::display_instant_message()
|
||||
*
|
||||
*/
|
||||
public static function displayInstantMessage( $message, $type = 'information', $class = false, $return = false ) {
|
||||
return self::display_instant_message( $message, $type, $class, $return );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function sanitize_and_format_message( $message ) {
|
||||
// return preg_replace( '/`(.*?)`/s', '<pre>$1</pre>', stripslashes( $message ) );
|
||||
$backticks_pattern = '|`(.*)`|U';
|
||||
preg_match_all( $backticks_pattern, $message, $matches );
|
||||
|
||||
$sanitized_message = $message;
|
||||
if ( 2 === count( $matches ) ) {
|
||||
$matches_to_sanitize = $matches[1];
|
||||
|
||||
foreach ( $matches_to_sanitize as &$match_to_sanitize ) {
|
||||
$match_to_sanitize = '<pre>' . esc_html( $match_to_sanitize ) . '</pre>';
|
||||
}
|
||||
unset( $match_to_sanitize );
|
||||
|
||||
$sanitized_message = str_replace( $matches[0], $matches_to_sanitize, $sanitized_message );
|
||||
}
|
||||
|
||||
return stripslashes( $sanitized_message );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
global $pagenow;
|
||||
$filtered_import = filter_input( INPUT_GET, 'import',FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_NULL_ON_FAILURE );
|
||||
$filtered_step = filter_input( INPUT_GET, 'step',FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_NULL_ON_FAILURE );
|
||||
|
||||
if ($pagenow == 'admin.php' && 0 === strcmp( $filtered_import, 'wordpress' ) && $filtered_step == 1 ) {
|
||||
add_action('admin_head', 'icl_import_xml');
|
||||
}
|
||||
|
||||
function icl_import_xml() {
|
||||
global $sitepress;
|
||||
$langs = $sitepress->get_active_languages();
|
||||
if (empty($langs)) {
|
||||
return;
|
||||
}
|
||||
$default = $sitepress->get_default_language();
|
||||
|
||||
$out = '<h3>' . esc_html__('Select Language', 'sitepress') . '</h3><p><select name="icl_post_language">';
|
||||
foreach ($langs as $lang) {
|
||||
$out .= '<option value="' . esc_attr( $lang['code'] ) . '"';
|
||||
if ($default == $lang['code']) {
|
||||
$out .= ' selected="selected"';
|
||||
}
|
||||
$out .= '>' . esc_html( $lang['native_name'] ) . '<\/option>';
|
||||
}
|
||||
$out .= '<\/select><\/p>';
|
||||
|
||||
echo '
|
||||
<script type="text/javascript">
|
||||
jQuery(document).ready(function(){
|
||||
jQuery("#wpbody-content").find("form .submit").before(\'' . $out . '\');
|
||||
});
|
||||
</script>
|
||||
';
|
||||
}
|
||||
|
||||
add_action('import_start', 'icl_import_xml_start', 0);
|
||||
function icl_import_xml_start() {
|
||||
set_time_limit( 0 );
|
||||
$post_languages = isset( $_POST['icl_post_language'] ) ? $_POST['icl_post_language'] : array();
|
||||
|
||||
$_POST['icl_tax_post_tag_language'] = $_POST['icl_tax_category_language'] = $_POST['icl_tax_language'] = $post_languages;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Registers scripts so that they can be reused throughout WPML plugins
|
||||
* Hooked to `admin_enqueue_scripts`
|
||||
*/
|
||||
function wpml_register_js_scripts() {
|
||||
wp_register_script( 'wpml-underscore-template-compiler',
|
||||
ICL_PLUGIN_URL . '/res/js/shared/wpml-template-compiler.js',
|
||||
array( "underscore" ) );
|
||||
wp_register_script( 'wpml-domain-validation',
|
||||
ICL_PLUGIN_URL . '/res/js/settings/wpml-domain-validation.js',
|
||||
array( "jquery" ) );
|
||||
|
||||
}
|
||||
|
||||
if ( is_admin() ) {
|
||||
add_action( 'admin_enqueue_scripts', 'wpml_register_js_scripts', -PHP_INT_MAX );
|
||||
} else {
|
||||
add_action( 'wp_enqueue_scripts', 'wpml_register_js_scripts', -PHP_INT_MAX );
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Registers TM scripts that they are being used from WPML plugin
|
||||
* Hooked to `admin_enqueue_scripts` and 'wp_enqueue_scripts'
|
||||
*/
|
||||
if ( ! \WPML\Plugins::isTMActive() && defined( 'WPML_TM_URL' ) ) {
|
||||
/**
|
||||
* Registers scripts so that they can be reused throughout WPML plugins
|
||||
*/
|
||||
function wpml_tm_register_js_scripts() {
|
||||
if ( \WPML\Setup\Option::isTMAllowed() ) {
|
||||
wp_register_script(
|
||||
'wpml-tm-editor-templates',
|
||||
WPML_TM_URL . '/res/js/translation-editor/templates.js',
|
||||
array(),
|
||||
WPML_TM_VERSION,
|
||||
true
|
||||
);
|
||||
wp_register_script(
|
||||
'wpml-tm-editor-job',
|
||||
WPML_TM_URL . '/res/js/translation-editor/wpml-tm-editor-job.js',
|
||||
array( 'underscore', 'backbone' ),
|
||||
WPML_TM_VERSION,
|
||||
true
|
||||
);
|
||||
|
||||
$scripts = array(
|
||||
'wpml-tm-editor-job-field-view',
|
||||
'wpml-tm-editor-job-basic-field-view',
|
||||
'wpml-tm-editor-job-single-line-field-view',
|
||||
'wpml-tm-editor-job-textarea-field-view',
|
||||
'wpml-tm-editor-job-wysiwyg-field-view',
|
||||
'wpml-tm-editor-field-view-factory',
|
||||
'wpml-tm-editor-section-view',
|
||||
'wpml-tm-editor-group-view',
|
||||
'wpml-tm-editor-image-view',
|
||||
'wpml-tm-editor-main-view',
|
||||
'wpml-tm-editor-header-view',
|
||||
'wpml-tm-editor-note-view',
|
||||
'wpml-tm-editor-footer-view',
|
||||
'wpml-tm-editor-languages-view',
|
||||
'wpml-tm-editor-copy-all-dialog',
|
||||
'wpml-tm-editor-edit-independently-dialog',
|
||||
'wpml-tm-editor-translation-memory',
|
||||
);
|
||||
|
||||
$additional_requirements = array(
|
||||
'wpml-tm-editor-footer-view' => array( 'wpml-tm-progressbar' ),
|
||||
);
|
||||
|
||||
foreach ( $scripts as $script ) {
|
||||
wp_register_script(
|
||||
$script,
|
||||
WPML_TM_URL . '/res/js/translation-editor/' . $script . '.js',
|
||||
array_merge(
|
||||
array( 'wpml-tm-editor-job' ),
|
||||
isset( $additional_requirements[ $script ] ) ? $additional_requirements[ $script ] : array()
|
||||
),
|
||||
WPML_TM_VERSION,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
wp_register_script(
|
||||
'wpml-tm-editor-scripts',
|
||||
WPML_TM_URL . '/res/js/translation-editor/translation-editor.js',
|
||||
array_merge( array(
|
||||
'jquery',
|
||||
'jquery-ui-dialog',
|
||||
'wpml-tm-editor-templates',
|
||||
'wpml-tm-editor-job'
|
||||
), $scripts ),
|
||||
WPML_TM_VERSION,
|
||||
true
|
||||
);
|
||||
wp_register_script(
|
||||
'wpml-tp-polling-box-populate',
|
||||
WPML_TM_URL . '/res/js/tp-polling/box-populate.js',
|
||||
array( 'jquery' ),
|
||||
WPML_TM_VERSION,
|
||||
true
|
||||
);
|
||||
wp_register_script(
|
||||
'wpml-tp-polling',
|
||||
WPML_TM_URL . '/res/js/tp-polling/poll-for-translations.js',
|
||||
array( 'wpml-tp-polling-box-populate' ),
|
||||
WPML_TM_VERSION,
|
||||
true
|
||||
);
|
||||
wp_register_script(
|
||||
'wpml-tm-mcs',
|
||||
WPML_TM_URL . '/res/js/mcs/wpml-tm-mcs.js',
|
||||
array( 'wpml-tp-polling' ),
|
||||
WPML_TM_VERSION,
|
||||
true
|
||||
);
|
||||
wp_register_script(
|
||||
'wpml-tm-mcs-translate-link-targets',
|
||||
WPML_TM_URL . '/res/js/mcs/wpml-tm-mcs-translate-link-targets.js',
|
||||
array(),
|
||||
WPML_TM_VERSION,
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( is_admin() ) {
|
||||
add_action( 'admin_enqueue_scripts', 'wpml_tm_register_js_scripts' );
|
||||
} else {
|
||||
add_action( 'wp_enqueue_scripts', 'wpml_tm_register_js_scripts' );
|
||||
}
|
||||
}
|
||||
301
wp-content/plugins/sitepress-multilingual-cms/inc/lang-data.php
Normal file
301
wp-content/plugins/sitepress-multilingual-cms/inc/lang-data.php
Normal file
@@ -0,0 +1,301 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
function icl_get_languages_names() {
|
||||
static $__icl_lang_names_cached = null;
|
||||
|
||||
if ( $__icl_lang_names_cached === null ) {
|
||||
$serialized_languages = file_get_contents( WPML_PLUGIN_PATH . '/res/languages.json' );
|
||||
$__icl_lang_names = json_decode( $serialized_languages, true );
|
||||
|
||||
$__icl_lang_names_cached = $__icl_lang_names;
|
||||
}
|
||||
|
||||
return $__icl_lang_names_cached;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
function icl_get_languages_codes() {
|
||||
static $result = null;
|
||||
|
||||
if ( null === $result ) {
|
||||
$result = array(
|
||||
'Abkhazian' => 'ab',
|
||||
'Afar' => 'aa',
|
||||
'Afrikaans' => 'af',
|
||||
'Akan' => 'ak',
|
||||
'Albanian' => 'sq',
|
||||
'Amharic' => 'am',
|
||||
'Arabic' => 'ar',
|
||||
'Armenian' => 'hy',
|
||||
'Assamese' => 'as',
|
||||
'Avar' => 'av',
|
||||
'Avestan' => 'ae',
|
||||
'Aymara' => 'ay',
|
||||
'Azerbaijani' => 'az',
|
||||
'Bambara' => 'bm',
|
||||
'Bashkir' => 'ba',
|
||||
'Basque' => 'eu',
|
||||
'Belarusian' => 'be',
|
||||
'Bengali' => 'bn',
|
||||
'Bhutani' => 'dz',
|
||||
'Bihari' => 'bh',
|
||||
'Bislama' => 'bi',
|
||||
'Bosnian' => 'bs',
|
||||
'Breton' => 'br',
|
||||
'Bulgarian' => 'bg',
|
||||
'Burmese' => 'my',
|
||||
'Cambodian' => 'km',
|
||||
'Catalan' => 'ca',
|
||||
'Chamorro' => 'ch',
|
||||
'Chechen' => 'ce',
|
||||
'Chichewa' => 'ny',
|
||||
'Chinese (Simplified)' => 'zh-hans',
|
||||
'Chinese (Traditional)' => 'zh-hant',
|
||||
'Chuvash' => 'cv',
|
||||
'Cornish' => 'kw',
|
||||
'Corsican' => 'co',
|
||||
'Cree' => 'cr',
|
||||
'Croatian' => 'hr',
|
||||
'Czech' => 'cs',
|
||||
'Danish' => 'da',
|
||||
'English' => 'en',
|
||||
'Esperanto' => 'eo',
|
||||
'Estonian' => 'et',
|
||||
'Ewe' => 'ee',
|
||||
'Faeroese' => 'fo',
|
||||
'Fiji' => 'fj',
|
||||
'Finnish' => 'fi',
|
||||
'French' => 'fr',
|
||||
'Frisian' => 'fy',
|
||||
'Fulah' => 'ff',
|
||||
'Galician' => 'gl',
|
||||
'Georgian' => 'ka',
|
||||
'German' => 'de',
|
||||
'Greek' => 'el',
|
||||
'Greenlandic' => 'kl',
|
||||
'Guarani' => 'gn',
|
||||
'Gujarati' => 'gu',
|
||||
'Hausa' => 'ha',
|
||||
'Hebrew' => 'he',
|
||||
'Herero' => 'hz',
|
||||
'Hindi' => 'hi',
|
||||
'Hiri Motu' => 'ho',
|
||||
'Hungarian' => 'hu',
|
||||
'Icelandic' => 'is',
|
||||
'Igbo' => 'ig',
|
||||
'Indonesian' => 'id',
|
||||
'Interlingua' => 'ia',
|
||||
'Interlingue' => 'ie',
|
||||
'Inuktitut' => 'iu',
|
||||
'Inupiak' => 'ik',
|
||||
'Irish' => 'ga',
|
||||
'Italian' => 'it',
|
||||
'Japanese' => 'ja',
|
||||
'Javanese' => 'jv',
|
||||
'Kannada' => 'kn',
|
||||
'Kanuri' => 'kr',
|
||||
'Kashmiri' => 'ks',
|
||||
'Kazakh' => 'kk',
|
||||
'Kikuyu' => 'ki',
|
||||
'Kinyarwanda' => 'rw',
|
||||
'Kirghiz' => 'ky',
|
||||
'Kirundi' => 'rn',
|
||||
'Komi' => 'kv',
|
||||
'Kongo' => 'kg',
|
||||
'Korean' => 'ko',
|
||||
'Kurdish' => 'ku',
|
||||
'Kwanyama' => 'kj',
|
||||
'Laothian' => 'lo',
|
||||
'Latvian' => 'lv',
|
||||
'Lingala' => 'ln',
|
||||
'Lithuanian' => 'lt',
|
||||
'Luganda' => 'lg',
|
||||
'Luxembourgish' => 'lb',
|
||||
'Macedonian' => 'mk',
|
||||
'Malagasy' => 'mg',
|
||||
'Malay' => 'ms',
|
||||
'Malayalam' => 'ml',
|
||||
'Maldivian' => 'dv',
|
||||
'Maltese' => 'mt',
|
||||
'Manx' => 'gv',
|
||||
'Maori' => 'mi',
|
||||
'Marathi' => 'mr',
|
||||
'Marshallese' => 'mh',
|
||||
'Moldavian' => 'mo',
|
||||
'Mongolian' => 'mn',
|
||||
'Nauru' => 'na',
|
||||
'Navajo' => 'nv',
|
||||
'Ndonga' => 'ng',
|
||||
'Nepali' => 'ne',
|
||||
'North Ndebele' => 'nd',
|
||||
'Northern Sami' => 'se',
|
||||
'Dutch' => 'nl',
|
||||
'Norwegian Bokmål' => 'no',
|
||||
'Norwegian Nynorsk' => 'nn',
|
||||
'Occitan' => 'oc',
|
||||
'Old Slavonic' => 'cu',
|
||||
'Oriya' => 'or',
|
||||
'Oromo' => 'om',
|
||||
'Ossetian' => 'os',
|
||||
'Pali' => 'pi',
|
||||
'Pashto' => 'ps',
|
||||
'Persian' => 'fa',
|
||||
'Polish' => 'pl',
|
||||
'Portuguese, Brazil' => 'pt-br',
|
||||
'Portuguese, Portugal' => 'pt-pt',
|
||||
'Punjabi' => 'pa',
|
||||
'Quechua' => 'qu',
|
||||
'Rhaeto-Romance' => 'rm',
|
||||
'Romanian' => 'ro',
|
||||
'Russian' => 'ru',
|
||||
'Samoan' => 'sm',
|
||||
'Sango' => 'sg',
|
||||
'Sanskrit' => 'sa',
|
||||
'Sardinian' => 'sc',
|
||||
'Scots Gaelic' => 'gd',
|
||||
'Serbian' => 'sr',
|
||||
'Serbo-Croatian' => 'sh',
|
||||
'Sesotho' => 'st',
|
||||
'Setswana' => 'tn',
|
||||
'Shona' => 'sn',
|
||||
'Sindhi' => 'sd',
|
||||
'Singhalese' => 'si',
|
||||
'Siswati' => 'ss',
|
||||
'Slavic' => 'sla',
|
||||
'Slovak' => 'sk',
|
||||
'Slovenian' => 'sl',
|
||||
'Somali' => 'so',
|
||||
'South Ndebele' => 'nr',
|
||||
'Spanish' => 'es',
|
||||
'Sudanese' => 'su',
|
||||
'Swahili' => 'sw',
|
||||
'Swedish' => 'sv',
|
||||
'Tagalog' => 'tl',
|
||||
'Tahitian' => 'ty',
|
||||
'Tajik' => 'tg',
|
||||
'Tamil' => 'ta',
|
||||
'Tatar' => 'tt',
|
||||
'Telugu' => 'te',
|
||||
'Thai' => 'th',
|
||||
'Tibetan' => 'bo',
|
||||
'Tigrinya' => 'ti',
|
||||
'Tonga' => 'to',
|
||||
'Tsonga' => 'ts',
|
||||
'Turkish' => 'tr',
|
||||
'Turkmen' => 'tk',
|
||||
'Twi' => 'tw',
|
||||
'Uighur' => 'ug',
|
||||
'Ukrainian' => 'uk',
|
||||
'Urdu' => 'ur',
|
||||
'Uzbek' => 'uz',
|
||||
'Venda' => 've',
|
||||
'Vietnamese' => 'vi',
|
||||
'Welsh' => 'cy',
|
||||
'Wolof' => 'wo',
|
||||
'Xhosa' => 'xh',
|
||||
'Yiddish' => 'yi',
|
||||
'Yoruba' => 'yo',
|
||||
'Zhuang' => 'za',
|
||||
'Zulu' => 'zu',
|
||||
);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
function icl_get_languages_locales() {
|
||||
static $result = null;
|
||||
|
||||
if ( ! $result ) {
|
||||
$result = array(
|
||||
'af' => 'af_ZA',
|
||||
'ar' => 'ar',
|
||||
'az' => 'az',
|
||||
'be' => 'be_BY',
|
||||
'bg' => 'bg_BG',
|
||||
'bn' => 'bn_BD',
|
||||
'bs' => 'bs_BA',
|
||||
'ca' => 'ca',
|
||||
'cs' => 'cs_CZ',
|
||||
'cy' => 'cy_GB',
|
||||
'da' => 'da_DK',
|
||||
'de' => 'de_DE',
|
||||
'el' => 'el',
|
||||
'en' => 'en_US',
|
||||
'eo' => 'eo_UY',
|
||||
'es' => 'es_ES',
|
||||
'et' => 'et',
|
||||
'eu' => 'eu_ES',
|
||||
'fa' => 'fa_IR',
|
||||
'fi' => 'fi',
|
||||
'fo' => 'fo_FO',
|
||||
'fr' => 'fr_FR',
|
||||
'ga' => 'ga_IE',
|
||||
'gl' => 'gl_ES',
|
||||
'he' => 'he_IL',
|
||||
'hi' => 'hi_IN',
|
||||
'hr' => 'hr',
|
||||
'hu' => 'hu_HU',
|
||||
'hy' => 'hy_AM',
|
||||
'id' => 'id_ID',
|
||||
'is' => 'is_IS',
|
||||
'it' => 'it_IT',
|
||||
'ja' => 'ja',
|
||||
'ka' => 'ge_GE',
|
||||
'km' => 'km_KH',
|
||||
'ko' => 'ko_KR',
|
||||
'ku' => 'ckb',
|
||||
'lt' => 'lt_LT',
|
||||
'lv' => 'lv_LV',
|
||||
'mg' => 'mg_MG',
|
||||
'mk' => 'mk_MK',
|
||||
'mn' => 'mn_MN',
|
||||
'ms' => 'ms_MY',
|
||||
'mt' => 'mt_MT',
|
||||
'nb' => 'nb_NO',
|
||||
'ne' => 'ne',
|
||||
'no' => 'nb_NO',
|
||||
'nn' => 'nn_NO',
|
||||
'ni' => 'ni_ID',
|
||||
'nl' => 'nl_NL',
|
||||
'pa' => 'pa_IN',
|
||||
'pl' => 'pl_PL',
|
||||
'pt-br' => 'pt_BR',
|
||||
'pt-pt' => 'pt_PT',
|
||||
'qu' => 'quz_PE',
|
||||
'ro' => 'ro_RO',
|
||||
'ru' => 'ru_RU',
|
||||
'si' => 'si_LK',
|
||||
'sk' => 'sk_SK',
|
||||
'sl' => 'sl_SI',
|
||||
'so' => 'so_SO',
|
||||
'sq' => 'sq_AL',
|
||||
'sr' => 'sr_RS',
|
||||
'su' => 'su_ID',
|
||||
'sv' => 'sv_SE',
|
||||
'ta' => 'ta_IN',
|
||||
'tg' => 'tg_TJ',
|
||||
'th' => 'th',
|
||||
'tr' => 'tr_TR',
|
||||
'ug' => 'ug_CN',
|
||||
'uk' => 'uk',
|
||||
'ur' => 'ur',
|
||||
'uz' => 'uz_UZ',
|
||||
'vi' => 'vi_VN',
|
||||
'zh-hans' => 'zh_CN',
|
||||
'zh-hant' => 'zh_TW',
|
||||
);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class SitePressLanguageSwitcher
|
||||
*
|
||||
* @deprecated since 3.6.0
|
||||
*/
|
||||
class SitePressLanguageSwitcher {
|
||||
|
||||
/**
|
||||
* @deprecated since 3.6.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
static function get_language_selector_footer() {
|
||||
ob_start();
|
||||
do_action( 'wpml_footer_language_selector' );
|
||||
$output = ob_get_contents();
|
||||
ob_end_clean();
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated since 3.6.0
|
||||
*/
|
||||
function language_selector_footer() {
|
||||
do_action( 'wpml_footer_language_selector' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $native_name
|
||||
* @param bool $translated_name
|
||||
* @param bool $show_native_name
|
||||
* @param bool $show_translate_name
|
||||
* @param bool $include_html
|
||||
*
|
||||
* @return string
|
||||
* @deprecated since 3.6.0
|
||||
*
|
||||
*/
|
||||
public function language_display( $native_name, $translated_name = false, $show_native_name = false, $show_translate_name = false, $include_html = true ) {
|
||||
$result = '';
|
||||
|
||||
if ( ! $show_native_name ) {
|
||||
$native_name = '';
|
||||
}
|
||||
|
||||
if ( ! $show_translate_name ) {
|
||||
$translated_name = '';
|
||||
}
|
||||
|
||||
if ( $native_name && $translated_name ) {
|
||||
if ( $native_name != $translated_name ) {
|
||||
if ( $show_native_name ) {
|
||||
if ( $include_html ) {
|
||||
$result .= '<span class="icl_lang_sel_native">';
|
||||
}
|
||||
$result .= '%1$s';
|
||||
if ( $include_html ) {
|
||||
$result .= '</span>';
|
||||
}
|
||||
if ( $show_translate_name ) {
|
||||
$result .= ' ';
|
||||
if ( $include_html ) {
|
||||
$result .= '<span class="icl_lang_sel_translated">';
|
||||
}
|
||||
$result .= $show_native_name
|
||||
? '<span class="icl_lang_sel_bracket">(</span>%2$s<span class="icl_lang_sel_bracket">)</span>'
|
||||
: '%2$s';
|
||||
if ( $include_html ) {
|
||||
$result .= '</span>';
|
||||
}
|
||||
}
|
||||
} elseif ( $show_translate_name ) {
|
||||
if ( $include_html ) {
|
||||
$result .= '<span class="icl_lang_sel_translated">';
|
||||
}
|
||||
$result .= '%2$s';
|
||||
if ( $include_html ) {
|
||||
$result .= '</span>';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ( $include_html ) {
|
||||
$result .= '<span class="icl_lang_sel_current icl_lang_sel_native">';
|
||||
}
|
||||
$result .= '%1$s';
|
||||
if ( $include_html ) {
|
||||
$result .= '</span>';
|
||||
}
|
||||
}
|
||||
} elseif ( $native_name ) {
|
||||
$result = '%1$s';
|
||||
} elseif ( $translated_name ) {
|
||||
$result = '%2$s';
|
||||
}
|
||||
|
||||
return sprintf( $result, $native_name, $translated_name );
|
||||
}
|
||||
} // end class
|
||||
|
||||
global $icl_language_switcher;
|
||||
$icl_language_switcher = new SitePressLanguageSwitcher();
|
||||
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
|
||||
class WPML_TM_Blog_Translators {
|
||||
|
||||
/** @var WPML_TM_Records $tm_records */
|
||||
private $tm_records;
|
||||
|
||||
/**
|
||||
* @var SitePress;
|
||||
*/
|
||||
private $sitepress;
|
||||
|
||||
/** @var WPML_Translator_Records $translator_records */
|
||||
private $translator_records;
|
||||
|
||||
/** @var WPML_Cache_Factory */
|
||||
private $cache_factory;
|
||||
|
||||
/**
|
||||
* @param SitePress $sitepress
|
||||
* @param WPML_TM_Records $tm_records
|
||||
* @param WPML_Translator_Records $translator_records
|
||||
* @param WPML_Cache_Factory $cache_factory
|
||||
*/
|
||||
public function __construct(
|
||||
SitePress $sitepress,
|
||||
WPML_TM_Records $tm_records,
|
||||
WPML_Translator_Records $translator_records,
|
||||
WPML_Cache_Factory $cache_factory
|
||||
) {
|
||||
$this->sitepress = $sitepress;
|
||||
$this->tm_records = $tm_records;
|
||||
$this->translator_records = $translator_records;
|
||||
$this->cache_factory = $cache_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* It returns true if the site has translators.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function has_translators() {
|
||||
$cache = $this->cache_factory->get( 'WPML_TM_Blog_Translators::has_translators' );
|
||||
|
||||
return $cache->execute_and_cache(
|
||||
'has-translators',
|
||||
function () {
|
||||
return $this->translator_records->has_users_with_capability();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $args
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function get_blog_translators( $args = array() ) {
|
||||
$from = isset( $args['from'] ) ? $args['from'] : false;
|
||||
$to = isset( $args['to'] ) ? $args['to'] : false;
|
||||
|
||||
$all_translators = $this->get_raw_blog_translators();
|
||||
$translators = array();
|
||||
|
||||
foreach ( $all_translators as $key => $translator ) {
|
||||
if ( ! $from || ! $to ) {
|
||||
$translators[] = isset( $translator->data ) ? $translator->data : $translator;
|
||||
} elseif ( $this->translator_has_language_pair( $translator->ID, $from, $to ) ) {
|
||||
$translators[] = isset( $translator->data ) ? $translator->data : $translator;
|
||||
}
|
||||
}
|
||||
|
||||
return apply_filters( 'blog_translators', $translators, $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $translator_id
|
||||
* @param string $from
|
||||
* @param string $to
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function translator_has_language_pair( $translator_id, $from, $to ) {
|
||||
$language_pairs = $this->get_language_pairs( $translator_id );
|
||||
|
||||
if ( isset( $language_pairs[ $from ][ $to ] ) && (bool) $language_pairs[ $from ][ $to ] ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function get_raw_blog_translators() {
|
||||
$cache = $this->cache_factory->get( 'WPML_TM_Blog_Translators::get_raw_blog_translators' );
|
||||
|
||||
return $cache->execute_and_cache(
|
||||
'has-translators',
|
||||
function () {
|
||||
return $this->translator_records->get_users_with_capability();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $user_id
|
||||
* @param array $args
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function is_translator( $user_id, $args = array() ) {
|
||||
$defaults = [
|
||||
'lang_from' => null,
|
||||
'lang_to' => null,
|
||||
'job_id' => null,
|
||||
'post_id' => null,
|
||||
'admin_override' => true,
|
||||
];
|
||||
$args = array_merge( $defaults, $args );
|
||||
|
||||
$lang_from = $args['lang_from'];
|
||||
$lang_to = $args['lang_to'];
|
||||
$job_id = $args['job_id'];
|
||||
$admin_override = $args['admin_override'];
|
||||
|
||||
$is_translator = $this->sitepress->get_wp_api()
|
||||
->user_can( $user_id, 'translate' );
|
||||
// check if user is administrator and return true if he is
|
||||
if ( $admin_override && $this->sitepress->get_wp_api()
|
||||
->user_can( $user_id, 'manage_options' )
|
||||
) {
|
||||
$is_translator = true;
|
||||
do_action( 'wpml_tm_ate_enable_subscription', $user_id );
|
||||
} else {
|
||||
if ( $lang_from && $lang_to ) {
|
||||
$user_language_pairs = $this->get_language_pairs( $user_id );
|
||||
if ( ! empty( $user_language_pairs ) ) {
|
||||
foreach ( $user_language_pairs as $user_lang_from => $user_lang_to ) {
|
||||
if ( array_key_exists( $lang_to, $user_lang_to ) ) {
|
||||
$is_translator = true;
|
||||
break;
|
||||
} else {
|
||||
$is_translator = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$is_translator = false;
|
||||
}
|
||||
}
|
||||
if ( $job_id ) {
|
||||
$job_record = $this->tm_records->icl_translate_job_by_job_id( $job_id );
|
||||
$translator_id = in_array(
|
||||
$job_record->service(),
|
||||
array(
|
||||
'local',
|
||||
0,
|
||||
)
|
||||
) ? $job_record->translator_id() : - 1;
|
||||
$is_translator = $translator_id == $user_id
|
||||
|| ( $is_translator && empty( $translator_id ) );
|
||||
}
|
||||
}
|
||||
|
||||
return apply_filters( 'wpml_override_is_translator', $is_translator, $user_id, $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $user_id
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_language_pairs( $user_id ) {
|
||||
|
||||
return $this->sitepress->get_wp_api()
|
||||
->get_user_meta(
|
||||
$user_id,
|
||||
$this->sitepress->wpdb()->prefix . 'language_pairs',
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
$icl_ncp_plugins = array(
|
||||
'absolute-links/absolute-links-plugin.php',
|
||||
'cms-navigation/CMS-Navigation.php',
|
||||
);
|
||||
$active_plugins = get_option( 'active_plugins' );
|
||||
|
||||
$icl_ncp_plugins = $active_plugins ? array_intersect( $icl_ncp_plugins, $active_plugins ) : [];
|
||||
|
||||
if ( ! empty( $icl_ncp_plugins ) ) {
|
||||
$icl_sitepress_disabled = true;
|
||||
icl_suppress_activation();
|
||||
|
||||
|
||||
add_action( 'admin_notices', 'icl_incomp_plugins_warn' );
|
||||
function icl_incomp_plugins_warn() {
|
||||
global $icl_ncp_plugins;
|
||||
echo '<div class="error"><ul><li><strong>';
|
||||
esc_html_e( 'WPML cannot be activated together with these older plugins:', 'sitepress' );
|
||||
echo '<ul style="list-style:disc;margin:20px;">';
|
||||
foreach ( $icl_ncp_plugins as $incp ) {
|
||||
echo '<li>' . esc_html( $incp ) . '</li>';
|
||||
}
|
||||
echo '</ul>';
|
||||
esc_html_e( 'WPML will be deactivated', 'sitepress' );
|
||||
echo '</strong></li></ul></div>';
|
||||
}
|
||||
} else {
|
||||
$icl_sitepress_disabled = false;
|
||||
}
|
||||
|
||||
$filtered_page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_NULL_ON_FAILURE );
|
||||
if ( 0 === strcmp( $filtered_page, WPML_PLUGIN_FOLDER . '/menu/troubleshooting.php' ) || isset( $pagenow ) && $pagenow == 'index.php' ) {
|
||||
$icl_ncp_plugins2 = array(
|
||||
'wp-no-category-base/no-category-base.php',
|
||||
);
|
||||
$active_plugins = get_option( 'active_plugins' );
|
||||
$icl_ncp_plugins2 = array_intersect( $icl_ncp_plugins2, $active_plugins );
|
||||
if ( ! empty( $icl_ncp_plugins2 ) ) {
|
||||
if ( 0 === strcmp( $filtered_page, WPML_PLUGIN_FOLDER . '/menu/troubleshooting.php' ) ) {
|
||||
add_action( 'admin_notices', 'icl_incomp_plugins_warn2' );
|
||||
function icl_incomp_plugins_warn2() {
|
||||
global $icl_ncp_plugins2;
|
||||
echo '<a name="icl_inc_plugins_notice"></a><div class="error" style="padding:10px;">';
|
||||
esc_html_e( 'These plugins are known to have compatibiliy issues with WPML:', 'sitepress' );
|
||||
echo '<ul style="list-style:disc;margin-left:20px;">';
|
||||
foreach ( $icl_ncp_plugins2 as $incp ) {
|
||||
echo '<li>' . esc_html( $incp ) . '</li>';
|
||||
}
|
||||
echo '</ul>';
|
||||
echo '</div>';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/*
|
||||
* NextGen Gallery plugin integration.
|
||||
*
|
||||
* - Filters the_content
|
||||
* -- Adjusts gallery preview image URL from default to current language (2.0.66 <=)
|
||||
*/
|
||||
|
||||
class WPML_Plugin_Integration_Nexgen_Gallery {
|
||||
|
||||
|
||||
function __construct() {
|
||||
if ( defined( 'NEXTGEN_GALLERY_PLUGIN_VERSION' ) && version_compare( NEXTGEN_GALLERY_PLUGIN_VERSION, '2.0.66', '<=' ) ) {
|
||||
add_filter( 'the_content', array( 'WPML_Plugin_Integration_Nexgen_Gallery', 'the_content_gallery_preview_images' ), 1 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters post content and fixes gallery preview images URL.
|
||||
*
|
||||
* Adjust gallery preview image URL from default to current language.
|
||||
* Allows NextGen to match and replace preview images with gallery.
|
||||
* NextGen inserts image previews with default language URL.
|
||||
*
|
||||
* @global SitePress $sitepress
|
||||
* @param string $content
|
||||
* @return string
|
||||
*/
|
||||
public static function the_content_gallery_preview_images( $content ) {
|
||||
global $sitepress;
|
||||
if ( $sitepress->get_current_language() != $sitepress->get_default_language() ) {
|
||||
$default_url = preg_replace(
|
||||
'/(^http[s]?:\/\/)/',
|
||||
'',
|
||||
$sitepress->language_url( $sitepress->get_default_language() )
|
||||
);
|
||||
$current_url = preg_replace( '/(^http[s]?:\/\/)/', '', home_url() );
|
||||
$preview_url = $default_url . 'nextgen-attach_to_post/preview';
|
||||
$alt_preview_url = $default_url . 'index.php/nextgen-attach_to_post/preview';
|
||||
if ( preg_match_all( "#<img(.*)http(s)?://({$preview_url}|{$alt_preview_url})/id--(\\d+)(.*)\\/>#mi", $content, $matches, PREG_SET_ORDER ) ) {
|
||||
foreach ( $matches as $match ) {
|
||||
$content = str_replace( $match[0], "<img{$match[1]}http{$match[2]}://{$current_url}nextgen-attach_to_post/preview/id--{$match[4]}\"{$match[5]}/>", $content );
|
||||
}
|
||||
}
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$wpml_ngg = new WPML_Plugin_Integration_Nexgen_Gallery();
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
$action_filter_loader = new WPML_Action_Filter_Loader();
|
||||
$action_filter_loader->load(
|
||||
array(
|
||||
'WPML_Compatibility_Factory',
|
||||
)
|
||||
);
|
||||
|
||||
add_action( 'plugins_loaded', 'wpml_plugins_integration_setup', 10 );
|
||||
|
||||
/**
|
||||
* Loads compatibility classes for active plugins.
|
||||
*/
|
||||
function wpml_plugins_integration_setup() {
|
||||
global $sitepress, $wpdb;
|
||||
|
||||
$factories_to_load = [];
|
||||
|
||||
// bbPress integration.
|
||||
if ( class_exists( 'bbPress' ) ) {
|
||||
$wpml_bbpress_api = new WPML_BBPress_API();
|
||||
$wpml_bbpress_filters = new WPML_BBPress_Filters( $wpml_bbpress_api );
|
||||
$wpml_bbpress_filters->add_hooks();
|
||||
}
|
||||
|
||||
// NextGen Gallery.
|
||||
if ( defined( 'NEXTGEN_GALLERY_PLUGIN_VERSION' ) ) {
|
||||
// Todo: do not include files: move to autoloaded classes.
|
||||
require_once WPML_PLUGIN_PATH . '/inc/plugin-integration-nextgen.php';
|
||||
}
|
||||
|
||||
if ( class_exists( 'GoogleSitemapGeneratorLoader' ) ) {
|
||||
$wpml_google_sitemap_generator = new WPML_Google_Sitemap_Generator( $wpdb, $sitepress );
|
||||
$wpml_google_sitemap_generator->init_hooks();
|
||||
}
|
||||
|
||||
if ( class_exists( 'Tiny_Plugin' ) ) {
|
||||
$factories_to_load[] = 'WPML_Compatibility_Tiny_Compress_Images_Factory';
|
||||
}
|
||||
|
||||
// phpcs:disable WordPress.NamingConventions.ValidVariableName
|
||||
global $DISQUSVERSION;
|
||||
if ( $DISQUSVERSION ) {
|
||||
$factories_to_load[] = 'WPML_Compatibility_Disqus_Factory';
|
||||
}
|
||||
// phpcs:enable
|
||||
|
||||
if ( defined( 'GOOGLESITEKIT_VERSION' ) ) {
|
||||
$factories_to_load[] = \WPML\Compatibility\GoogleSiteKit\Hooks::class;
|
||||
}
|
||||
|
||||
$action_filter_loader = new WPML_Action_Filter_Loader();
|
||||
$action_filter_loader->load( $factories_to_load );
|
||||
}
|
||||
|
||||
add_action( 'after_setup_theme', 'wpml_themes_integration_setup' );
|
||||
|
||||
/**
|
||||
* Loads compatibility classes for active themes.
|
||||
*/
|
||||
function wpml_themes_integration_setup() {
|
||||
|
||||
$actions = [];
|
||||
|
||||
if ( function_exists( 'twentyseventeen_panel_count' ) && ! function_exists( 'twentyseventeen_translate_panel_id' ) ) {
|
||||
$wpml_twentyseventeen = new WPML_Compatibility_2017();
|
||||
$wpml_twentyseventeen->init_hooks();
|
||||
}
|
||||
|
||||
$action_filter_loader = new WPML_Action_Filter_Loader();
|
||||
$action_filter_loader->load( $actions );
|
||||
}
|
||||
|
||||
@@ -0,0 +1,290 @@
|
||||
<?php
|
||||
|
||||
use WPML\API\Sanitize;
|
||||
|
||||
/**
|
||||
* Class WPML_Admin_Post_Actions
|
||||
*
|
||||
* @package wpml-core
|
||||
* @subpackage post-translation
|
||||
*/
|
||||
class WPML_Admin_Post_Actions extends WPML_Post_Translation {
|
||||
|
||||
const DUPLICATE_MEDIA_META_KEY = '_wpml_media_duplicate';
|
||||
const DUPLICATE_FEATURED_META_KEY = '_wpml_media_featured';
|
||||
const DUPLICATE_MEDIA_GLOBAL_KEY = 'duplicate_media';
|
||||
const DUPLICATE_FEATURED_GLOBAL_KEY = 'duplicate_media';
|
||||
|
||||
private $http_referer;
|
||||
|
||||
public function init() {
|
||||
parent::init ();
|
||||
if ( $this->is_setup_complete() ) {
|
||||
add_action ( 'delete_post', array( $this, 'delete_post_actions' ) );
|
||||
add_action ( 'wp_trash_post', array( $this, 'trashed_post_actions' ) );
|
||||
add_action ( 'untrashed_post', array( $this, 'untrashed_post_actions' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
* @param string $post_status
|
||||
*
|
||||
* @return null|int
|
||||
*/
|
||||
function get_save_post_trid( $post_id, $post_status ) {
|
||||
$trid = $this->get_element_trid( $post_id );
|
||||
|
||||
if ( ! ( $this->is_inner_post_insertion() && $this->is_editing_different_post( $post_id ) ) ) {
|
||||
$trid = $trid ? $trid : filter_var( isset( $_POST['icl_trid'] ) ? $_POST['icl_trid'] : '', FILTER_SANITIZE_NUMBER_INT );
|
||||
$trid = $trid ? $trid : filter_var( isset( $_GET['trid'] ) ? $_GET['trid'] : '', FILTER_SANITIZE_NUMBER_INT );
|
||||
$trid = $trid ? $trid : $this->get_trid_from_referer();
|
||||
}
|
||||
|
||||
$trid = apply_filters( 'wpml_save_post_trid_value', $trid, $post_status );
|
||||
|
||||
return $trid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
* @param WP_Post $post
|
||||
*/
|
||||
public function save_post_actions( $post_id, $post ) {
|
||||
global $sitepress;
|
||||
|
||||
$this->defer_term_counting();
|
||||
if ( ! $post ) {
|
||||
$post = get_post( $post_id );
|
||||
}
|
||||
|
||||
// exceptions
|
||||
$http_referer = $this->get_http_referer();
|
||||
if ( ! $this->has_save_post_action( $post ) && ! $http_referer->is_rest_request_called_from_post_edit_page() ) {
|
||||
return;
|
||||
}
|
||||
if ( WPML_WordPress_Actions::is_bulk_trash( $post_id ) ||
|
||||
WPML_WordPress_Actions::is_bulk_untrash( $post_id ) ||
|
||||
$this->has_invalid_language_details_on_heartbeat()
|
||||
) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$default_language = $sitepress->get_default_language();
|
||||
$post_vars = $this->get_post_vars( $post );
|
||||
|
||||
if ( isset( $post_vars['action'] ) && $post_vars['action'] === 'post-quickpress-publish' ) {
|
||||
$language_code = $default_language;
|
||||
} else {
|
||||
if( isset( $post_vars['post_ID'] ) ){
|
||||
$post_id = $post_vars['post_ID'];
|
||||
}
|
||||
$language_code = $this->get_save_post_lang( $post_id, $sitepress );
|
||||
}
|
||||
|
||||
if ( $this->is_inline_action( $post_vars ) && ! ( $language_code = $this->get_element_lang_code(
|
||||
$post_id
|
||||
) )
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( isset( $post_vars['icl_translation_of'] ) && is_numeric( $post_vars['icl_translation_of'] ) ) {
|
||||
$translation_of_data_prepared = $this->wpdb->prepare(
|
||||
"SELECT trid, language_code
|
||||
FROM {$this->wpdb->prefix}icl_translations
|
||||
WHERE element_id=%d
|
||||
AND element_type=%s
|
||||
LIMIT 1",
|
||||
$post_vars['icl_translation_of'],
|
||||
'post_' . $post->post_type
|
||||
);
|
||||
list( $trid, $source_language ) = $this->wpdb->get_row( $translation_of_data_prepared, 'ARRAY_N' );
|
||||
}
|
||||
|
||||
if ( isset( $post_vars['icl_translation_of'] ) && $post_vars['icl_translation_of'] == 'none' ) {
|
||||
$trid = null;
|
||||
$source_language = $language_code;
|
||||
} else {
|
||||
$trid = isset( $trid ) && $trid ? $trid : $this->get_save_post_trid( $post_id, $post->post_status );
|
||||
// after getting the right trid set the source language from it by referring to the root translation
|
||||
// of this trid, in case no proper source language has been set yet
|
||||
$source_language = isset( $source_language )
|
||||
? $source_language : $this->get_save_post_source_lang( $trid, $language_code, $default_language );
|
||||
}
|
||||
if ( isset( $post_vars['icl_tn_note'] ) ) {
|
||||
update_post_meta( $post_id, '_icl_translator_note', $post_vars['icl_tn_note'] );
|
||||
}
|
||||
|
||||
$this->after_save_post( $trid, $post_vars, $language_code, $source_language );
|
||||
|
||||
if ( 'attachment' !== $post->post_type ) {
|
||||
$this->save_media_options( $post_id, $source_language );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
* @param string|null $source_language
|
||||
*/
|
||||
private function save_media_options( $post_id, $source_language ) {
|
||||
|
||||
if ( $this->has_post_media_options_metabox() ) {
|
||||
$original_post_id = isset( $_POST['icl_translation_of'] )
|
||||
? filter_var( $_POST['icl_translation_of'], FILTER_SANITIZE_NUMBER_INT ) : $post_id;
|
||||
$duplicate_media = isset( $_POST['wpml_duplicate_media'] )
|
||||
? filter_var( $_POST['wpml_duplicate_media'], FILTER_SANITIZE_NUMBER_INT ) : false;
|
||||
$duplicate_featured = isset( $_POST['wpml_duplicate_featured'] )
|
||||
? filter_var( $_POST['wpml_duplicate_featured'], FILTER_SANITIZE_NUMBER_INT ) : false;
|
||||
|
||||
update_post_meta( $original_post_id, self::DUPLICATE_MEDIA_META_KEY, (int) $duplicate_media );
|
||||
update_post_meta( $original_post_id, self::DUPLICATE_FEATURED_META_KEY, (int) $duplicate_featured );
|
||||
} else {
|
||||
$this->sync_media_options_with_original_or_global_settings( $post_id, $source_language );
|
||||
}
|
||||
}
|
||||
|
||||
private function has_post_media_options_metabox() {
|
||||
return array_key_exists( WPML_Meta_Boxes_Post_Edit_HTML::FLAG_HAS_MEDIA_OPTIONS, $_POST );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
* @param string|null $source_language
|
||||
*/
|
||||
private function sync_media_options_with_original_or_global_settings( $post_id, $source_language ) {
|
||||
global $sitepress;
|
||||
|
||||
$source_post_id = $sitepress->get_object_id( $post_id, get_post_type( $post_id ), false, $source_language );
|
||||
$is_translation = $source_post_id && $source_post_id !== $post_id;
|
||||
|
||||
foreach (
|
||||
array(
|
||||
self::DUPLICATE_FEATURED_META_KEY => self::DUPLICATE_FEATURED_GLOBAL_KEY,
|
||||
self::DUPLICATE_MEDIA_META_KEY => self::DUPLICATE_MEDIA_GLOBAL_KEY,
|
||||
) as $meta_key => $global_key
|
||||
) {
|
||||
|
||||
$source_value = get_post_meta( $source_post_id, $meta_key, true );
|
||||
|
||||
if ( '' === $source_value ) {
|
||||
// fallback to global setting
|
||||
$media_options = get_option( '_wpml_media', array() );
|
||||
|
||||
if ( isset( $media_options['new_content_settings'][ $global_key ] ) ) {
|
||||
$source_value = (int) $media_options['new_content_settings'][ $global_key ];
|
||||
|
||||
if ( $source_post_id ) {
|
||||
update_post_meta( $source_post_id, $meta_key, $source_value );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( '' !== $source_value && $is_translation ) {
|
||||
update_post_meta( $post_id, $meta_key, $source_value );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function has_invalid_language_details_on_heartbeat() {
|
||||
if ( ! WPML_WordPress_Actions::is_heartbeat() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( isset( $_POST['data']['icl_post_language'], $_POST['data']['icl_trid'] ) ) {
|
||||
$_POST['icl_post_language'] = Sanitize::string( $_POST['data']['icl_post_language'] );
|
||||
$_POST['icl_trid'] = filter_var( $_POST['data']['icl_trid'], FILTER_SANITIZE_NUMBER_INT );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $post_id
|
||||
* @param SitePress $sitepress
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function get_save_post_lang( $post_id, $sitepress ) {
|
||||
$language_code = null;
|
||||
if ( isset( $_POST['post_ID'] ) && (int) $_POST['post_ID'] === (int) $post_id ) {
|
||||
$language_code = filter_var(
|
||||
( isset( $_POST['icl_post_language'] ) ? $_POST['icl_post_language'] : '' ),
|
||||
FILTER_SANITIZE_FULL_SPECIAL_CHARS );
|
||||
}
|
||||
$language_code = $language_code
|
||||
? $language_code
|
||||
: filter_input(
|
||||
INPUT_GET,
|
||||
'lang',
|
||||
FILTER_SANITIZE_FULL_SPECIAL_CHARS
|
||||
);
|
||||
|
||||
return $language_code ? $language_code : parent::get_save_post_lang( $post_id, $sitepress );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $post_vars
|
||||
* @return bool
|
||||
*/
|
||||
private function is_inline_action( $post_vars ) {
|
||||
|
||||
return isset( $post_vars[ 'action' ] )
|
||||
&& $post_vars[ 'action' ] == 'inline-save'
|
||||
|| isset( $_GET[ 'bulk_edit' ] )
|
||||
|| isset( $_GET[ 'doing_wp_cron' ] )
|
||||
|| ( isset( $_GET[ 'action' ] )
|
||||
&& $_GET[ 'action' ] == 'untrash' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $trid
|
||||
* @param string $language_code
|
||||
* @param string $default_language
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
protected function get_save_post_source_lang( $trid, $language_code, $default_language ) {
|
||||
$source_language = filter_input ( INPUT_GET, 'source_lang', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
|
||||
$source_language = $source_language ? $source_language : $this->get_source_language_from_referer();
|
||||
$source_language = $source_language ? $source_language : SitePress::get_source_language_by_trid ( $trid );
|
||||
$source_language = $source_language === 'all' ? $default_language : $source_language;
|
||||
$source_language = $source_language !== $language_code ? $source_language : null;
|
||||
|
||||
return $source_language;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the source_language $_GET parameter from the HTTP_REFERER
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
private function get_source_language_from_referer() {
|
||||
if ( ! isset( $_SERVER['HTTP_REFERER'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$referer = $_SERVER['HTTP_REFERER'];
|
||||
$query = (string) wpml_parse_url( $referer, PHP_URL_QUERY );
|
||||
parse_str( $query, $query_parts );
|
||||
|
||||
return isset( $query_parts['source_lang'] ) ? $query_parts['source_lang'] : false;
|
||||
}
|
||||
|
||||
public function get_trid_from_referer() {
|
||||
$http_referer = $this->get_http_referer();
|
||||
return $http_referer->get_trid();
|
||||
}
|
||||
|
||||
protected function get_http_referer() {
|
||||
if ( ! $this->http_referer ) {
|
||||
$factory = new WPML_URL_HTTP_Referer_Factory();
|
||||
$this->http_referer = $factory->create();
|
||||
}
|
||||
|
||||
return $this->http_referer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
class WPML_Comment_Duplication{
|
||||
|
||||
public function move_to_original($duplicate_of, $post_duplicates, $comment){
|
||||
global $wpml_post_translations, $wpdb;
|
||||
|
||||
$_orig_lang = $wpml_post_translations->get_element_lang_code ( $duplicate_of );
|
||||
$post_duplicates[ $_orig_lang ] = $duplicate_of;
|
||||
$original_parent = get_comment_meta ( $comment[ 'comment_parent' ], '_icl_duplicate_of', true );
|
||||
$wpdb->update (
|
||||
$wpdb->comments,
|
||||
array(
|
||||
'comment_post_ID' => $duplicate_of,
|
||||
'comment_parent' => $original_parent
|
||||
), array( 'comment_ID' => $comment['comment_ID'] ), array( '%d', '%d' ), array( '%d' )
|
||||
);
|
||||
wp_update_comment_count_now($duplicate_of);
|
||||
}
|
||||
|
||||
public function get_correct_parent($comment, $dup_id){
|
||||
global $wpdb;
|
||||
|
||||
$translated_parent = $wpdb->get_var (
|
||||
$wpdb->prepare (
|
||||
" SELECT cmb.comment_id
|
||||
FROM {$wpdb->commentmeta} cm
|
||||
JOIN {$wpdb->commentmeta} cmb
|
||||
ON ( cmb.meta_value = cm.meta_value
|
||||
AND cmb.meta_key = cm.meta_key)
|
||||
OR cm.comment_id = cmb.meta_value
|
||||
JOIN {$wpdb->comments} c
|
||||
ON c.comment_ID = cmb.comment_id
|
||||
WHERE cm.meta_key = '_icl_duplicate_of'
|
||||
AND ( cm.comment_id = %d OR cm.meta_value = %d )
|
||||
AND c.comment_post_ID = %d",
|
||||
$comment[ 'comment_parent' ],
|
||||
$comment[ 'comment_parent' ],
|
||||
$dup_id
|
||||
)
|
||||
);
|
||||
|
||||
return $translated_parent;
|
||||
}
|
||||
|
||||
public function insert_duplicated_comment( $comment, $dup_id, $original_cid ) {
|
||||
global $wpdb, $iclTranslationManagement;
|
||||
$dup_comment_id = $this->duplicate_exists ( $dup_id, $original_cid );
|
||||
remove_action ( 'wp_insert_comment', array( $iclTranslationManagement, 'duplication_insert_comment' ), 100 );
|
||||
|
||||
if ( $dup_comment_id ) {
|
||||
$comment[ 'comment_ID' ] = $dup_comment_id;
|
||||
wp_update_comment ( $comment );
|
||||
} else {
|
||||
$wpdb->insert ( $wpdb->comments, $comment );
|
||||
$dup_comment_id = $wpdb->insert_id;
|
||||
|
||||
add_action ( 'wp_insert_comment', array( $iclTranslationManagement, 'duplication_insert_comment' ), 100 );
|
||||
update_comment_meta ( $dup_comment_id, '_icl_duplicate_of', $original_cid );
|
||||
// comment meta
|
||||
$meta = $wpdb->get_results (
|
||||
$wpdb->prepare (
|
||||
"SELECT meta_key, meta_value FROM {$wpdb->commentmeta} WHERE comment_id=%d",
|
||||
$original_cid
|
||||
)
|
||||
);
|
||||
foreach ( $meta as $meta_row ) {
|
||||
$wpdb->insert (
|
||||
$wpdb->commentmeta,
|
||||
array(
|
||||
'comment_id' => $dup_comment_id,
|
||||
'meta_key' => $meta_row->meta_key,
|
||||
'meta_value' => $meta_row->meta_value
|
||||
), array( '%d', '%s', '%s' )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
wp_update_comment_count_now ( $dup_id );
|
||||
}
|
||||
|
||||
private function duplicate_exists( $dup_id, $original_cid ) {
|
||||
global $wpdb;
|
||||
|
||||
$duplicate = $wpdb->get_var (
|
||||
$wpdb->prepare (
|
||||
" SELECT comm.comment_ID
|
||||
FROM {$wpdb->comments} comm
|
||||
JOIN {$wpdb->commentmeta} cm
|
||||
ON comm.comment_ID = cm.comment_id
|
||||
WHERE comm.comment_post_ID = %d
|
||||
AND cm.meta_key = '_icl_duplicate_of'
|
||||
AND cm.meta_value = %d
|
||||
LIMIT 1",
|
||||
$dup_id,
|
||||
$original_cid
|
||||
)
|
||||
);
|
||||
|
||||
return $duplicate;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Create_Post_Helper
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
class WPML_Create_Post_Helper {
|
||||
|
||||
/** @var SitePress $sitepress */
|
||||
private $sitepress;
|
||||
|
||||
public function __construct( SitePress $sitepress ) {
|
||||
$this->sitepress = $sitepress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $postarr will be escaped inside the method
|
||||
* @param string|null $lang
|
||||
* @param bool $wp_error
|
||||
*
|
||||
* @return int|WP_Error
|
||||
*/
|
||||
public function insert_post( array $postarr, $lang = null, $wp_error = false ) {
|
||||
$current_language = null;
|
||||
$postarr = $this->slash_and_preserve_tag_ids( $postarr );
|
||||
|
||||
if ( $lang ) {
|
||||
$current_language = $this->sitepress->get_current_language();
|
||||
$this->sitepress->switch_lang( $lang, false );
|
||||
}
|
||||
|
||||
if ( isset( $postarr['ID'] ) ) {
|
||||
$new_post_id = wp_update_post( $postarr, $wp_error );
|
||||
} else {
|
||||
add_filter( 'wp_insert_post_empty_content', array( $this, 'allow_empty_post' ), 10, 0 );
|
||||
$new_post_id = wp_insert_post( $postarr, $wp_error );
|
||||
remove_filter( 'wp_insert_post_empty_content', array( $this, 'allow_empty_post' ) );
|
||||
|
||||
}
|
||||
|
||||
if ( $current_language ) {
|
||||
$this->sitepress->switch_lang( $current_language, false );
|
||||
}
|
||||
|
||||
return $new_post_id;
|
||||
}
|
||||
|
||||
public function allow_empty_post() {
|
||||
return false; // We need to return false to indicate that the post is not empty
|
||||
}
|
||||
|
||||
/**
|
||||
* We need to make sure that tag IDs are not casted into strings.
|
||||
* This is a side effect of https://core.trac.wordpress.org/ticket/45121
|
||||
* (wp_update_post() can modify post tag) for which we have
|
||||
* a temporary fix in `\WPML_Page_Builders_Media_Shortcodes_Update::translate`.
|
||||
*
|
||||
* @param array $postarr
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function slash_and_preserve_tag_ids( array $postarr ) {
|
||||
if ( array_key_exists( 'tags_input', $postarr ) ) {
|
||||
$tagIds = array_filter( $postarr['tags_input'], 'is_int' );
|
||||
$postarr = wp_slash( $postarr );
|
||||
$postarr['tags_input'] = array_merge( $tagIds, $this->parse_tag( $postarr['tags_input'] ) );
|
||||
} else {
|
||||
$postarr = wp_slash( $postarr );
|
||||
}
|
||||
|
||||
return $postarr;
|
||||
}
|
||||
|
||||
private function parse_tag( $tags ) {
|
||||
if ( empty( $tags ) ) {
|
||||
$tags = array();
|
||||
}
|
||||
|
||||
if ( ! is_array( $tags ) ) {
|
||||
$comma = _x( ',', 'tag delimiter' );
|
||||
if ( ',' !== $comma ) {
|
||||
$tags = str_replace( $comma, ',', $tags );
|
||||
}
|
||||
$tags = explode( ',', trim( $tags, " \n\t\r\0\x0B," ) );
|
||||
}
|
||||
|
||||
return $tags;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
use WPML\LIB\WP\Hooks;
|
||||
|
||||
class WPML_Frontend_Post_Actions extends WPML_Post_Translation {
|
||||
|
||||
public function init() {
|
||||
parent::init ();
|
||||
if ( $this->is_setup_complete() ) {
|
||||
|
||||
/**
|
||||
* In theory, we could add the 'delete_post` action for all frontend requests
|
||||
* We'll limit it to REST to avoid any unexpected problems
|
||||
*/
|
||||
Hooks::onAction( 'rest_api_init' )
|
||||
->then( function () {
|
||||
add_action( 'delete_post', [ $this, 'delete_post_actions' ] );
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
* @param string $post_status
|
||||
*
|
||||
* @return null|int
|
||||
*/
|
||||
function get_save_post_trid( $post_id, $post_status ) {
|
||||
|
||||
return $this->get_element_trid( $post_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $pidd
|
||||
* @param WP_Post $post
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function save_post_actions( $pidd, $post ) {
|
||||
global $sitepress;
|
||||
|
||||
$this->defer_term_counting();
|
||||
if ( ! $post ) {
|
||||
$post = get_post( $pidd );
|
||||
}
|
||||
|
||||
$http_referer = new WPML_URL_HTTP_Referer( new WPML_Rest( new WP_Http() ) );
|
||||
// exceptions
|
||||
if ( ! $this->has_save_post_action( $post ) || $http_referer->is_rest_request_called_from_post_edit_page() ) {
|
||||
return;
|
||||
}
|
||||
$default_language = $sitepress->get_default_language();
|
||||
$post_vars = $this->get_post_vars( $post );
|
||||
$post_id = isset( $post_vars['post_ID'] ) ? $post_vars['post_ID']
|
||||
: $pidd; //latter case for XML-RPC publishing
|
||||
$language_code = $this->get_save_post_lang( $post_id, $sitepress );
|
||||
$trid = $this->get_save_post_trid( $post_id, $post->post_status );
|
||||
// after getting the right trid set the source language from it by referring to the root translation
|
||||
// of this trid, in case no proper source language has been set yet
|
||||
$source_language = $this->get_save_post_source_lang( $trid, $language_code, $default_language );
|
||||
$this->after_save_post( $trid, $post_vars, $language_code, $source_language );
|
||||
}
|
||||
|
||||
protected function get_save_post_source_lang( $trid, $language_code, $default_language ) {
|
||||
$post_id = $this->get_element_id ( $trid, $language_code );
|
||||
|
||||
return $post_id ? $this->get_source_lang_code ( $post_id ) : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,383 @@
|
||||
<?php
|
||||
|
||||
require_once dirname( __FILE__ ) . '/wpml-wordpress-actions.class.php';
|
||||
|
||||
/**
|
||||
* Class WPML_Post_Duplication
|
||||
*
|
||||
* @package wpml-core
|
||||
* @subpackage post-translation
|
||||
*/
|
||||
class WPML_Post_Duplication extends WPML_WPDB_And_SP_User {
|
||||
|
||||
function get_duplicates( $master_post_id ) {
|
||||
global $wpml_post_translations;
|
||||
$duplicates = array();
|
||||
|
||||
$post_ids_query = " SELECT post_id
|
||||
FROM {$this->wpdb->postmeta}
|
||||
WHERE meta_key='_icl_lang_duplicate_of'
|
||||
AND meta_value = %d
|
||||
AND post_id <> %d";
|
||||
$post_ids_prepare = $this->wpdb->prepare( $post_ids_query, array( $master_post_id, $master_post_id ) );
|
||||
$post_ids = $this->wpdb->get_col( $post_ids_prepare );
|
||||
foreach ( $post_ids as $post_id ) {
|
||||
$language_code = $wpml_post_translations->get_element_lang_code( $post_id );
|
||||
|
||||
if ( ! $language_code ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$duplicates[ $language_code ] = $post_id;
|
||||
}
|
||||
|
||||
return $duplicates;
|
||||
}
|
||||
|
||||
function make_duplicate( $master_post_id, $lang ) {
|
||||
global $wpml_post_translations;
|
||||
|
||||
/**
|
||||
* @deprecated Use 'wpml_before_make_duplicate' instead
|
||||
* @since 3.4
|
||||
*/
|
||||
do_action( 'icl_before_make_duplicate', $master_post_id, $lang );
|
||||
do_action( 'wpml_before_make_duplicate', $master_post_id, $lang );
|
||||
$master_post = get_post( $master_post_id );
|
||||
|
||||
if ( ! $master_post || $this->is_external( $master_post_id ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$is_duplicated = false;
|
||||
$translations = $wpml_post_translations->get_element_translations( $master_post_id, false, false );
|
||||
if ( isset( $translations[ $lang ] ) ) {
|
||||
$post_array[ 'ID' ] = $translations[ $lang ];
|
||||
if ( WPML_WordPress_Actions::is_bulk_trash( $post_array[ 'ID' ] ) || WPML_WordPress_Actions::is_bulk_untrash( $post_array[ 'ID' ] ) ) {
|
||||
return true;
|
||||
}
|
||||
$is_duplicated = get_post_meta( $translations[ $lang ], '_icl_lang_duplicate_of', true );
|
||||
}
|
||||
$post_array['post_author'] = $master_post->post_author;
|
||||
$post_array['post_date'] = $master_post->post_date;
|
||||
$post_array['post_date_gmt'] = $master_post->post_date_gmt;
|
||||
$duplicated_post_content = $this->duplicate_post_content( $lang, $master_post );
|
||||
$post_array['post_content'] = $duplicated_post_content;
|
||||
$duplicated_post_title = $this->duplicate_post_title( $lang, $master_post );
|
||||
$post_array['post_title'] = $duplicated_post_title;
|
||||
$duplicated_post_excerpt = $this->duplicate_post_excerpt( $lang, $master_post );
|
||||
$post_array['post_excerpt'] = $duplicated_post_excerpt;
|
||||
if ( $this->sitepress->get_setting('sync_post_status' ) ) {
|
||||
$sync_post_status = true;
|
||||
} else {
|
||||
$sync_post_status = ( ! isset( $post_array[ 'ID' ] )
|
||||
|| ( $this->sitepress->get_setting( 'sync_delete' ) && $master_post->post_status === 'trash' ) || $is_duplicated );
|
||||
}
|
||||
if ( $sync_post_status || ( isset( $post_array[ 'ID' ] ) && get_post_status( $post_array[ 'ID' ] ) === 'auto-draft' ) ) {
|
||||
$post_array[ 'post_status' ] = $master_post->post_status;
|
||||
}
|
||||
$post_array[ 'comment_status' ] = $master_post->comment_status;
|
||||
$post_array[ 'ping_status' ] = $master_post->ping_status;
|
||||
$post_array[ 'post_name' ] = $master_post->post_name;
|
||||
if ( $master_post->post_parent ) {
|
||||
$parent = $this->sitepress->get_object_id( $master_post->post_parent, $master_post->post_type, false, $lang );
|
||||
$post_array[ 'post_parent' ] = $parent;
|
||||
}
|
||||
$post_array['menu_order'] = $master_post->menu_order;
|
||||
$post_array['post_type'] = $master_post->post_type;
|
||||
$post_array['post_mime_type'] = $master_post->post_mime_type;
|
||||
$trid = $this->sitepress->get_element_trid( $master_post->ID,
|
||||
'post_' . $master_post->post_type );
|
||||
$id = $this->save_duplicate( $post_array, $lang );
|
||||
|
||||
require_once WPML_PLUGIN_PATH . '/inc/cache.php';
|
||||
icl_cache_clear();
|
||||
|
||||
global $ICL_Pro_Translation;
|
||||
/** @var WPML_Pro_Translation $ICL_Pro_Translation */
|
||||
if ( $ICL_Pro_Translation ) {
|
||||
$ICL_Pro_Translation->fix_links_to_translated_content( $id, $lang );
|
||||
}
|
||||
if ( ! is_wp_error( $id ) ) {
|
||||
$ret = $this->run_wpml_actions( $master_post, $trid, $lang, $id, $post_array );
|
||||
} else {
|
||||
throw new Exception( $id->get_error_message() );
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $element_id
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
private function is_external( $element_id ) {
|
||||
$query = "SELECT element_type FROM {$this->wpdb->prefix}icl_translations WHERE element_id=%d AND element_type LIKE %s LIMIT 1";
|
||||
|
||||
return ! $this->wpdb->get_var( $this->wpdb->prepare( $query, $element_id, 'post_%' ) );
|
||||
}
|
||||
|
||||
private function run_wpml_actions( $master_post, $trid, $lang, $id, $post_array ) {
|
||||
$master_post_id = $master_post->ID;
|
||||
$this->sitepress->set_element_language_details( $id, 'post_' . $master_post->post_type, $trid, $lang );
|
||||
$this->sync_duplicate_password( $master_post_id, $id );
|
||||
$this->sync_page_template( $master_post_id, $id );
|
||||
$this->duplicate_fix_children( $master_post_id, $lang );
|
||||
|
||||
// make sure post name is copied
|
||||
$this->wpdb->update( $this->wpdb->posts, array( 'post_name' => $master_post->post_name ), array( 'ID' => $id ) );
|
||||
|
||||
if ( $this->sitepress->get_setting( 'sync_post_taxonomies', false ) ) {
|
||||
$this->duplicate_taxonomies( $master_post_id, $lang );
|
||||
}
|
||||
$this->duplicate_custom_fields( $master_post_id, $lang );
|
||||
update_post_meta( $id, '_icl_lang_duplicate_of', $master_post->ID );
|
||||
|
||||
// Duplicate post format after the taxonomies because post format is stored
|
||||
// as a taxonomy by WP.
|
||||
if ( $this->sitepress->get_setting( 'sync_post_format' ) ) {
|
||||
$_wp_post_format = get_post_format( $master_post_id );
|
||||
set_post_format( $id, $_wp_post_format );
|
||||
}
|
||||
if ( $this->sitepress->get_setting( 'sync_comments_on_duplicates' ) ) {
|
||||
$this->duplicate_comments( $master_post_id, $id );
|
||||
}
|
||||
$status_helper = wpml_get_post_status_helper();
|
||||
$status_helper->set_status( $id, ICL_TM_DUPLICATE );
|
||||
$status_helper->set_update_status( $id, false );
|
||||
do_action( 'icl_make_duplicate', $master_post_id, $lang, $post_array, $id );
|
||||
clean_post_cache( $id );
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
private function sync_page_template( $master_post_id, $duplicate_post_id ) {
|
||||
$_wp_page_template = get_post_meta( $master_post_id, '_wp_page_template', true );
|
||||
if ( ! empty( $_wp_page_template ) ) {
|
||||
update_post_meta( $duplicate_post_id, '_wp_page_template', $_wp_page_template );
|
||||
}
|
||||
}
|
||||
|
||||
private function duplicate_comments( $master_post_id, $translated_id ) {
|
||||
global $sitepress;
|
||||
|
||||
remove_filter( 'comments_clauses', array( $sitepress, 'comments_clauses' ), 10 );
|
||||
$comments_on_master = get_comments( array( 'post_id' => $master_post_id ) );
|
||||
$comments_on_translation = get_comments( array( 'post_id' => $translated_id, 'status' => 'any' ) );
|
||||
add_filter( 'comments_clauses', array( $sitepress, 'comments_clauses' ), 10, 2 );
|
||||
foreach ( $comments_on_translation as $comment ) {
|
||||
wp_delete_comment( $comment->comment_ID, true );
|
||||
clean_comment_cache( $comment->comment_ID );
|
||||
}
|
||||
$iclTranslationManagement = wpml_load_core_tm();
|
||||
foreach ( $comments_on_master as $comment ) {
|
||||
$iclTranslationManagement->duplication_insert_comment( $comment->comment_ID );
|
||||
clean_comment_cache( $comment->comment_ID );
|
||||
}
|
||||
|
||||
wp_update_comment_count_now( $master_post_id );
|
||||
wp_update_comment_count_now( $translated_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $post_array
|
||||
* @param string $lang
|
||||
*
|
||||
* @return int|WP_Error
|
||||
*/
|
||||
private function save_duplicate( array $post_array, $lang ) {
|
||||
return wpml_get_create_post_helper()->insert_post( $post_array, $lang, true );
|
||||
}
|
||||
|
||||
private function duplicate_fix_children( $master_post_id, $lang ) {
|
||||
$post_type = $this->wpdb->get_var(
|
||||
$this->wpdb->prepare( "SELECT post_type FROM {$this->wpdb->posts} WHERE ID=%d", $master_post_id )
|
||||
);
|
||||
$master_children = $this->wpdb->get_col(
|
||||
$this->wpdb->prepare(
|
||||
"SELECT ID FROM {$this->wpdb->posts} WHERE post_parent=%d AND post_type != 'revision'",
|
||||
$master_post_id
|
||||
)
|
||||
);
|
||||
$dup_parent = icl_object_id( $master_post_id, $post_type, false, $lang );
|
||||
if ( $master_children ) {
|
||||
foreach ( $master_children as $master_child ) {
|
||||
$dup_child = icl_object_id( $master_child, $post_type, false, $lang );
|
||||
if ( $dup_child ) {
|
||||
$this->wpdb->update( $this->wpdb->posts, array( 'post_parent' => $dup_parent ), array( 'ID' => $dup_child ) );
|
||||
}
|
||||
$this->duplicate_fix_children( $master_child, $lang );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function duplicate_taxonomies( $master_post_id, $lang ) {
|
||||
$post_type = get_post_field( 'post_type', $master_post_id );
|
||||
$taxonomies = get_object_taxonomies( $post_type );
|
||||
$trid = $this->sitepress->get_element_trid( $master_post_id, 'post_' . $post_type );
|
||||
if ( $trid ) {
|
||||
$translations = $this->sitepress->get_element_translations( $trid, 'post_' . $post_type, false, false, true );
|
||||
if ( isset( $translations[ $lang ] ) ) {
|
||||
$duplicate_post_id = $translations[ $lang ]->element_id;
|
||||
/* If we have an existing post, we first of all remove all terms currently attached to it.
|
||||
* The main reason behind is the removal of the potentially present default category on the post.
|
||||
*/
|
||||
wp_delete_object_term_relationships( $duplicate_post_id, $taxonomies );
|
||||
} else {
|
||||
return false; // translation not found!
|
||||
}
|
||||
}
|
||||
$term_helper = wpml_get_term_translation_util();
|
||||
$term_helper->duplicate_terms( $master_post_id, $lang );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function sync_duplicate_password( $master_post_id, $duplicate_post_id ) {
|
||||
if ( post_password_required( $master_post_id ) ) {
|
||||
$sql = $this->wpdb->prepare( "UPDATE {$this->wpdb->posts} AS dupl,
|
||||
(SELECT org.post_password FROM {$this->wpdb->posts} AS org WHERE ID = %d ) AS pwd
|
||||
SET dupl.post_password = pwd.post_password
|
||||
WHERE dupl.ID = %d",
|
||||
array( $master_post_id, $duplicate_post_id ) );
|
||||
$this->wpdb->query( $sql );
|
||||
}
|
||||
}
|
||||
|
||||
private function duplicate_custom_fields( $master_post_id, $lang ) {
|
||||
$duplicate_post_id = false;
|
||||
$post_type = get_post_field( 'post_type', $master_post_id );
|
||||
|
||||
$trid = $this->sitepress->get_element_trid( $master_post_id, 'post_' . $post_type );
|
||||
if ( $trid ) {
|
||||
$translations = $this->sitepress->get_element_translations( $trid, 'post_' . $post_type );
|
||||
if ( isset( $translations[ $lang ] ) ) {
|
||||
$duplicate_post_id = $translations[ $lang ]->element_id;
|
||||
} else {
|
||||
return false; // translation not found!
|
||||
}
|
||||
}
|
||||
$default_exceptions = WPML_Config::get_custom_fields_translation_settings();
|
||||
$exceptions = apply_filters( 'wpml_duplicate_custom_fields_exceptions', array() );
|
||||
$exceptions = array_merge( $exceptions, $default_exceptions );
|
||||
$exceptions = array_unique( $exceptions );
|
||||
|
||||
$exceptions_in = ! empty( $exceptions )
|
||||
? 'AND meta_key NOT IN ( ' . wpml_prepare_in( $exceptions ) . ') ' : '';
|
||||
$from_where_string = "FROM {$this->wpdb->postmeta} WHERE post_id = %d " . $exceptions_in;
|
||||
$post_meta_master = $this->wpdb->get_results( "SELECT meta_key, meta_value " . $this->wpdb->prepare( $from_where_string,
|
||||
$master_post_id ) );
|
||||
$this->wpdb->query( "DELETE " . $this->wpdb->prepare( $from_where_string, $duplicate_post_id ) );
|
||||
|
||||
$values = [];
|
||||
foreach ( $post_meta_master as $post_meta ) {
|
||||
$is_serialized = is_serialized( $post_meta->meta_value );
|
||||
$meta_data = array(
|
||||
'context' => 'custom_field',
|
||||
'attribute' => 'value',
|
||||
'key' => $post_meta->meta_key,
|
||||
'is_serialized' => $is_serialized,
|
||||
'post_id' => $duplicate_post_id,
|
||||
'master_post_id' => $master_post_id,
|
||||
);
|
||||
|
||||
/**
|
||||
* @deprecated use 'wpml_duplicate_generic_string' instead, with the same arguments
|
||||
*/
|
||||
$icl_duplicate_generic_string = apply_filters( 'icl_duplicate_generic_string',
|
||||
$post_meta->meta_value,
|
||||
$lang,
|
||||
$meta_data );
|
||||
$post_meta->meta_value = $icl_duplicate_generic_string;
|
||||
$wpml_duplicate_generic_string = apply_filters( 'wpml_duplicate_generic_string',
|
||||
$post_meta->meta_value,
|
||||
$lang,
|
||||
$meta_data );
|
||||
$post_meta->meta_value = $wpml_duplicate_generic_string;
|
||||
if ( ! is_serialized( $post_meta->meta_value ) ) {
|
||||
$post_meta->meta_value = maybe_serialize( $post_meta->meta_value );
|
||||
}
|
||||
|
||||
$values[] = $this->wpdb->prepare(
|
||||
'( %d, %s, %s )',
|
||||
$duplicate_post_id,
|
||||
$post_meta->meta_key,
|
||||
$post_meta->meta_value
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! empty( $values ) ) {
|
||||
$values = implode( ', ', $values );
|
||||
$this->wpdb->query(
|
||||
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
"INSERT INTO `{$this->wpdb->postmeta}` (`post_id`, `meta_key`, `meta_value`) VALUES {$values}"
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $lang
|
||||
* @param \WP_Post $master_post
|
||||
*
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
private function duplicate_post_content( $lang, $master_post ) {
|
||||
$duplicated_post_content_meta = array(
|
||||
'context' => 'post',
|
||||
'attribute' => 'content',
|
||||
'key' => $master_post->ID
|
||||
);
|
||||
$duplicated_post_content = $master_post->post_content;
|
||||
$duplicated_post_content = apply_filters( 'icl_duplicate_generic_string', $duplicated_post_content, $lang, $duplicated_post_content_meta );
|
||||
$duplicated_post_content = apply_filters( 'wpml_duplicate_generic_string', $duplicated_post_content, $lang, $duplicated_post_content_meta );
|
||||
|
||||
return $duplicated_post_content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $lang
|
||||
* @param \WP_Post $master_post
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function duplicate_post_title( $lang, $master_post ) {
|
||||
$duplicated_post_title_meta = array(
|
||||
'context' => 'post',
|
||||
'attribute' => 'title',
|
||||
'key' => $master_post->ID
|
||||
);
|
||||
$duplicated_post_title = $master_post->post_title;
|
||||
$duplicated_post_title = apply_filters( 'icl_duplicate_generic_string', $duplicated_post_title, $lang, $duplicated_post_title_meta );
|
||||
$duplicated_post_title = apply_filters( 'wpml_duplicate_generic_string', $duplicated_post_title, $lang, $duplicated_post_title_meta );
|
||||
|
||||
return $duplicated_post_title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $lang
|
||||
* @param WP_Post $master_post
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function duplicate_post_excerpt( $lang, $master_post ) {
|
||||
$duplicated_post_excerpt_meta = array(
|
||||
'context' => 'post',
|
||||
'attribute' => 'excerpt',
|
||||
'key' => $master_post->ID
|
||||
);
|
||||
$duplicated_post_excerpt = $master_post->post_excerpt;
|
||||
$duplicated_post_excerpt = apply_filters( 'icl_duplicate_generic_string',
|
||||
$duplicated_post_excerpt,
|
||||
$lang,
|
||||
$duplicated_post_excerpt_meta );
|
||||
$duplicated_post_excerpt = apply_filters( 'wpml_duplicate_generic_string',
|
||||
$duplicated_post_excerpt,
|
||||
$lang,
|
||||
$duplicated_post_excerpt_meta );
|
||||
|
||||
return $duplicated_post_excerpt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
class WPML_Post_Hierarchy_Sync extends WPML_Hierarchy_Sync {
|
||||
|
||||
protected $element_id_column = 'ID';
|
||||
protected $parent_element_id_column = 'ID';
|
||||
protected $parent_id_column = 'post_parent';
|
||||
protected $element_type_column = 'post_type';
|
||||
protected $element_type_prefix = 'post_';
|
||||
|
||||
/**
|
||||
* @param wpdb $wpdb
|
||||
*/
|
||||
public function __construct( &$wpdb ) {
|
||||
parent::__construct( $wpdb );
|
||||
$this->elements_table = $wpdb->posts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $element_type
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_hierarchical( $element_type ) {
|
||||
return is_post_type_hierarchical( $element_type );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,364 @@
|
||||
<?php
|
||||
|
||||
use WPML\FP\Lst;
|
||||
use WPML\FP\Maybe;
|
||||
use WPML\FP\Obj;
|
||||
use function WPML\FP\partial;
|
||||
|
||||
/**
|
||||
* Class WPML_Post_Synchronization
|
||||
*
|
||||
* @package wpml-core
|
||||
* @subpackage post-translation
|
||||
*/
|
||||
|
||||
class WPML_Post_Synchronization extends WPML_SP_And_PT_User {
|
||||
|
||||
/** @var bool[] */
|
||||
private $sync_parent_cpt = array();
|
||||
/** @var bool $sync_parent */
|
||||
private $sync_parent;
|
||||
/** @var bool $sync_delete */
|
||||
private $sync_delete;
|
||||
/** @var bool $sync_ping_status */
|
||||
private $sync_ping_status;
|
||||
/** @var bool $sync_post_date */
|
||||
private $sync_post_date;
|
||||
/** @var bool $sync_post_format */
|
||||
private $sync_post_format;
|
||||
/** @var bool $sync_comment_status */
|
||||
private $sync_comment_status;
|
||||
/** @var bool $sync_page_template */
|
||||
private $sync_page_template;
|
||||
/** @var bool $sync_menu_order */
|
||||
private $sync_menu_order;
|
||||
/** @var bool $sync_password */
|
||||
private $sync_password;
|
||||
/** @var bool $sync_private_flag */
|
||||
private $sync_private_flag;
|
||||
/** @var bool $is_deleting_all_translations */
|
||||
private $is_deleting_all_translations = false;
|
||||
/** @var array $deleted_post_types */
|
||||
private $deleted_post_types = array();
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $sync_document_status;
|
||||
|
||||
/**
|
||||
* @param array $settings
|
||||
* @param WPML_Post_Translation $post_translations
|
||||
* @param SitePress $sitepress
|
||||
*/
|
||||
public function __construct( &$settings, &$post_translations, &$sitepress ) {
|
||||
parent::__construct( $post_translations, $sitepress );
|
||||
$this->sync_delete = isset( $settings[ 'sync_delete' ] ) ? $settings[ 'sync_delete' ] : false;
|
||||
$this->sync_parent = isset( $settings[ 'sync_page_parent' ] ) ? $settings[ 'sync_page_parent' ] : false;
|
||||
$this->sync_ping_status = isset( $settings[ 'sync_ping_status' ] ) ? $settings[ 'sync_ping_status' ] : false;
|
||||
$this->sync_post_date = isset( $settings[ 'sync_post_date' ] ) ? $settings[ 'sync_post_date' ] : false;
|
||||
$this->sync_post_format = isset( $settings[ 'sync_post_format' ] ) ? $settings[ 'sync_post_format' ] : false;
|
||||
$this->sync_comment_status = isset( $settings[ 'sync_comment_status' ] ) ? $settings[ 'sync_comment_status' ] : false;
|
||||
$this->sync_page_template = isset( $settings[ 'sync_page_template' ] ) ? $settings[ 'sync_page_template' ] : false;
|
||||
$this->sync_password = isset( $settings[ 'sync_password' ] ) ? $settings[ 'sync_password' ] : false;
|
||||
$this->sync_private_flag = isset( $settings[ 'sync_private_flag' ] ) ? $settings[ 'sync_private_flag' ] : false;
|
||||
$this->sync_document_status = isset( $settings[ 'translated_document_status' ] ) ? $settings[ 'translated_document_status' ] : 1;
|
||||
$this->sync_menu_order = isset( $settings[ 'sync_page_ordering' ] ) ? $settings[ 'sync_page_ordering' ] : array();
|
||||
}
|
||||
|
||||
private function must_sync_parents( $post_type ) {
|
||||
if ( ! array_key_exists( $post_type, $this->sync_parent_cpt ) ) {
|
||||
$this->sync_parent_cpt[ $post_type ] = apply_filters( 'wpml_sync_parent_for_post_type', $this->sync_parent, $post_type );
|
||||
}
|
||||
|
||||
return $this->sync_parent_cpt[ $post_type ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes parents of translations for hierarchical post types
|
||||
*
|
||||
* User changed parent for a post in $post_type and we are setting proper parent for $translation_id in
|
||||
* $language_code_translated language
|
||||
*
|
||||
* @param string $post_type - post_type that should have the translated parents fixed
|
||||
*/
|
||||
private function maybe_fix_translated_parent( $post_type ) {
|
||||
if ( $this->must_sync_parents( $post_type ) ) {
|
||||
$sync_helper = wpml_get_hierarchy_sync_helper();
|
||||
$sync_helper->sync_element_hierarchy( $post_type );
|
||||
}
|
||||
}
|
||||
|
||||
public function sync_with_duplicates( $post_id ) {
|
||||
$duplicates = $this->sitepress->get_duplicates( $post_id );
|
||||
foreach ( array_keys( $duplicates ) as $lang_code ) {
|
||||
$this->sitepress->make_duplicate( $post_id, $lang_code );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
* @param bool $keep_db_entries
|
||||
*/
|
||||
public function delete_post_actions( $post_id, $keep_db_entries = false ) {
|
||||
$post_type = get_post_type( $post_id );
|
||||
$post_type_exceptions = array( 'nav_menu_item' );
|
||||
if ( in_array( $post_type, $post_type_exceptions ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$trid = null;
|
||||
if ( ! $this->is_deleting_all_translations ) {
|
||||
$this->is_deleting_all_translations = ! $this->post_translation->get_original_element( $post_id, true );
|
||||
$trid = $this->post_translation->get_element_trid( $post_id );
|
||||
$translated_ids = $this->get_translations_without_source( $post_id, $trid );
|
||||
if ( $this->sync_delete || Lst::includes( $post_type, [ 'wp_template', 'wp_template_part' ] ) ) {
|
||||
$this->delete_translations( $translated_ids, $keep_db_entries );
|
||||
}
|
||||
$this->is_deleting_all_translations = false;
|
||||
}
|
||||
|
||||
if ( ! $keep_db_entries ) {
|
||||
$this->post_translation->delete_post_translation_entry( $post_id );
|
||||
|
||||
if ( $trid && ! $this->is_deleting_all_translations ) {
|
||||
$lang_code = $this->post_translation->get_element_lang_code( $post_id );
|
||||
$this->set_new_original( $trid, $lang_code );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $this->is_deleting_all_translations ) {
|
||||
$this->run_final_actions_for_delete_post( $post_type );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
* @param int $trid
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_translations_without_source( $post_id, $trid ) {
|
||||
$actual_translations_only = ! $this->is_deleting_all_translations;
|
||||
$translated_ids = $this->post_translation->get_element_translations( $post_id, $trid, $actual_translations_only );
|
||||
unset( $translated_ids[ array_search( $post_id, $translated_ids ) ] );
|
||||
return $translated_ids;
|
||||
}
|
||||
|
||||
private function is_bulk_delete() {
|
||||
return ( isset( $_REQUEST['action'] ) && 'delete' === $_REQUEST['action']
|
||||
|| isset( $_REQUEST['action2'] ) && 'delete' === $_REQUEST['action2']
|
||||
) && ( isset( $_REQUEST['post'] ) && is_array( $_REQUEST['post'] )
|
||||
|| isset( $_REQUEST['media'] ) && is_array( $_REQUEST['media'] )
|
||||
);
|
||||
}
|
||||
|
||||
/** @param string $post_type */
|
||||
private function reset_cache( $post_type ) {
|
||||
require_once WPML_PLUGIN_PATH . '/inc/cache.php';
|
||||
icl_cache_clear( $post_type . 's_per_language', true );
|
||||
}
|
||||
|
||||
/** @param string $post_type */
|
||||
private function defer_delete_actions( $post_type ) {
|
||||
if ( ! in_array( $post_type, $this->deleted_post_types, true ) ) {
|
||||
$this->deleted_post_types[] = $post_type;
|
||||
if ( ! has_action( 'shutdown', array( $this, 'shutdown_action' ) ) ) {
|
||||
add_action( 'shutdown', array( $this, 'shutdown_action' ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function shutdown_action() {
|
||||
$this->post_translation->reload();
|
||||
|
||||
foreach ( $this->deleted_post_types as $post_type ) {
|
||||
$this->reset_cache( $post_type );
|
||||
$this->maybe_fix_translated_parent( $post_type );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $translated_ids
|
||||
* @param bool $keep_db_entries
|
||||
*/
|
||||
private function delete_translations( array $translated_ids, $keep_db_entries ) {
|
||||
if ( ! empty( $translated_ids ) ) {
|
||||
foreach ( $translated_ids as $trans_id ) {
|
||||
if ( ! $this->is_bulk_prevented( $trans_id ) ) {
|
||||
if ( $keep_db_entries ) {
|
||||
$this->post_translation->trash_translation( $trans_id );
|
||||
} else {
|
||||
wp_delete_post( $trans_id, true );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @param string $post_type */
|
||||
private function run_final_actions_for_delete_post( $post_type ) {
|
||||
if ( $this->is_bulk_delete() ) {
|
||||
$this->defer_delete_actions( $post_type );
|
||||
} else {
|
||||
$this->post_translation->reload();
|
||||
$this->reset_cache( $post_type );
|
||||
$this->maybe_fix_translated_parent( $post_type );
|
||||
}
|
||||
}
|
||||
|
||||
private function is_bulk_prevented( $post_id ) {
|
||||
|
||||
return ( isset( $_GET[ 'delete_all' ] ) && $_GET[ 'delete_all' ] === 'Empty Trash' )
|
||||
|| in_array( $post_id, ( isset( $_GET[ 'ids' ] ) ? $_GET[ 'ids' ] : array() ) );
|
||||
}
|
||||
|
||||
function untrashed_post_actions( $post_id ) {
|
||||
if ( $this->sync_delete ) {
|
||||
$translations = $this->post_translation->get_element_translations( $post_id, false, true );
|
||||
foreach ( $translations as $t_id ) {
|
||||
$this->post_translation->untrash_translation( $t_id );
|
||||
}
|
||||
}
|
||||
$post_type = get_post_type( $post_id );
|
||||
require_once WPML_PLUGIN_PATH . '/inc/cache.php';
|
||||
icl_cache_clear( $post_type . 's_per_language', true );
|
||||
}
|
||||
|
||||
public function sync_with_translations( $post_id, $post_vars = false ) {
|
||||
global $wpdb;
|
||||
|
||||
$wp_api = $this->sitepress->get_wp_api();
|
||||
$term_count_update = new WPML_Update_Term_Count( $wp_api );
|
||||
|
||||
$post = get_post ( $post_id );
|
||||
$source_post_status = $this->get_post_status( $post_id );
|
||||
$translated_ids = $this->post_translation->get_element_translations( $post_id, false, true );
|
||||
$post_format = $this->sync_post_format ? get_post_format( $post_id ) : null;
|
||||
$ping_status = $this->sync_ping_status ? ( pings_open( $post_id ) ? 'open' : 'closed' ) : null;
|
||||
$comment_status = $this->sync_comment_status ? ( comments_open( $post_id ) ? 'open' : 'closed' ) : null;
|
||||
$post_password = $this->sync_password ? $post->post_password : null;
|
||||
$menu_order = $this->sync_menu_order && ! empty( $post->menu_order ) ? $post->menu_order : null;
|
||||
$page_template = $this->sync_page_template && get_post_type( $post_id ) === 'page' ? get_post_meta( $post_id, '_wp_page_template', true ) : null;
|
||||
$post_date = $this->sync_post_date ? $wpdb->get_var( $wpdb->prepare( "SELECT post_date FROM {$wpdb->posts} WHERE ID=%d LIMIT 1", $post_id ) ) : null;
|
||||
|
||||
foreach ( $translated_ids as $lang_code => $translated_pid ) {
|
||||
$post_status = $this->get_post_status( $translated_pid );
|
||||
|
||||
$post_status_differs = ( 'private' === $source_post_status && 'publish' === $post_status )
|
||||
|| ( 'publish' === $source_post_status && 'private' === $post_status );
|
||||
if ( $this->sync_private_flag && $post_status_differs ) {
|
||||
$post_status = $source_post_status;
|
||||
}
|
||||
|
||||
$this->sync_custom_fields ( $post_id, $translated_pid );
|
||||
if ( $post_format ) {
|
||||
set_post_format ( $translated_pid, $post_format );
|
||||
}
|
||||
if ( $post_date !== null ) {
|
||||
$post_date_gmt = get_gmt_from_date ( $post_date );
|
||||
$data = array( 'post_date' => $post_date, 'post_date_gmt' => $post_date_gmt );
|
||||
$now = gmdate('Y-m-d H:i:59');
|
||||
$allow_post_statuses = array( 'private', 'pending', 'draft' );
|
||||
if ( mysql2date('U', $post_date_gmt, false) > mysql2date('U', $now, false) ) {
|
||||
if ( ! in_array( $post_status, $allow_post_statuses, true ) ) {
|
||||
$post_status = 'future';
|
||||
}
|
||||
}
|
||||
$data[ 'post_status' ] = $post_status;
|
||||
$wpdb->update ( $wpdb->posts, $data, array( 'ID' => $translated_pid ) );
|
||||
wp_schedule_single_event( strtotime( $post_date_gmt . '+1 second' ), 'publish_future_post', array( $translated_pid ) );
|
||||
}
|
||||
if ( $post_password !== null ) {
|
||||
$wpdb->update ( $wpdb->posts, array( 'post_password' => $post_password ), array( 'ID' => $translated_pid ) );
|
||||
}
|
||||
if ( $post_status !== null && ! in_array( $this->get_post_status( $translated_pid ), array( 'auto-draft', 'draft', 'inherit', 'trash' ) ) ) {
|
||||
$wpdb->update ( $wpdb->posts, array( 'post_status' => $post_status ), array( 'ID' => $translated_pid ) );
|
||||
$term_count_update->update_for_post( $translated_pid );
|
||||
} elseif ( $post_status == null && $this->sync_private_flag && $this->get_post_status( $translated_pid ) === 'private' ) {
|
||||
$wpdb->update ( $wpdb->posts, array( 'post_status' => $this->get_post_status( $post_id ) ), array( 'ID' => $translated_pid ) );
|
||||
$term_count_update->update_for_post( $translated_pid );
|
||||
}
|
||||
if ( $ping_status !== null ) {
|
||||
$wpdb->update ( $wpdb->posts, array( 'ping_status' => $ping_status ), array( 'ID' => $translated_pid ) );
|
||||
}
|
||||
if ( $comment_status !== null ) {
|
||||
$wpdb->update ( $wpdb->posts, array( 'comment_status' => $comment_status ), array( 'ID' => $translated_pid ) );
|
||||
}
|
||||
if ( $page_template !== null ) {
|
||||
update_post_meta ( $translated_pid, '_wp_page_template', $page_template );
|
||||
}
|
||||
$this->sync_with_translations ( $translated_pid );
|
||||
}
|
||||
$this->maybe_fix_translated_parent( get_post_type( $post_id ) );
|
||||
|
||||
if ( $menu_order !== null && (bool) $translated_ids !== false ) {
|
||||
$query = $wpdb->prepare(
|
||||
"UPDATE {$wpdb->posts}
|
||||
SET menu_order=%s
|
||||
WHERE ID IN (" . wpml_prepare_in( $translated_ids, '%d' ) . ')',
|
||||
$menu_order
|
||||
);
|
||||
$wpdb->query( $query );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The function `get_post_status` does not return the raw status for attachments.
|
||||
* As we are running direct DB updates here, we need the actual DB value.
|
||||
*
|
||||
* @param int $post_id
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
private function get_post_status( $post_id ) {
|
||||
$isAttachment = function( $post_id ) { return 'attachment' === get_post_type( $post_id ); };
|
||||
|
||||
return Maybe::of( $post_id )
|
||||
->filter( $isAttachment )
|
||||
->map( 'get_post' )
|
||||
->map( Obj::prop( 'post_status' ) )
|
||||
->getOrElse( partial( 'get_post_status', $post_id ) );
|
||||
}
|
||||
|
||||
private function sync_custom_fields( $original_id, $post_id ) {
|
||||
if ( $original_id && $original_id != $post_id ) {
|
||||
$this->sitepress->copy_custom_fields ( $original_id, $post_id );
|
||||
} else {
|
||||
$translations = $this->post_translation->get_element_translations ( $post_id, false, true );
|
||||
foreach ( $translations as $t_id ) {
|
||||
$this->sitepress->copy_custom_fields ( $post_id, $t_id );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function set_new_original( $trid, $removed_lang_code ) {
|
||||
if ( $trid && $removed_lang_code ) {
|
||||
$priorities = $this->sitepress->get_setting( 'languages_order' );
|
||||
$this->post_translation->reload();
|
||||
$translations = $this->post_translation->get_element_translations( false, $trid );
|
||||
$new_source_lang_code = false;
|
||||
foreach ( $priorities as $lang_code ) {
|
||||
if ( isset( $translations[ $lang_code ] ) ) {
|
||||
$new_source_lang_code = $lang_code;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( $new_source_lang_code ) {
|
||||
global $wpdb;
|
||||
|
||||
$rows_updated = $wpdb->update( $wpdb->prefix . 'icl_translations',
|
||||
array( 'source_language_code' => $new_source_lang_code ),
|
||||
array( 'trid' => $trid, 'source_language_code' => $removed_lang_code )
|
||||
);
|
||||
|
||||
if( 0 < $rows_updated ) {
|
||||
do_action( 'wpml_translation_update', array( 'trid' => $trid ) );
|
||||
}
|
||||
|
||||
$wpdb->query( " UPDATE {$wpdb->prefix}icl_translations
|
||||
SET source_language_code = NULL
|
||||
WHERE language_code = source_language_code" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,442 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Post_Translation
|
||||
*
|
||||
* @package wpml-core
|
||||
* @subpackage post-translation
|
||||
*/
|
||||
abstract class WPML_Post_Translation extends WPML_Element_Translation {
|
||||
|
||||
protected $settings;
|
||||
protected $post_translation_sync;
|
||||
public static $defer_term_counting = false;
|
||||
|
||||
/**
|
||||
* @var WPML_Debug_BackTrace
|
||||
*/
|
||||
private $debug_backtrace;
|
||||
|
||||
/**
|
||||
* @param array $settings
|
||||
* @param wpdb $wpdb
|
||||
*/
|
||||
public function __construct( &$settings, &$wpdb ) {
|
||||
parent::__construct( $wpdb );
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
protected function is_setup_complete( ) {
|
||||
return isset( $this->settings[ 'setup_complete' ]) && $this->settings[ 'setup_complete' ];
|
||||
}
|
||||
|
||||
public function init() {
|
||||
if ( $this->is_setup_complete() ) {
|
||||
add_action( 'save_post', [ $this, 'save_post_actions' ], 100, 2 );
|
||||
add_action( 'shutdown', [ $this, 'shutdown_action' ], PHP_INT_MAX );
|
||||
add_action( 'edit_attachment', [ $this, 'attachment_actions' ], 100 );
|
||||
add_action( 'add_attachment', [ $this, 'attachment_actions' ], 100 );
|
||||
}
|
||||
}
|
||||
|
||||
public function get_original_post_status( $trid, $source_lang_code = null ) {
|
||||
|
||||
return $this->get_original_post_attr ( $trid, 'post_status', $source_lang_code );
|
||||
}
|
||||
|
||||
public function get_original_post_ID( $trid, $source_lang_code = null ) {
|
||||
|
||||
return $this->get_original_post_attr ( $trid, 'ID', $source_lang_code );
|
||||
}
|
||||
|
||||
public function get_original_menu_order
|
||||
( $trid, $source_lang_code = null ) {
|
||||
|
||||
return $this->get_original_post_attr ( $trid, 'menu_order', $source_lang_code );
|
||||
}
|
||||
|
||||
public function get_original_comment_status( $trid, $source_lang_code = null ) {
|
||||
|
||||
return $this->get_original_post_attr ( $trid, 'comment_status', $source_lang_code );
|
||||
}
|
||||
|
||||
public function get_original_ping_status( $trid, $source_lang_code = null ) {
|
||||
|
||||
return $this->get_original_post_attr ( $trid, 'ping_status', $source_lang_code );
|
||||
}
|
||||
|
||||
public function get_original_post_format( $trid, $source_lang_code = null ) {
|
||||
|
||||
return get_post_format ( $this->get_original_post_ID ( $trid, $source_lang_code ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $pidd
|
||||
* @param WP_Post $post
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public abstract function save_post_actions( $pidd, $post );
|
||||
|
||||
/** @param int $post_id */
|
||||
public function attachment_actions( $post_id ) {
|
||||
/**
|
||||
* This filter hooks determines whether we should apply the
|
||||
* "save_post" actions on an attachment.
|
||||
*
|
||||
* @since 4.4.0
|
||||
*
|
||||
* @param bool True if we should apply save post actions on the attachment, false otherwise (default false).
|
||||
* @param int $post_id The attachment post ID.
|
||||
*/
|
||||
if ( apply_filters( 'wpml_apply_save_attachment_actions', false, $post_id ) ) {
|
||||
$post = get_post( $post_id );
|
||||
|
||||
if ( $post ) {
|
||||
$this->save_post_actions( $post_id, $post );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function shutdown_action() {
|
||||
if ( self::$defer_term_counting ) {
|
||||
self::$defer_term_counting = false;
|
||||
wp_defer_term_counting( false );
|
||||
}
|
||||
}
|
||||
|
||||
public function trash_translation ( $trans_id ) {
|
||||
if ( !WPML_WordPress_Actions::is_bulk_trash( $trans_id ) ) {
|
||||
wp_trash_post( $trans_id );
|
||||
}
|
||||
}
|
||||
|
||||
public function untrash_translation( $trans_id ) {
|
||||
if ( ! WPML_WordPress_Actions::is_bulk_untrash( $trans_id ) ) {
|
||||
wp_untrash_post( $trans_id );
|
||||
}
|
||||
}
|
||||
|
||||
function untrashed_post_actions( $post_id ) {
|
||||
$translation_sync = $this->get_sync_helper ();
|
||||
$translation_sync->untrashed_post_actions ( $post_id );
|
||||
}
|
||||
|
||||
public function delete_post_translation_entry( $post_id ) {
|
||||
|
||||
$update_args = array( 'context' => 'post', 'element_id' => $post_id );
|
||||
do_action( 'wpml_translation_update', array_merge( $update_args, array( 'type' => 'before_delete' ) ) );
|
||||
|
||||
$sql = $this->wpdb->prepare( "DELETE FROM {$this->wpdb->prefix}icl_translations
|
||||
WHERE element_id = %d
|
||||
AND element_type LIKE 'post%%'
|
||||
LIMIT 1",
|
||||
$post_id );
|
||||
$res = $this->wpdb->query( $sql );
|
||||
|
||||
do_action( 'wpml_translation_update', array_merge( $update_args, array( 'type' => 'after_delete' ) ) );
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function trashed_post_actions( $post_id ) {
|
||||
$this->delete_post_actions( $post_id, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* This function holds all actions to be run after deleting a post.
|
||||
* 1. Delete the posts entry in icl_translations.
|
||||
* 2. Set one of the posts translations or delete all translations of the post, depending on sitepress settings.
|
||||
*
|
||||
* @param Integer $post_id
|
||||
* @param bool $keep_db_entries Sets whether icl_translations entries are to be deleted or kept, when hooking this to
|
||||
* post trashing we want them to be kept.
|
||||
*/
|
||||
public function delete_post_actions( $post_id, $keep_db_entries = false ) {
|
||||
$translation_sync = $this->get_sync_helper ();
|
||||
$translation_sync->delete_post_actions ( $post_id, $keep_db_entries );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
* @param string $post_status
|
||||
*
|
||||
* @return null|int
|
||||
*/
|
||||
abstract function get_save_post_trid( $post_id, $post_status );
|
||||
|
||||
/**
|
||||
* @param integer $post_id
|
||||
* @param SitePress $sitepress
|
||||
* @return bool|mixed|null|string|void
|
||||
*/
|
||||
public function get_save_post_lang( $post_id, $sitepress ) {
|
||||
$language_code = $this->get_element_lang_code ( $post_id );
|
||||
$language_code = $language_code ? $language_code : $sitepress->get_current_language ();
|
||||
$language_code = $sitepress->is_active_language ( $language_code ) ? $language_code
|
||||
: $sitepress->get_default_language ();
|
||||
|
||||
return apply_filters ( 'wpml_save_post_lang', $language_code );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $trid
|
||||
* @param string $language_code
|
||||
* @param string $default_language
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected abstract function get_save_post_source_lang( $trid, $language_code, $default_language );
|
||||
|
||||
/**
|
||||
* Sets a posts language details, invalidates caches relating to the post and triggers
|
||||
* synchronisation actions across translations of the just saved post.
|
||||
*
|
||||
* @param int $trid
|
||||
* @param array $post_vars
|
||||
* @param string $language_code
|
||||
* @param string $source_language
|
||||
*
|
||||
* @used-by \WPML_Post_Translation::save_post_actions as final step of the WPML Core save_post actions
|
||||
*/
|
||||
protected function after_save_post( $trid, $post_vars, $language_code, $source_language ) {
|
||||
$this->maybe_set_elid( $trid, $post_vars['post_type'], $language_code, $post_vars['ID'], $source_language );
|
||||
$translation_sync = $this->get_sync_helper();
|
||||
$original_id = $this->get_original_element( $post_vars['ID'] );
|
||||
$translation_sync->sync_with_translations( $original_id ? $original_id : $post_vars['ID'], $post_vars );
|
||||
$translation_sync->sync_with_duplicates( $post_vars['ID'] );
|
||||
if ( ! function_exists( 'icl_cache_clear' ) ) {
|
||||
require_once WPML_PLUGIN_PATH . '/inc/cache.php';
|
||||
}
|
||||
icl_cache_clear( $post_vars['post_type'] . 's_per_language', true );
|
||||
if ( ! in_array( $post_vars['post_type'], array( 'nav_menu_item', 'attachment' ), true ) ) {
|
||||
do_action( 'wpml_tm_save_post', $post_vars['ID'], get_post( $post_vars['ID'] ), false );
|
||||
}
|
||||
// Flush object cache.
|
||||
$this->flush_object_cache_for_groups( array( 'ls_languages', 'element_translations' ) );
|
||||
|
||||
do_action( 'wpml_after_save_post', $post_vars['ID'], $trid, $language_code, $source_language );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new instance of WPML_WP_Cache for each group and flush cache for group.
|
||||
* @param array $groups
|
||||
*/
|
||||
private function flush_object_cache_for_groups( $groups = array() ) {
|
||||
if ( ! empty( $groups ) ) {
|
||||
foreach ( $groups as $group ) {
|
||||
$cache = new WPML_WP_Cache( $group );
|
||||
$cache->flush_group_cache();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function get_original_post_attr( $trid, $attribute, $source_lang_code ) {
|
||||
$legal_attributes = array(
|
||||
'post_status',
|
||||
'post_date',
|
||||
'menu_order',
|
||||
'comment_status',
|
||||
'ping_status',
|
||||
'ID'
|
||||
);
|
||||
$res = false;
|
||||
if ( in_array ( $attribute, $legal_attributes, true ) ) {
|
||||
$attribute = 'p.' . $attribute;
|
||||
$source_snippet = $source_lang_code === null
|
||||
? " AND wpml_translations.source_language_code IS NULL "
|
||||
: $this->wpdb->prepare ( " AND wpml_translations.language_code = %s ", $source_lang_code );
|
||||
$res = $this->wpdb->get_var (
|
||||
$this->wpdb->prepare (
|
||||
"SELECT {$attribute}
|
||||
" . $this->get_element_join() . "
|
||||
WHERE wpml_translations.trid=%d
|
||||
{$source_snippet}
|
||||
LIMIT 1",
|
||||
$trid
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function has_save_post_action( $post ) {
|
||||
if ( ! $post ) {
|
||||
return false;
|
||||
}
|
||||
$is_auto_draft = isset( $post->post_status ) && $post->post_status === 'auto-draft';
|
||||
$is_editing_different_post = $this->is_editing_different_post( $post->ID );
|
||||
$is_saving_a_revision = array_key_exists( 'post_type', $_POST ) && 'revision' === $_POST['post_type'];
|
||||
$is_untrashing = array_key_exists( 'action', $_GET ) && 'untrash' === $_GET['action'];
|
||||
$is_auto_save = array_key_exists( 'autosave', $_POST );
|
||||
$skip_sitepress_actions = array_key_exists( 'skip_sitepress_actions', $_POST );
|
||||
$is_post_a_revision = 'revision' === $post->post_type;
|
||||
$is_scheduled_to_be_trashed = get_post_meta( $post->ID, '_wp_trash_meta_status', true );
|
||||
$is_add_meta_action = isset( $_POST['action'] ) && 'add-meta' === $_POST['action'];
|
||||
$is_inner_post_insertion = $this->is_inner_post_insertion();
|
||||
|
||||
return $this->is_translated_type( $post->post_type )
|
||||
&& ! ( $is_auto_draft
|
||||
|| $is_auto_save
|
||||
|| $skip_sitepress_actions
|
||||
|| ( $is_editing_different_post && ! $is_inner_post_insertion )
|
||||
|| $is_saving_a_revision
|
||||
|| $is_post_a_revision
|
||||
|| $is_scheduled_to_be_trashed
|
||||
|| $is_add_meta_action
|
||||
|| $is_untrashing );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_editing_different_post( $post_id ) {
|
||||
return array_key_exists( 'post_ID', $_POST ) && (int) $_POST['post_ID'] && $post_id != $_POST['post_ID'];
|
||||
}
|
||||
|
||||
protected function get_element_join() {
|
||||
|
||||
return "FROM {$this->wpdb->prefix}icl_translations wpml_translations
|
||||
JOIN {$this->wpdb->posts} p
|
||||
ON wpml_translations.element_id = p.ID
|
||||
AND wpml_translations.element_type = CONCAT('post_', p.post_type)";
|
||||
}
|
||||
|
||||
protected function get_type_prefix() {
|
||||
return 'post_';
|
||||
}
|
||||
|
||||
|
||||
public function is_translated_type( $post_type ) {
|
||||
global $sitepress;
|
||||
|
||||
return $sitepress->is_translated_post_type ( $post_type );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_Post $post
|
||||
*
|
||||
* @return string[] all language codes the post can be translated into
|
||||
*/
|
||||
public function get_allowed_target_langs( $post ) {
|
||||
global $sitepress;
|
||||
|
||||
$active_languages = $sitepress->get_active_languages ();
|
||||
$can_translate = array_keys ( $active_languages );
|
||||
$can_translate = array_diff (
|
||||
$can_translate,
|
||||
array( $this->get_element_lang_code ( $post->ID ) )
|
||||
);
|
||||
|
||||
return apply_filters ( 'wpml_allowed_target_langs', $can_translate, $post->ID, 'post' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Before setting the language of the post to be saved, check if a translation in this language already exists
|
||||
* This check is necessary, so that synchronization actions like thrashing or un-trashing of posts, do not lead to
|
||||
* database corruption, due to erroneously changing a posts language into a state,
|
||||
* where it collides with an existing translation. While the UI prevents this sort of action for the most part,
|
||||
* this is not necessarily the case for other plugins like TM.
|
||||
* The logic here first of all checks if an existing translation id is present in the desired language_code.
|
||||
* If so but this translation is actually not the currently to be saved post,
|
||||
* then this post will be saved to its current language. If the translation already exists,
|
||||
* the existing translation id will be used. In all other cases a new entry in icl_translations will be created.
|
||||
*
|
||||
* @param Integer $trid
|
||||
* @param String $post_type
|
||||
* @param String $language_code
|
||||
* @param Integer $post_id
|
||||
* @param String $source_language
|
||||
*/
|
||||
private function maybe_set_elid( $trid, $post_type, $language_code, $post_id, $source_language ) {
|
||||
global $sitepress;
|
||||
|
||||
$element_type = 'post_' . $post_type;
|
||||
$sitepress->set_element_language_details (
|
||||
$post_id,
|
||||
$element_type,
|
||||
$trid,
|
||||
$language_code,
|
||||
$source_language
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_Post_Synchronization
|
||||
*/
|
||||
private function get_sync_helper() {
|
||||
global $sitepress;
|
||||
|
||||
$this->post_translation_sync = $this->post_translation_sync
|
||||
? $this->post_translation_sync : new WPML_Post_Synchronization( $this->settings, $this, $sitepress );
|
||||
|
||||
return $this->post_translation_sync;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_Debug_BackTrace
|
||||
*/
|
||||
private function get_debug_backtrace() {
|
||||
if ( ! $this->debug_backtrace ) {
|
||||
$this->debug_backtrace = new WPML\Utils\DebugBackTrace( 20 );
|
||||
}
|
||||
|
||||
return $this->debug_backtrace;
|
||||
}
|
||||
|
||||
public function set_debug_backtrace( WPML_Debug_BackTrace $debug_backtrace ) {
|
||||
$this->debug_backtrace = $debug_backtrace;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_inner_post_insertion() {
|
||||
$debug_backtrace = $this->get_debug_backtrace();
|
||||
return 1 < $debug_backtrace->count_function_in_call_stack( 'wp_insert_post' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_Post $post
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_post_vars( $post ) {
|
||||
$post_vars = array();
|
||||
|
||||
if ( ! $this->is_inner_post_insertion() ) {
|
||||
$post_vars = (array) $_POST;
|
||||
}
|
||||
|
||||
foreach ( (array) $post as $k => $v ) {
|
||||
$post_vars[ $k ] = $v;
|
||||
}
|
||||
|
||||
$post_vars['post_type'] = isset( $post_vars['post_type'] ) ? $post_vars['post_type'] : $post->post_type;
|
||||
|
||||
return $post_vars;
|
||||
}
|
||||
|
||||
protected function defer_term_counting() {
|
||||
if ( ! self::$defer_term_counting ) {
|
||||
self::$defer_term_counting = true;
|
||||
wp_defer_term_counting( true );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return self|WPML_Frontend_Post_Actions|WPML_Admin_Post_Actions
|
||||
*/
|
||||
public static function getGlobalInstance() {
|
||||
global $wpml_post_translations, $sitepress;
|
||||
|
||||
if ( ! isset( $wpml_post_translations ) ) {
|
||||
wpml_load_post_translation( is_admin(), $sitepress->get_settings() );
|
||||
}
|
||||
|
||||
return $wpml_post_translations;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
<?php
|
||||
|
||||
class WPML_Root_Page_Actions {
|
||||
|
||||
/** @var array $sp_settings */
|
||||
private $sp_settings;
|
||||
|
||||
public function __construct( &$sitepress_settings ) {
|
||||
$this->sp_settings = &$sitepress_settings;
|
||||
}
|
||||
|
||||
public function delete_root_page_lang() {
|
||||
global $wpdb;
|
||||
$root_id = $this->get_root_page_id ();
|
||||
|
||||
if ( $root_id ) {
|
||||
|
||||
$update_args = array(
|
||||
'element_id' => $root_id,
|
||||
'element_type' => 'post_page',
|
||||
'context' => 'post'
|
||||
);
|
||||
|
||||
do_action( 'wpml_translation_update', array_merge( $update_args, array( 'type' => 'before_delete' ) ) );
|
||||
|
||||
$wpdb->delete (
|
||||
$wpdb->prefix . 'icl_translations', array( 'element_id' => $root_id, 'element_type' => 'post_page' ), array( '%d', '%s' )
|
||||
);
|
||||
|
||||
do_action( 'wpml_translation_update', array_merge( $update_args, array( 'type' => 'after_delete' ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given $url points at the root page
|
||||
*
|
||||
* @param string $url
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @uses \WPML_Root_Page::is_root_page
|
||||
*/
|
||||
public function is_url_root_page( $url ) {
|
||||
$ret = false;
|
||||
|
||||
if ( $this->get_root_page_id() ) {
|
||||
$ret = WPML_Root_Page::is_root_page( $url );
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a page is used as the root page, returns the id of that page, otherwise false.
|
||||
*
|
||||
* @return bool|false|int
|
||||
*/
|
||||
public function get_root_page_id() {
|
||||
$urls_in_dirs = isset($this->sp_settings['language_negotiation_type']) && (int)$this->sp_settings['language_negotiation_type'] === 1;
|
||||
$urls = isset( $this->sp_settings['urls'] ) ? $this->sp_settings['urls'] : array();
|
||||
|
||||
return $urls_in_dirs && isset( $urls['root_page'] )
|
||||
&& ! empty( $urls['directory_for_default_language'] )
|
||||
&& isset( $urls['show_on_root'] )
|
||||
&& $urls['show_on_root'] === 'page'
|
||||
&& $urls['root_page']
|
||||
? $urls['root_page'] : false;
|
||||
}
|
||||
|
||||
function wpml_home_url_init() {
|
||||
global $pagenow, $sitepress;
|
||||
|
||||
if ( $pagenow == 'post.php' || $pagenow == 'post-new.php' ) {
|
||||
|
||||
$root_id = $this->get_root_page_id();
|
||||
if ( ! empty( $_GET['wpml_root_page'] ) && ! empty( $root_id ) ) {
|
||||
$rp = get_post( $root_id );
|
||||
if ( $rp && $rp->post_status != 'trash' ) {
|
||||
wp_redirect( get_edit_post_link( $root_id, 'no-display' ) );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( $_GET['wpml_root_page'] ) && $_GET['wpml_root_page'] || ( isset( $_GET['post'] ) && $_GET['post'] == $root_id ) ) {
|
||||
remove_action( 'admin_head', array( $sitepress, 'post_edit_language_options' ) );
|
||||
add_action( 'admin_head', array( $this, 'wpml_home_url_language_box_setup' ) );
|
||||
remove_action( 'page_link', array( $sitepress, 'permalink_filter' ), 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function wpml_home_url_exclude_root_page_from_menus( $args ) {
|
||||
if ( !empty( $args[ 'exclude' ] ) ) {
|
||||
$args[ 'exclude' ] .= ',';
|
||||
} else {
|
||||
$args[ 'exclude' ] = '';
|
||||
}
|
||||
$args[ 'exclude' ] .= $this->get_root_page_id();
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters out all page menu items that point to the root page.
|
||||
*
|
||||
* @param object[] $items
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @hook wp_get_nav_menu_items
|
||||
*/
|
||||
function exclude_root_page_menu_item( $items ) {
|
||||
$root_id = $this->get_root_page_id();
|
||||
foreach ( $items as $key => $item ) {
|
||||
if ( isset( $item->object_id )
|
||||
&& isset( $item->type )
|
||||
&& $item->object_id == $root_id
|
||||
&& $item->type === 'post_type'
|
||||
) {
|
||||
unset( $items[ $key ] );
|
||||
}
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
function wpml_home_url_exclude_root_page( $excludes ) {
|
||||
$excludes[ ] = $this->get_root_page_id();
|
||||
|
||||
return $excludes;
|
||||
|
||||
}
|
||||
|
||||
function wpml_home_url_exclude_root_page2( $args ) {
|
||||
$args[ 'exclude' ][ ] = $this->get_root_page_id();
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
function wpml_home_url_get_pages( $pages ) {
|
||||
$root_id = $this->get_root_page_id();
|
||||
foreach ( $pages as $k => $page ) {
|
||||
if ( $page->ID == $root_id ) {
|
||||
unset( $pages[ $k ] );
|
||||
$pages = array_values ( $pages );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $pages;
|
||||
}
|
||||
|
||||
function wpml_home_url_language_box_setup() {
|
||||
add_meta_box(
|
||||
WPML_Meta_Boxes_Post_Edit_HTML::WRAPPER_ID,
|
||||
__( 'Language', 'sitepress' ),
|
||||
array( $this, 'wpml_home_url_language_box' ),
|
||||
'page',
|
||||
/**
|
||||
* Filter meta box position.
|
||||
*
|
||||
* The context within the screen where the boxes should display. Available contexts vary from screen to screen.
|
||||
* Post edit screen contexts include 'normal', 'side', and 'advanced'.
|
||||
*
|
||||
* @param String WPML_Meta_Boxes_Post_Edit_HTML::WRAPPER_ID Meta box ID.
|
||||
*
|
||||
* @since 4.2.8
|
||||
*
|
||||
*/
|
||||
apply_filters( 'wpml_post_edit_meta_box_context', 'side', WPML_Meta_Boxes_Post_Edit_HTML::WRAPPER_ID ),
|
||||
apply_filters( 'wpml_post_edit_meta_box_priority', 'high' )
|
||||
);
|
||||
}
|
||||
|
||||
function wpml_home_url_language_box( $post ) {
|
||||
$root_id = $this->get_root_page_id();
|
||||
if ( isset( $_GET[ 'wpml_root_page' ] )
|
||||
|| ( !empty( $root_id )
|
||||
&& $post->ID == $root_id ) ) {
|
||||
_e ( "This page does not have a language since it's the site's root page." );
|
||||
echo '<input type="hidden" name="_wpml_root_page" value="1" />';
|
||||
}
|
||||
}
|
||||
|
||||
function wpml_home_url_save_post_actions( $pidd, $post ) {
|
||||
global $sitepress, $wpdb, $iclTranslationManagement;
|
||||
|
||||
if ( (bool) filter_input ( INPUT_POST, '_wpml_root_page' ) === true ) {
|
||||
|
||||
if ( isset( $_POST[ 'autosave' ] ) || ( isset( $post->post_type ) && $post->post_type == 'revision' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$iclsettings[ 'urls' ][ 'root_page' ] = $post->ID;
|
||||
$sitepress->save_settings ( $iclsettings );
|
||||
|
||||
remove_action( 'save_post', array( $sitepress, 'save_post_actions' ), 10 );
|
||||
|
||||
if ( !is_null ( $iclTranslationManagement ) ) {
|
||||
remove_action( 'save_post', array( $iclTranslationManagement, 'save_post_actions' ), 11 );
|
||||
}
|
||||
|
||||
$update_args = array(
|
||||
'element_id' => $post->ID,
|
||||
'element_type' => 'post_page',
|
||||
'context' => 'post'
|
||||
);
|
||||
|
||||
do_action( 'wpml_translation_update', array_merge( $update_args, array( 'type' => 'before_delete' ) ) );
|
||||
|
||||
$wpdb->query (
|
||||
$wpdb->prepare (
|
||||
"DELETE FROM {$wpdb->prefix}icl_translations WHERE element_type='post_page' AND element_id=%d",
|
||||
$post->ID
|
||||
)
|
||||
);
|
||||
|
||||
do_action( 'wpml_translation_update', array_merge( $update_args, array( 'type' => 'after_delete' ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
function wpml_home_url_setup_root_page() {
|
||||
global $sitepress, $wpml_query_filter;
|
||||
|
||||
remove_action( 'template_redirect', 'redirect_canonical' );
|
||||
add_action( 'parse_query', array( $this, 'wpml_home_url_parse_query' ) );
|
||||
|
||||
remove_filter( 'posts_join', array( $wpml_query_filter, 'posts_join_filter' ), 10 );
|
||||
remove_filter( 'posts_where', array( $wpml_query_filter, 'posts_where_filter' ), 10 );
|
||||
$root_id = $this->get_root_page_id();
|
||||
$rp = get_post( $root_id );
|
||||
if ( $rp && $rp->post_status != 'trash' ) {
|
||||
$sitepress->ROOT_URL_PAGE_ID = $root_id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_Query $q
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function wpml_home_url_parse_query( $q ) {
|
||||
if ( ! $q->is_main_query() ) {
|
||||
return $q;
|
||||
}
|
||||
if ( ! WPML_Root_Page::is_current_request_root() ) {
|
||||
return $q;
|
||||
} else {
|
||||
remove_action( 'parse_query', array( $this, 'wpml_home_url_parse_query' ) );
|
||||
|
||||
$uri_path = trim( wpml_parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH ), '/' );
|
||||
$uri_parts = explode( '/', $uri_path );
|
||||
$potential_pagination_parameter = array_pop( $uri_parts );
|
||||
|
||||
$query_args = array();
|
||||
wp_parse_str( wpml_parse_url( $_SERVER['REQUEST_URI'], PHP_URL_QUERY ), $query_args );
|
||||
|
||||
if ( is_numeric( $potential_pagination_parameter ) ) {
|
||||
$query_args['page'] = $potential_pagination_parameter;
|
||||
}
|
||||
|
||||
$q->parse_query( $query_args );
|
||||
$root_id = $this->get_root_page_id();
|
||||
add_action( 'parse_query', array( $this, 'wpml_home_url_parse_query' ) );
|
||||
|
||||
if ( false !== $root_id ) {
|
||||
$q = $this->set_page_query_parameters( $q, $root_id );
|
||||
} else {
|
||||
$front_page = get_option( 'page_on_front' );
|
||||
if ( $front_page ) {
|
||||
$q = $this->set_page_query_parameters( $q, $front_page );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $q;
|
||||
}
|
||||
|
||||
private function set_page_query_parameters( $q, $page_id ) {
|
||||
$q->query_vars['page_id'] = $page_id;
|
||||
$q->query['page_id'] = $page_id;
|
||||
$q->is_page = 1;
|
||||
$q->queried_object = new WP_Post( get_post( $page_id ) );
|
||||
$q->queried_object_id = $page_id;
|
||||
$q->query_vars['error'] = '';
|
||||
$q->is_404 = false;
|
||||
$q->query['error'] = null;
|
||||
$q->is_home = false;
|
||||
$q->is_singular = true;
|
||||
|
||||
return $q;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the language switcher is to be displayed.
|
||||
* Used to check if the displayed page is a root page and the switcher is to be hidden because of it.
|
||||
*
|
||||
* @return bool true if the switcher is to be hidden
|
||||
*/
|
||||
function wpml_home_url_ls_hide_check() {
|
||||
global $sitepress;
|
||||
|
||||
return $sitepress->get_setting( 'language_negotiation_type' ) == 1
|
||||
&& (bool) ( $urls = $sitepress->get_setting( 'urls' ) ) === true
|
||||
&& ! empty( $urls['directory_for_default_language'] )
|
||||
&& isset( $urls['show_on_root'] ) && $urls['show_on_root'] === 'page'
|
||||
&& ! empty( $urls['hide_language_switchers'] )
|
||||
&& WPML_Root_Page::is_current_request_root();
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_WordPress_Actions
|
||||
* @package wpml-core
|
||||
* @subpackage post-translation
|
||||
*/
|
||||
class WPML_WordPress_Actions {
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_bulk_trash( $post_id ) {
|
||||
if ( self::is_trash_action() && self::post_id_in_bulk( $post_id ) ) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_bulk_untrash( $post_id ) {
|
||||
if ( self::is_untrash_action() && self::post_id_in_bulk( $post_id, true ) ) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function is_heartbeat( ) {
|
||||
return self::is_action( 'heartbeat', 'post' );
|
||||
}
|
||||
|
||||
protected static function is_trash_action() {
|
||||
return self::is_action( 'trash' );
|
||||
}
|
||||
|
||||
protected static function is_untrash_action() {
|
||||
return self::is_action( 'untrash' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $action
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected static function is_action( $action, $type = 'get' ) {
|
||||
if ( $type == 'get' ) {
|
||||
return ( isset( $_GET[ 'action' ] ) && $_GET[ 'action' ] == $action ) || ( isset( $_GET[ 'action2' ] ) && $_GET[ 'action2' ] == $action );
|
||||
} elseif ( $type == 'post' ) {
|
||||
return ( isset( $_POST[ 'action' ] ) && $_POST[ 'action' ] == $action ) || ( isset( $_POST[ 'action2' ] ) && $_POST[ 'action2' ] == $action );
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
* @param bool $check_ids
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected static function post_id_in_bulk( $post_id, $check_ids = false ) {
|
||||
if ( isset( $_GET[ 'post' ] ) && is_array( $_GET[ 'post' ] ) && in_array( $post_id, $_GET[ 'post' ] ) ) {
|
||||
return true;
|
||||
} elseif ( $check_ids ) {
|
||||
// We need to check the ids parameter when user clicks on 'undo' after trashing.
|
||||
return isset( $_GET[ 'ids' ] ) && is_string( $_GET[ 'ids' ] ) && in_array( $post_id, explode( ',', $_GET[ 'ids' ] ) );
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Name_Query_Filter_Translated
|
||||
*
|
||||
* @package wpml-core
|
||||
* @subpackage post-translation
|
||||
*
|
||||
* @since 3.2.3
|
||||
*/
|
||||
class WPML_Name_Query_Filter_Translated extends WPML_Name_Query_Filter {
|
||||
|
||||
private $pages_to_langs = array();
|
||||
|
||||
/**
|
||||
* @param array $pages_with_name
|
||||
*
|
||||
* @return int|null|string
|
||||
*/
|
||||
protected function select_best_match( $pages_with_name ) {
|
||||
|
||||
if ( ! empty( $pages_with_name['matching_ids'] ) ) {
|
||||
$matching_page = $this->get_matching_page_in_requested_lang( $pages_with_name['matching_ids'] );
|
||||
|
||||
if ( $matching_page ) {
|
||||
return $matching_page;
|
||||
}
|
||||
|
||||
$display_as_translated_page = $this->get_matching_page_displayed_as_translated();
|
||||
|
||||
if ( $display_as_translated_page ) {
|
||||
return $display_as_translated_page;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $pages_with_name['related_ids'] ) ) {
|
||||
return $this->get_the_best_related_page_to_redirect( $pages_with_name['related_ids'] );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $matching_ids
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
private function get_matching_page_in_requested_lang( array $matching_ids ) {
|
||||
foreach ( $matching_ids as $matching_id ) {
|
||||
$page_lang = $this->post_translation->get_element_lang_code( (int) $matching_id );
|
||||
|
||||
if ( $this->sitepress->get_current_language() === $page_lang ) {
|
||||
return (int) $matching_id;
|
||||
}
|
||||
|
||||
$this->pages_to_langs[ $matching_id ] = $page_lang;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|null
|
||||
*/
|
||||
private function get_matching_page_displayed_as_translated() {
|
||||
foreach ( $this->pages_to_langs as $page_id => $lang ) {
|
||||
if ( $lang === $this->sitepress->get_default_language()
|
||||
&& $this->sitepress->is_display_as_translated_post_type( get_post_type( $page_id ) )
|
||||
) {
|
||||
return $this->post_translation->element_id_in( $page_id, $this->sitepress->get_current_language(), true );
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: `$this->active_languages` is already ordered in `get_ordered_langs`
|
||||
*
|
||||
* @param array $related_page_ids
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
private function get_the_best_related_page_to_redirect( array $related_page_ids ) {
|
||||
foreach ( $this->active_languages as $lang_code ) {
|
||||
foreach ( $related_page_ids as $related_page_id ) {
|
||||
$page_lang = $this->post_translation->get_element_lang_code( (int) $related_page_id );
|
||||
|
||||
if ( $page_lang === $lang_code ) {
|
||||
return $related_page_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a SQL snippet for joining the posts table with icl translations filtered for the post_type
|
||||
* of this class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_from_join_snippet() {
|
||||
|
||||
return " FROM {$this->wpdb->posts} p
|
||||
JOIN {$this->wpdb->prefix}icl_translations wpml_translations
|
||||
ON p.ID = wpml_translations.element_id
|
||||
AND wpml_translations.element_type = CONCAT('post_', p.post_type ) ";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Name_Query_Filter_Untranslated
|
||||
*
|
||||
* @package wpml-core
|
||||
* @subpackage post-translation
|
||||
*
|
||||
* @since 3.2.3
|
||||
*/
|
||||
class WPML_Name_Query_Filter_Untranslated extends WPML_Name_Query_Filter {
|
||||
|
||||
protected function select_best_match( $pages_with_name ) {
|
||||
if ( ! empty( $pages_with_name['matching_ids'] ) ) {
|
||||
return reset( $pages_with_name['matching_ids'] );
|
||||
} elseif ( ! empty( $pages_with_name['related_ids'] ) ) {
|
||||
return reset( $pages_with_name['related_ids'] );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a SQL snippet for joining the posts table with icl translations filtered for the post_type
|
||||
* of this class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_from_join_snippet() {
|
||||
|
||||
return " FROM {$this->wpdb->posts} p ";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Name_Query_Filter
|
||||
*
|
||||
* @package wpml-core
|
||||
* @subpackage post-translation
|
||||
*
|
||||
* @since 3.2.3
|
||||
*/
|
||||
abstract class WPML_Name_Query_Filter extends WPML_Slug_Resolution {
|
||||
|
||||
/** @var string $post_type */
|
||||
protected $post_type;
|
||||
|
||||
/** @var string[] $indexes */
|
||||
protected $indexes = array( 'name' );
|
||||
|
||||
/** @var string $id_index */
|
||||
protected $id_index = 'p';
|
||||
|
||||
/** @var string[] $active_languages */
|
||||
protected $active_languages = array();
|
||||
|
||||
/** @var string $al_regexp */
|
||||
protected $al_regexp;
|
||||
|
||||
/** @var WPML_Post_Translation $post_translation */
|
||||
protected $post_translation;
|
||||
|
||||
protected $is_translated;
|
||||
|
||||
/**
|
||||
* @param string $post_type
|
||||
* @param SitePress $sitepress
|
||||
* @param WPML_Post_Translation $post_translations
|
||||
* @param wpdb $wpdb
|
||||
*/
|
||||
public function __construct( $post_type, &$sitepress, &$post_translations, &$wpdb ) {
|
||||
parent::__construct( $wpdb, $sitepress );
|
||||
$this->post_type = $post_type;
|
||||
$this->indexes[] = $post_type;
|
||||
$this->is_translated = $this->sitepress->is_translated_post_type( $post_type );
|
||||
$this->post_translation = &$post_translations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks through the "name" and "pagename" query vars in a given query and identifies the correct page_id
|
||||
* corresponding to either of these two and then adjusts the query page_id to point at this correct page_id.
|
||||
*
|
||||
* @param WP_Query $page_query
|
||||
*
|
||||
* @return array
|
||||
* - WP_Query that uses the id index stored in \WPML_Name_Query_Filter::$id_index
|
||||
* instead of "name" or "pagename" in case a match was found, otherwise
|
||||
* returns the input query unaltered.
|
||||
* - int|false the page ID
|
||||
*/
|
||||
public function filter_page_name( WP_Query $page_query ) {
|
||||
$this->active_languages = $this->get_ordered_langs();
|
||||
$this->al_regexp = $this->generate_al_regexp( $this->active_languages );
|
||||
foreach ( $this->indexes as $index ) {
|
||||
list( $pages_with_name, $page_name_for_query ) = $this->query_needs_adjustment( $page_query, $index );
|
||||
if ( ! empty( $pages_with_name['matching_ids'] ) || ! empty( $pages_with_name['related_ids'] ) ) {
|
||||
$pid = $this->select_best_match( $pages_with_name );
|
||||
if ( isset( $pid ) ) {
|
||||
if ( ! isset( $page_query->queried_object_id ) || $pid != $page_query->queried_object_id ) {
|
||||
$page_query = $this->maybe_adjust_query_by_pid( $page_query, $pid, $index );
|
||||
break;
|
||||
} else {
|
||||
unset( $pid );
|
||||
}
|
||||
} elseif ( (bool) $page_name_for_query === true ) {
|
||||
$page_query->query_vars[ $index ] = $page_name_for_query;
|
||||
$page_query->query_vars['post_type'] = $this->post_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array( $page_query, isset( $pid ) ? $pid : false );
|
||||
}
|
||||
|
||||
abstract protected function select_best_match( $pages_with_name );
|
||||
|
||||
/**
|
||||
* @param WP_Query $page_query
|
||||
* @param int $pid
|
||||
* @param string $index
|
||||
*
|
||||
* @return WP_Query
|
||||
*/
|
||||
protected function maybe_adjust_query_by_pid( $page_query, $pid, $index ) {
|
||||
if ( ! ( isset( $page_query->queried_object )
|
||||
&& isset( $page_query->queried_object->ID )
|
||||
&& (int) $page_query->queried_object->ID === (int) $pid )
|
||||
) {
|
||||
if ( isset( $page_query->query['page_id'] ) ) {
|
||||
$page_query->query['page_id'] = (int) $pid;
|
||||
}
|
||||
$page_query->query_vars['page_id'] = null;
|
||||
$page_query->query_vars[ $this->id_index ] = (int) $pid;
|
||||
if ( isset( $page_query->query[ $this->id_index ] ) ) {
|
||||
$page_query->query[ $this->id_index ] = (int) $pid;
|
||||
}
|
||||
$page_query->is_page = false;
|
||||
if ( isset( $page_query->query_vars[ $this->post_type ] )
|
||||
&& $this->post_type !== 'page'
|
||||
) {
|
||||
$this->set_query_var_to_restore( $this->post_type, $page_query );
|
||||
unset( $page_query->query_vars[ $this->post_type ] );
|
||||
}
|
||||
unset( $page_query->query_vars[ $index ] );
|
||||
if ( ! empty( $page_query->queried_object ) ) {
|
||||
$page_query->queried_object = get_post( $pid );
|
||||
$page_query->queried_object_id = (int) $pid;
|
||||
}
|
||||
|
||||
$page_query = $this->adjusting_id( $page_query );
|
||||
}
|
||||
|
||||
return $page_query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the post id is being adjusted. Can be overridden.
|
||||
*
|
||||
* @param WP_Query $page_query
|
||||
*
|
||||
* @return WP_Query
|
||||
*/
|
||||
|
||||
protected function adjusting_id( $page_query ) {
|
||||
$page_query->is_single = true;
|
||||
|
||||
return $page_query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a SQL snippet for joining the posts table with icl translations filtered for the post_type
|
||||
* of this class.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function get_from_join_snippet();
|
||||
|
||||
/**
|
||||
* Generates a regular expression matcher for matching language slugs in a URI
|
||||
*
|
||||
* @param string[] $active_language_codes
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function generate_al_regexp( $active_language_codes ) {
|
||||
|
||||
return '/^(' . implode( '|', $active_language_codes ) . ')\//';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_Query $page_query
|
||||
* @param string $index
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function query_needs_adjustment( WP_Query $page_query, $index ) {
|
||||
if ( empty( $page_query->query_vars[ $index ] ) ) {
|
||||
$pages_with_name = false;
|
||||
$page_name_for_query = false;
|
||||
} else {
|
||||
$page_name_for_query = preg_replace( $this->al_regexp, '', $page_query->query_vars[ $index ] );
|
||||
|
||||
if ( $this->page_name_has_parent( $page_name_for_query ) ) {
|
||||
$pages_with_name = $this->get_multiple_slug_adjusted_IDs( explode( '/', $page_name_for_query ) );
|
||||
} else {
|
||||
$pages_with_name = $this->get_single_slug_adjusted_IDs(
|
||||
$page_name_for_query,
|
||||
$this->get_post_parent_query_var( $page_query )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return array( $pages_with_name, $page_name_for_query );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $page_name_for_query
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function page_name_has_parent( $page_name_for_query ) {
|
||||
return false !== strpos( $page_name_for_query, '/' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_Query $page_query
|
||||
*
|
||||
* @return int|string
|
||||
*/
|
||||
private function get_post_parent_query_var( WP_Query $page_query ) {
|
||||
$post_parent = 0;
|
||||
|
||||
if ( isset( $page_query->query_vars['post_parent'] ) ) {
|
||||
$post_parent = $page_query->query_vars['post_parent'];
|
||||
}
|
||||
|
||||
return $post_parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $page_name_for_query
|
||||
* @param string|int $post_parent
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_single_slug_adjusted_IDs( $page_name_for_query, $post_parent ) {
|
||||
$cache = new WPML_WP_Cache( get_class( $this ) );
|
||||
$cache_key = 'get_single_slug_adjusted_IDs' . $this->post_type . $page_name_for_query . $post_parent;
|
||||
$found = false;
|
||||
|
||||
$pages_with_name = $cache->get( $cache_key, $found );
|
||||
|
||||
if ( ! $found ) {
|
||||
$pages_with_name = $this->get_single_slug_adjusted_IDs_from_DB( $page_name_for_query, $post_parent );
|
||||
$cache->set( $cache_key, $pages_with_name );
|
||||
}
|
||||
|
||||
return array( 'matching_ids' => $pages_with_name );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $page_name_for_query
|
||||
* @param string|int $post_parent
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_single_slug_adjusted_IDs_from_DB( $page_name_for_query, $post_parent ) {
|
||||
$pages_with_name = $this->wpdb->get_col(
|
||||
$this->wpdb->prepare(
|
||||
'
|
||||
SELECT ID
|
||||
' . $this->get_from_join_snippet()
|
||||
. $this->get_where_snippet() . ' p.post_name = %s
|
||||
ORDER BY p.post_parent = %d DESC
|
||||
',
|
||||
$page_name_for_query,
|
||||
$post_parent
|
||||
)
|
||||
);
|
||||
|
||||
return $pages_with_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string[] $slugs slugs that were queried for
|
||||
*
|
||||
* @return int[] page_ids ordered by their likelihood of correctly matching the query target,
|
||||
* derived from checking all slugs against the sits pages slugs as well as their parent slugs.
|
||||
* Elements at the beginning of the array are more correct than later elements, but the results
|
||||
* are not yet filtered for the correct language.
|
||||
*
|
||||
* @used-by \WPML_Page_Name_Query_Filter::filter_page_name to find the correct page_id corresponding to a set of slugs,
|
||||
* by filtering the results of this function by language of the
|
||||
* returned page_ids.
|
||||
*/
|
||||
private function get_multiple_slug_adjusted_IDs( $slugs ) {
|
||||
$parent_slugs = array_slice( $slugs, 0, - 1 );
|
||||
$pages_with_name = $this->wpdb->get_results(
|
||||
' SELECT p.ID, p.post_name, p.post_parent, par.post_name as parent_name
|
||||
' . $this->get_from_join_snippet() . "
|
||||
LEFT JOIN {$this->wpdb->posts} par
|
||||
ON par.ID = p.post_parent
|
||||
" . $this->get_where_snippet() . ' p.post_name IN (' . wpml_prepare_in( $slugs ) . ')
|
||||
ORDER BY par.post_name IN (' . wpml_prepare_in( $parent_slugs ) . ') DESC'
|
||||
);
|
||||
$query_scorer = new WPML_Score_Hierarchy( $pages_with_name, $slugs );
|
||||
|
||||
return $query_scorer->get_possible_ids_ordered();
|
||||
}
|
||||
|
||||
private function get_where_snippet() {
|
||||
|
||||
return $this->wpdb->prepare( ' WHERE p.post_type = %s AND ', $this->post_type );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Page_Name_Query_Filter
|
||||
*
|
||||
* @package wpml-core
|
||||
* @subpackage post-translation
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
class WPML_Page_Name_Query_Filter extends WPML_Name_Query_Filter_Translated {
|
||||
|
||||
protected $id_index = 'page_id';
|
||||
|
||||
/**
|
||||
* @param SitePress $sitepress
|
||||
* @param WPML_Post_Translation $post_translations
|
||||
* @param wpdb $wpdb
|
||||
*/
|
||||
public function __construct( &$sitepress, &$post_translations, &$wpdb ) {
|
||||
parent::__construct( 'page', $sitepress, $post_translations, $wpdb );
|
||||
$this->indexes = array( 'name', 'pagename' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_Query $page_query
|
||||
* @param int $pid
|
||||
* @param string $index
|
||||
*
|
||||
* @return WP_Query
|
||||
*/
|
||||
protected function maybe_adjust_query_by_pid( $page_query, $pid, $index ) {
|
||||
$page_query = parent::maybe_adjust_query_by_pid( $page_query, $pid, $index );
|
||||
|
||||
$is_page_for_posts = 'page' == get_option( 'show_on_front' ) && (int) $pid === (int) get_option( 'page_for_posts' );
|
||||
if ( $is_page_for_posts ) {
|
||||
$page_query->query_vars['post_status'] = 'publish';
|
||||
$page_query->query_vars['name'] = '';
|
||||
$page_query->query_vars['page_id'] = 0;
|
||||
$page_query->post_status = 'publish';
|
||||
$page_query->is_page = false;
|
||||
$page_query->is_singular = false;
|
||||
$page_query->is_home = true;
|
||||
$page_query->is_posts_page = true;
|
||||
}
|
||||
|
||||
return $page_query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the post id is being adjusted. Can be overridden.
|
||||
*
|
||||
* @param WP_Query $page_query
|
||||
*
|
||||
* @return WP_Query
|
||||
*/
|
||||
|
||||
protected function adjusting_id( $page_query ) {
|
||||
$page_query->is_page = true;
|
||||
|
||||
return $page_query;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Slug_Resolution
|
||||
*
|
||||
* @package wpml-core
|
||||
* @subpackage post-translation
|
||||
*/
|
||||
abstract class WPML_Slug_Resolution extends WPML_WPDB_And_SP_User {
|
||||
|
||||
const WPML_BACKUP_KEY = '_wpml_backup';
|
||||
|
||||
/**
|
||||
* Returns all active language codes ordered by the language order, but having the current language
|
||||
* at the beginning.
|
||||
*
|
||||
* @return string[]
|
||||
*
|
||||
* @uses \SitePress::get_setting to get the languages order from the sitepress settings
|
||||
*/
|
||||
protected function get_ordered_langs() {
|
||||
$lang_order = $this->sitepress->get_setting( 'languages_order' );
|
||||
$lang_order = $lang_order ? $lang_order : array_keys( $this->sitepress->get_active_languages() );
|
||||
array_unshift( $lang_order, $this->sitepress->get_current_language() );
|
||||
|
||||
return array_unique( $lang_order );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param WP_Query $wp_query
|
||||
*/
|
||||
protected function set_query_var_to_restore( $key, WP_Query $wp_query ) {
|
||||
$wp_query->query_vars[ self::WPML_BACKUP_KEY ][ $key ] = $wp_query->query_vars[ $key ];
|
||||
add_filter( 'the_posts', array( $this, 'restore_query_vars' ), 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_Post[] $posts
|
||||
* @param WP_Query $wp_query
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function restore_query_vars( $posts, $wp_query ) {
|
||||
if ( isset( $wp_query->query_vars[ self::WPML_BACKUP_KEY ] ) ) {
|
||||
foreach ( $wp_query->query_vars[ self::WPML_BACKUP_KEY ] as $key => $value ) {
|
||||
$wp_query->query_vars[ $key ] = $value;
|
||||
}
|
||||
|
||||
unset( $wp_query->query_vars[ self::WPML_BACKUP_KEY ] );
|
||||
remove_filter( 'the_posts', array( $this, 'restore_query_vars' ), 10 );
|
||||
}
|
||||
|
||||
return $posts;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,501 @@
|
||||
<?php
|
||||
/**
|
||||
* @package wpml-core
|
||||
*/
|
||||
|
||||
function icl_reset_language_data() {
|
||||
global $wpdb, $sitepress;
|
||||
|
||||
$active = $wpdb->get_col( "SELECT code FROM {$wpdb->prefix}icl_languages WHERE active = 1" );
|
||||
|
||||
$wpdb->query( "TRUNCATE TABLE `{$wpdb->prefix}icl_languages`" );
|
||||
SitePress_Setup::fill_languages();
|
||||
$wpdb->query( "TRUNCATE TABLE `{$wpdb->prefix}icl_languages_translations`" );
|
||||
SitePress_Setup::fill_languages_translations();
|
||||
$wpdb->query( "TRUNCATE TABLE `{$wpdb->prefix}icl_flags`" );
|
||||
SitePress_Setup::fill_flags();
|
||||
|
||||
// restore active
|
||||
$wpdb->query( "UPDATE {$wpdb->prefix}icl_languages SET active=1 WHERE code IN(" . wpml_prepare_in( $active ) . ')' );
|
||||
|
||||
$wpdb->update( $wpdb->prefix . 'icl_flags', array( 'from_template' => 0 ), null );
|
||||
|
||||
$codes = $wpdb->get_col( "SELECT code FROM {$wpdb->prefix}icl_languages" );
|
||||
foreach ( $codes as $code ) {
|
||||
if ( ! $code || $wpdb->get_var(
|
||||
$wpdb->prepare( "SELECT lang_code FROM {$wpdb->prefix}icl_flags WHERE lang_code = %s", $code )
|
||||
)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
if ( ! file_exists( WPML_PLUGIN_PATH . '/res/flags/' . $code . '.png' ) ) {
|
||||
$file = 'nil.png';
|
||||
} else {
|
||||
$file = $code . '.png';
|
||||
}
|
||||
$wpdb->insert(
|
||||
$wpdb->prefix . 'icl_flags',
|
||||
array(
|
||||
'lang_code' => $code,
|
||||
'flag' => $file,
|
||||
'from_template' => 0,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$last_default_language = $sitepress !== null ? $sitepress->get_default_language() : 'en';
|
||||
if ( ! in_array( $last_default_language, $codes ) ) {
|
||||
$allowed_langs = array_intersect( array_keys( $sitepress->get_active_languages() ), $codes );
|
||||
$sitepress->set_default_language( array_pop( $allowed_langs ) );
|
||||
}
|
||||
|
||||
icl_cache_clear();
|
||||
|
||||
do_action( 'wpml_translation_update', array( 'type' => 'reset' ) );
|
||||
}
|
||||
|
||||
function icl_sitepress_activate() {
|
||||
global $wpdb;
|
||||
|
||||
$charset_collate = SitePress_Setup::get_charset_collate();
|
||||
|
||||
try {
|
||||
SitePress_Setup::fill_languages();
|
||||
SitePress_Setup::fill_languages_translations();
|
||||
SitePress_Setup::fill_flags();
|
||||
|
||||
// translations
|
||||
$table_name = $wpdb->prefix . 'icl_translations';
|
||||
$found_table = (string) $wpdb->get_var( "SHOW TABLES LIKE '{$table_name}'" );
|
||||
if ( 0 !== strcasecmp( $found_table, $table_name ) ) {
|
||||
$sql = "
|
||||
CREATE TABLE IF NOT EXISTS `{$table_name}` (
|
||||
`translation_id` BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
|
||||
`element_type` VARCHAR( 60 ) NOT NULL DEFAULT 'post_post',
|
||||
`element_id` BIGINT NULL DEFAULT NULL ,
|
||||
`trid` BIGINT NOT NULL ,
|
||||
`language_code` VARCHAR( 7 ) NOT NULL,
|
||||
`source_language_code` VARCHAR( 7 ),
|
||||
UNIQUE KEY `el_type_id` (`element_type`,`element_id`),
|
||||
UNIQUE KEY `trid_lang` (`trid`,`language_code`),
|
||||
KEY `trid` (`trid`),
|
||||
KEY `id_type_language` (`element_id`, `element_type`, `language_code`)
|
||||
) {$charset_collate}";
|
||||
if ( $wpdb->query( $sql ) === false ) {
|
||||
throw new Exception( $wpdb->last_error );
|
||||
}
|
||||
}
|
||||
|
||||
// translation_status table
|
||||
$table_name = $wpdb->prefix . 'icl_translation_status';
|
||||
$found_table = (string) $wpdb->get_var( "SHOW TABLES LIKE '{$table_name}'" );
|
||||
if ( 0 !== strcasecmp( $found_table, $table_name ) ) {
|
||||
$sql = "
|
||||
CREATE TABLE IF NOT EXISTS `{$table_name}` (
|
||||
`rid` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
`translation_id` bigint(20) NOT NULL,
|
||||
`status` tinyint(4) NOT NULL,
|
||||
`translator_id` bigint(20) NOT NULL,
|
||||
`needs_update` tinyint(4) NOT NULL,
|
||||
`md5` varchar(32) NOT NULL,
|
||||
`translation_service` varchar(16) NOT NULL,
|
||||
`batch_id` int DEFAULT 0 NOT NULL,
|
||||
`translation_package` longtext NOT NULL,
|
||||
`timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`links_fixed` tinyint(4) NOT NULL DEFAULT 0,
|
||||
`_prevstate` longtext,
|
||||
`uuid` varchar(36) NULL,
|
||||
`tp_id` INT NULL DEFAULT NULL,
|
||||
`tp_revision` INT NOT NULL DEFAULT 1,
|
||||
`ts_status` TEXT NULL DEFAULT NULL,
|
||||
`review_status` ENUM('NEEDS_REVIEW', 'EDITING', 'ACCEPTED'),
|
||||
`ate_comm_retry_count` INT(11) UNSIGNED DEFAULT 0,
|
||||
PRIMARY KEY (`rid`),
|
||||
UNIQUE KEY `translation_id` (`translation_id`)
|
||||
) {$charset_collate}
|
||||
";
|
||||
if ( $wpdb->query( $sql ) === false ) {
|
||||
throw new Exception( $wpdb->last_error );
|
||||
}
|
||||
}
|
||||
|
||||
// translation jobs
|
||||
$table_name = $wpdb->prefix . 'icl_translate_job';
|
||||
$found_table = (string) $wpdb->get_var( "SHOW TABLES LIKE '{$table_name}'" );
|
||||
if ( 0 !== strcasecmp( $found_table, $table_name ) ) {
|
||||
$sql = "
|
||||
CREATE TABLE IF NOT EXISTS `{$table_name}` (
|
||||
`job_id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
|
||||
`rid` BIGINT UNSIGNED NOT NULL ,
|
||||
`translator_id` INT UNSIGNED NOT NULL ,
|
||||
`translated` TINYINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
`manager_id` INT UNSIGNED NOT NULL ,
|
||||
`revision` INT UNSIGNED NULL,
|
||||
`title` VARCHAR(160) NULL,
|
||||
`deadline_date` DATETIME NULL,
|
||||
`completed_date` DATETIME NULL,
|
||||
`editor` VARCHAR(16) NULL,
|
||||
`editor_job_id` BIGINT(20) UNSIGNED NULL,
|
||||
`edit_timestamp` INT(11) UNSIGNED NULL,
|
||||
`automatic` TINYINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
INDEX ( `rid` , `translator_id` )
|
||||
) {$charset_collate}
|
||||
";
|
||||
if ( $wpdb->query( $sql ) === false ) {
|
||||
throw new Exception( $wpdb->last_error );
|
||||
}
|
||||
}
|
||||
|
||||
// translate table
|
||||
$table_name = $wpdb->prefix . 'icl_translate';
|
||||
$found_table = (string) $wpdb->get_var( "SHOW TABLES LIKE '{$table_name}'" );
|
||||
if ( 0 !== strcasecmp( $found_table, $table_name ) ) {
|
||||
$sql = "
|
||||
CREATE TABLE IF NOT EXISTS `{$table_name}` (
|
||||
`tid` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
|
||||
`job_id` BIGINT UNSIGNED NOT NULL ,
|
||||
`content_id` BIGINT UNSIGNED NOT NULL ,
|
||||
`timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
|
||||
`field_type` VARCHAR( 160 ) NOT NULL ,
|
||||
`field_wrap_tag` VARCHAR( 16 ) NOT NULL ,
|
||||
`field_format` VARCHAR( 16 ) NOT NULL ,
|
||||
`field_translate` TINYINT NOT NULL ,
|
||||
`field_data` longtext NOT NULL ,
|
||||
`field_data_translated` longtext NOT NULL ,
|
||||
`field_finished` TINYINT NOT NULL DEFAULT 0,
|
||||
INDEX ( `job_id` )
|
||||
) {$charset_collate}
|
||||
";
|
||||
if ( $wpdb->query( $sql ) === false ) {
|
||||
throw new Exception( $wpdb->last_error );
|
||||
}
|
||||
}
|
||||
|
||||
// batches table
|
||||
$table_name = $wpdb->prefix . 'icl_translation_batches';
|
||||
$found_table = (string) $wpdb->get_var( "SHOW TABLES LIKE '{$table_name}'" );
|
||||
if ( 0 !== strcasecmp( $found_table, $table_name ) ) {
|
||||
$sql = "
|
||||
CREATE TABLE IF NOT EXISTS {$wpdb->prefix}icl_translation_batches (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`batch_name` text NOT NULL,
|
||||
`tp_id` int NULL,
|
||||
`ts_url` text NULL,
|
||||
`last_update` DATETIME NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) {$charset_collate}
|
||||
";
|
||||
if ( $wpdb->query( $sql ) === false ) {
|
||||
throw new Exception( $wpdb->last_error );
|
||||
}
|
||||
}
|
||||
|
||||
// languages locale file names
|
||||
$table_name = $wpdb->prefix . 'icl_locale_map';
|
||||
$found_table = (string) $wpdb->get_var( "SHOW TABLES LIKE '{$table_name}'" );
|
||||
if ( 0 !== strcasecmp( $found_table, $table_name ) ) {
|
||||
$sql = "
|
||||
CREATE TABLE IF NOT EXISTS `{$table_name}` (
|
||||
`code` VARCHAR( 7 ) NOT NULL ,
|
||||
`locale` VARCHAR( 35 ) NOT NULL ,
|
||||
PRIMARY KEY (`code` ,`locale`)
|
||||
) {$charset_collate}";
|
||||
if ( $wpdb->query( $sql ) === false ) {
|
||||
throw new Exception( $wpdb->last_error );
|
||||
}
|
||||
}
|
||||
|
||||
/* general string translation */
|
||||
$translation_priority_default = __( 'Optional', 'sitepress' );
|
||||
$table_name = $wpdb->prefix . 'icl_strings';
|
||||
$found_table = (string) $wpdb->get_var( "SHOW TABLES LIKE '{$table_name}'" );
|
||||
if ( 0 !== strcasecmp( $found_table, $table_name ) ) {
|
||||
$sql = "
|
||||
CREATE TABLE IF NOT EXISTS `{$table_name}` (
|
||||
`id` bigint(20) unsigned NOT NULL auto_increment,
|
||||
`language` varchar(7) NOT NULL,
|
||||
`context` varchar(" . WPML_STRING_TABLE_NAME_CONTEXT_LENGTH . ') NOT NULL,
|
||||
`name` varchar(' . WPML_STRING_TABLE_NAME_CONTEXT_LENGTH . ") NOT NULL,
|
||||
`value` longtext NOT NULL,
|
||||
`string_package_id` BIGINT unsigned NULL,
|
||||
`location` BIGINT unsigned NULL,
|
||||
`wrap_tag` VARCHAR( 16 ) NOT NULL,
|
||||
`type` VARCHAR(40) NOT NULL DEFAULT 'LINE',
|
||||
`title` VARCHAR(160) NULL,
|
||||
`status` TINYINT NOT NULL,
|
||||
`gettext_context` TEXT NOT NULL,
|
||||
`domain_name_context_md5` VARCHAR(32) NOT NULL,
|
||||
`translation_priority` varchar(160) NOT NULL,
|
||||
`word_count` int unsigned NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uc_domain_name_context_md5` (`domain_name_context_md5`),
|
||||
KEY `language_context` (`language`, `context`),
|
||||
KEY `icl_strings_name` (`name` ASC),
|
||||
KEY `icl_strings_translation_priority` ( `translation_priority` ASC ),
|
||||
KEY `context` ( `context` )
|
||||
) {$charset_collate}
|
||||
";
|
||||
if ( $wpdb->query( $sql ) === false ) {
|
||||
throw new Exception( $wpdb->last_error );
|
||||
}
|
||||
}
|
||||
|
||||
$table_name = $wpdb->prefix . 'icl_string_translations';
|
||||
$found_table = (string) $wpdb->get_var( "SHOW TABLES LIKE '{$table_name}'" );
|
||||
if ( 0 !== strcasecmp( $found_table, $table_name ) ) {
|
||||
$sql = "
|
||||
CREATE TABLE IF NOT EXISTS `{$table_name}` (
|
||||
`id` bigint(20) unsigned NOT NULL auto_increment,
|
||||
`string_id` bigint(20) unsigned NOT NULL,
|
||||
`language` varchar(10) NOT NULL,
|
||||
`status` tinyint(4) NOT NULL,
|
||||
`value` longtext NULL DEFAULT NULL,
|
||||
`mo_string` longtext NULL DEFAULT NULL,
|
||||
`translator_id` bigint(20) unsigned DEFAULT NULL,
|
||||
`translation_service` varchar(16) DEFAULT '' NOT NULL,
|
||||
`batch_id` int DEFAULT 0 NOT NULL,
|
||||
`translation_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `string_language` (`string_id`,`language`)
|
||||
) {$charset_collate}";
|
||||
if ( $wpdb->query( $sql ) === false ) {
|
||||
throw new Exception( $wpdb->last_error );
|
||||
}
|
||||
}
|
||||
|
||||
$table_name = $wpdb->prefix . 'icl_string_status';
|
||||
$found_table = (string) $wpdb->get_var( "SHOW TABLES LIKE '{$table_name}'" );
|
||||
if ( 0 !== strcasecmp( $found_table, $table_name ) ) {
|
||||
$sql = "
|
||||
CREATE TABLE IF NOT EXISTS `{$table_name}` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
|
||||
`rid` BIGINT NOT NULL ,
|
||||
`string_translation_id` BIGINT NOT NULL ,
|
||||
`timestamp` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
|
||||
`md5` VARCHAR( 32 ) NOT NULL,
|
||||
INDEX ( `string_translation_id` )
|
||||
) {$charset_collate}";
|
||||
if ( $wpdb->query( $sql ) === false ) {
|
||||
throw new Exception( $wpdb->last_error );
|
||||
}
|
||||
}
|
||||
|
||||
$table_name = $wpdb->prefix . 'icl_string_positions';
|
||||
$found_table = (string) $wpdb->get_var( "SHOW TABLES LIKE '{$table_name}'" );
|
||||
if ( 0 !== strcasecmp( $found_table, $table_name ) ) {
|
||||
$sql = "
|
||||
CREATE TABLE IF NOT EXISTS `{$table_name}` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
|
||||
`string_id` BIGINT NOT NULL ,
|
||||
`kind` TINYINT,
|
||||
`position_in_page` VARCHAR( 255 ) NOT NULL,
|
||||
INDEX ( `string_id` )
|
||||
) {$charset_collate}";
|
||||
if ( $wpdb->query( $sql ) === false ) {
|
||||
throw new Exception( $wpdb->last_error );
|
||||
}
|
||||
}
|
||||
|
||||
// message status table
|
||||
$table_name = $wpdb->prefix . 'icl_message_status';
|
||||
$found_table = (string) $wpdb->get_var( "SHOW TABLES LIKE '{$table_name}'" );
|
||||
if ( 0 !== strcasecmp( $found_table, $table_name ) ) {
|
||||
$sql = "
|
||||
CREATE TABLE IF NOT EXISTS `{$table_name}` (
|
||||
`id` bigint(20) unsigned NOT NULL auto_increment,
|
||||
`rid` bigint(20) unsigned NOT NULL,
|
||||
`object_id` bigint(20) unsigned NOT NULL,
|
||||
`from_language` varchar(10) NOT NULL,
|
||||
`to_language` varchar(10) NOT NULL,
|
||||
`timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP,
|
||||
`md5` varchar(32) NOT NULL,
|
||||
`object_type` varchar(64) NOT NULL,
|
||||
`status` smallint(6) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `rid` (`rid`),
|
||||
KEY `object_id` (`object_id`)
|
||||
) {$charset_collate}";
|
||||
if ( $wpdb->query( $sql ) === false ) {
|
||||
throw new Exception( $wpdb->last_error );
|
||||
}
|
||||
}
|
||||
|
||||
/* string translation - start */
|
||||
$icl_translation_sql = "
|
||||
CREATE TABLE IF NOT EXISTS {$wpdb->prefix}icl_core_status (
|
||||
`id` BIGINT NOT NULL auto_increment,
|
||||
`rid` BIGINT NOT NULL,
|
||||
`module` VARCHAR( 16 ) NOT NULL ,
|
||||
`origin` VARCHAR( 64 ) NOT NULL ,
|
||||
`target` VARCHAR( 64 ) NOT NULL ,
|
||||
`status` SMALLINT NOT NULL,
|
||||
`tp_revision` INT NOT NULL DEFAULT 1,
|
||||
`ts_status` TEXT NULL DEFAULT NULL,
|
||||
PRIMARY KEY ( `id` ) ,
|
||||
INDEX ( `rid` )
|
||||
) {$charset_collate}
|
||||
";
|
||||
if ( $wpdb->query( $icl_translation_sql ) === false ) {
|
||||
throw new Exception( $wpdb->last_error );
|
||||
}
|
||||
|
||||
$icl_translation_sql = "
|
||||
CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}icl_content_status` (
|
||||
`rid` BIGINT NOT NULL ,
|
||||
`nid` BIGINT NOT NULL ,
|
||||
`timestamp` DATETIME NOT NULL ,
|
||||
`md5` VARCHAR( 32 ) NOT NULL ,
|
||||
PRIMARY KEY ( `rid` ) ,
|
||||
INDEX ( `nid` )
|
||||
) {$charset_collate}
|
||||
";
|
||||
if ( $wpdb->query( $icl_translation_sql ) === false ) {
|
||||
throw new Exception( $wpdb->last_error );
|
||||
}
|
||||
|
||||
$icl_translation_sql = "
|
||||
CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}icl_node` (
|
||||
`nid` BIGINT NOT NULL ,
|
||||
`md5` VARCHAR( 32 ) NOT NULL ,
|
||||
`links_fixed` TINYINT NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY ( `nid` )
|
||||
) {$charset_collate}
|
||||
";
|
||||
if ( $wpdb->query( $icl_translation_sql ) === false ) {
|
||||
throw new Exception( $wpdb->last_error );
|
||||
}
|
||||
|
||||
$icl_translation_sql = "
|
||||
CREATE TABLE IF NOT EXISTS `{$wpdb->prefix}icl_reminders` (
|
||||
`id` BIGINT NOT NULL ,
|
||||
`message` TEXT NOT NULL ,
|
||||
`url` TEXT NOT NULL ,
|
||||
`can_delete` TINYINT NOT NULL ,
|
||||
`show` TINYINT NOT NULL ,
|
||||
PRIMARY KEY ( `id` )
|
||||
) {$charset_collate}
|
||||
";
|
||||
if ( $wpdb->query( $icl_translation_sql ) === false ) {
|
||||
throw new Exception( $wpdb->last_error );
|
||||
}
|
||||
} catch ( Exception $e ) {
|
||||
trigger_error( $e->getMessage(), E_USER_ERROR );
|
||||
exit;
|
||||
}
|
||||
|
||||
// don't set the new version if a multi-step upgrade is in progress
|
||||
if ( ! defined( 'ICL_MULTI_STEP_UPGRADE' ) ) {
|
||||
delete_option( 'icl_sitepress_version' );
|
||||
add_option( 'icl_sitepress_version', ICL_SITEPRESS_VERSION, '', true );
|
||||
}
|
||||
|
||||
$iclsettings = get_option( 'icl_sitepress_settings' );
|
||||
if ( $iclsettings === false ) {
|
||||
$short_v = implode( '.', array_slice( explode( '.', ICL_SITEPRESS_VERSION ), 0, 3 ) );
|
||||
$settings = array(
|
||||
'hide_upgrade_notice' => $short_v,
|
||||
);
|
||||
add_option( 'icl_sitepress_settings', $settings, '', true );
|
||||
} else {
|
||||
// reset ajx_health_flag
|
||||
$iclsettings['ajx_health_checked'] = 0;
|
||||
$iclsettings['just_reactivated'] = 1;
|
||||
update_option( 'icl_sitepress_settings', $iclsettings );
|
||||
}
|
||||
|
||||
// Set new caps for all administrator role
|
||||
wpml_enable_capabilities();
|
||||
|
||||
repair_el_type_collate();
|
||||
|
||||
WPML_Media_Duplication_Setup::initialize_settings();
|
||||
|
||||
do_action( 'wpml_activated' );
|
||||
}
|
||||
|
||||
function icl_sitepress_deactivate() {
|
||||
wp_clear_scheduled_hook( 'update_wpml_config_index' );
|
||||
require_once WPML_PLUGIN_PATH . '/inc/cache.php';
|
||||
icl_cache_clear();
|
||||
do_action( 'wpml_deactivated' );
|
||||
}
|
||||
|
||||
function icl_enable_capabilities() {
|
||||
global $wp_roles;
|
||||
|
||||
if ( ! isset( $wp_roles ) || ! is_object( $wp_roles ) ) {
|
||||
$wp_roles = new WP_Roles();
|
||||
}
|
||||
|
||||
$iclsettings = get_option( 'icl_sitepress_settings' );
|
||||
$icl_capabilities = icl_sitepress_get_capabilities();
|
||||
|
||||
// Set WPML capabilities to all roles with cap:"".
|
||||
$roles = $wp_roles->get_names();
|
||||
foreach ( $roles as $current_role => $role_name ) {
|
||||
if ( isset( $wp_roles->roles[ $current_role ]['capabilities']['manage_options'] ) ) {
|
||||
$role = get_role( $current_role );
|
||||
if ( isset( $role ) && is_object( $role ) ) {
|
||||
for ( $i = 0, $caps_limit = count( $icl_capabilities ); $i < $caps_limit; $i ++ ) {
|
||||
if ( ! isset( $wp_roles->roles[ $current_role ]['capabilities'][ $icl_capabilities[ $i ] ] ) ) {
|
||||
$role->add_cap( $icl_capabilities[ $i ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$user_admins = get_users(
|
||||
array(
|
||||
'role' => 'administrator',
|
||||
)
|
||||
);
|
||||
|
||||
if ( is_multisite() ) {
|
||||
$super_admins = get_super_admins();
|
||||
|
||||
foreach ( $super_admins as $admin ) {
|
||||
$super_admin = new WP_User( $admin );
|
||||
|
||||
if ( ! in_array( $super_admin, $user_admins, true ) ) {
|
||||
$user_admins[] = $super_admin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $user_admins as $user ) {
|
||||
if ( $user->exists() ) {
|
||||
for ( $i = 0, $caps_limit = count( $icl_capabilities ); $i < $caps_limit; $i ++ ) {
|
||||
$user->add_cap( $icl_capabilities[ $i ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$iclsettings['icl_capabilities_verified'] = true;
|
||||
update_option( 'icl_sitepress_settings', $iclsettings );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires at plugins_loaded action, to call icl_enable_capabilities().
|
||||
* https://onthegosystems.myjetbrains.com/youtrack/issue/wpmlcore-5695
|
||||
*/
|
||||
function wpml_enable_capabilities() {
|
||||
global $sitepress_settings;
|
||||
|
||||
/**
|
||||
* In case of multisite, in network activation,
|
||||
* including of pluggable.php before muplugins_loaded event trigger errors -
|
||||
* we postpone executing of icl_enable_capabilities to after plugins_loaded event.
|
||||
*
|
||||
* In other cases we include pluggable.php earlier than in wp-settings.php
|
||||
*/
|
||||
if ( ! did_action( 'muplugins_loaded' ) ) {
|
||||
add_action( 'plugins_loaded', 'wpml_enable_capabilities' );
|
||||
} else {
|
||||
if ( ! function_exists( 'get_user_by' ) ) {
|
||||
require ABSPATH . WPINC . '/pluggable.php';
|
||||
}
|
||||
icl_enable_capabilities();
|
||||
$sitepress_settings = get_option( 'icl_sitepress_settings' );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,386 @@
|
||||
<?php
|
||||
class SitePress_Setup {
|
||||
static function setup_complete() {
|
||||
global $sitepress;
|
||||
|
||||
return $sitepress->get_setting( 'setup_complete' );
|
||||
}
|
||||
|
||||
static function languages_complete() {
|
||||
return self::active_languages_complete() && self::languages_table_is_complete();
|
||||
}
|
||||
|
||||
private static function active_languages_complete() {
|
||||
static $result = null;
|
||||
|
||||
if ( $result === null ) {
|
||||
global $sitepress;
|
||||
|
||||
$result = $sitepress && 1 < count( $sitepress->get_active_languages() );
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private static function get_languages_codes() {
|
||||
static $languages_codes = array();
|
||||
if ( ! $languages_codes ) {
|
||||
$languages_codes = icl_get_languages_codes();
|
||||
}
|
||||
|
||||
return $languages_codes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private static function get_languages_names() {
|
||||
static $languages_names = array();
|
||||
if ( ! $languages_names ) {
|
||||
$languages_names = icl_get_languages_names();
|
||||
}
|
||||
|
||||
return $languages_names;
|
||||
}
|
||||
|
||||
private static function get_languages_names_count() {
|
||||
return count( self::get_languages_names() );
|
||||
}
|
||||
|
||||
static function get_charset_collate() {
|
||||
static $charset_collate = null;
|
||||
|
||||
if ( $charset_collate == null ) {
|
||||
$charset_collate = '';
|
||||
global $wpdb;
|
||||
if ( method_exists( $wpdb, 'has_cap' ) && $wpdb->has_cap( 'collation' ) ) {
|
||||
$schema = wpml_get_upgrade_schema();
|
||||
$charset = $schema->get_default_charset();
|
||||
$collate = $schema->get_default_collate();
|
||||
|
||||
if ( $charset ) {
|
||||
$charset_collate = "DEFAULT CHARACTER SET $charset";
|
||||
}
|
||||
|
||||
if ( $collate ) {
|
||||
$charset_collate .= " COLLATE $collate";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $charset_collate;
|
||||
}
|
||||
|
||||
private static function create_languages() {
|
||||
$sql = "( `id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
|
||||
`code` VARCHAR( 7 ) NOT NULL ,
|
||||
`english_name` VARCHAR( 128 ) NOT NULL ,
|
||||
`major` TINYINT NOT NULL DEFAULT '0',
|
||||
`active` TINYINT NOT NULL ,
|
||||
`default_locale` VARCHAR( 35 ),
|
||||
`tag` VARCHAR( 35 ),
|
||||
`encode_url` TINYINT( 1 ) NOT NULL DEFAULT 0,
|
||||
`country` VARCHAR(10) NULL DEFAULT NULL,
|
||||
UNIQUE KEY `code` (`code`),
|
||||
UNIQUE KEY `english_name` (`english_name`)
|
||||
) ";
|
||||
|
||||
return self::create_table( 'icl_languages', $sql );
|
||||
}
|
||||
|
||||
static function languages_table_is_complete() {
|
||||
global $wpdb;
|
||||
$table_name = $wpdb->prefix . 'icl_languages';
|
||||
$sql = "SELECT count(id) FROM {$table_name}";
|
||||
$records_count = $wpdb->get_var( $sql );
|
||||
|
||||
$languages_names_count = self::get_languages_names_count();
|
||||
|
||||
if ( $records_count < $languages_names_count ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$languages_codes = self::get_languages_codes();
|
||||
$language_pairs = self::get_language_translations();
|
||||
|
||||
foreach ( self::get_languages_names() as $lang => $val ) {
|
||||
foreach ( $val['tr'] as $k => $display ) {
|
||||
$k = self::fix_language_name( $k );
|
||||
|
||||
$code = $languages_codes[ $lang ];
|
||||
if ( ! array_key_exists( $code, $language_pairs ) || ! in_array( $languages_codes[ $k ], $language_pairs[ $code ], true ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $language_name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function fix_language_name( $language_name ) {
|
||||
if ( strpos( $language_name, 'Norwegian Bokm' ) === 0 ) {
|
||||
$language_name = 'Norwegian Bokmål';
|
||||
}
|
||||
|
||||
return $language_name;
|
||||
}
|
||||
|
||||
private static function get_language_translations() {
|
||||
$result = array();
|
||||
|
||||
global $wpdb;
|
||||
$table_name = $wpdb->prefix . 'icl_languages_translations';
|
||||
$sql = "SELECT language_code, display_language_code FROM {$table_name}";
|
||||
$rowset = $wpdb->get_results( $sql );
|
||||
|
||||
if ( is_array( $rowset ) ) {
|
||||
foreach ( $rowset as $row ) {
|
||||
$result[ $row->language_code ][] = $row->display_language_code;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
static function fill_languages() {
|
||||
global $wpdb, $sitepress;
|
||||
|
||||
$languages_codes = icl_get_languages_codes();
|
||||
$lang_locales = icl_get_languages_locales();
|
||||
|
||||
$table_name = $wpdb->prefix . 'icl_languages';
|
||||
if ( ! self::create_languages() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! self::languages_table_is_complete() ) {
|
||||
// First truncate the table
|
||||
$active_languages = ( $sitepress !== null
|
||||
&& $sitepress->is_setup_complete() ) ? $sitepress->get_active_languages() : array();
|
||||
|
||||
$wpdb->hide_errors();
|
||||
|
||||
$sql = 'TRUNCATE ' . $table_name;
|
||||
|
||||
$truncate_result = $wpdb->query( $sql );
|
||||
|
||||
$wpdb->show_errors();
|
||||
|
||||
if ( false !== $truncate_result ) {
|
||||
foreach ( self::get_languages_names() as $key => $val ) {
|
||||
$language_code = $languages_codes[ $key ];
|
||||
$default_locale = isset( $lang_locales[ $language_code ] ) ? $lang_locales[ $language_code ] : '';
|
||||
|
||||
$language_tag = strtolower( str_replace( '_', '-', $language_code ) );
|
||||
|
||||
$args = array(
|
||||
'english_name' => $key,
|
||||
'code' => $language_code,
|
||||
'major' => $val['major'],
|
||||
'active' => isset( $active_languages[ $language_code ] ) ? 1 : 0,
|
||||
'default_locale' => $default_locale,
|
||||
'tag' => $language_tag,
|
||||
);
|
||||
if ( $wpdb->insert( $table_name, $args ) === false ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static function create_languages_translations() {
|
||||
|
||||
$sql = '(`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
|
||||
`language_code` VARCHAR( 7 ) NOT NULL ,
|
||||
`display_language_code` VARCHAR( 7 ) NOT NULL ,
|
||||
`name` VARCHAR( 255 ) NOT NULL,
|
||||
UNIQUE(`language_code`, `display_language_code`)
|
||||
)';
|
||||
|
||||
return self::create_table( 'icl_languages_translations', $sql );
|
||||
}
|
||||
|
||||
static function fill_languages_translations() {
|
||||
global $wpdb;
|
||||
|
||||
$languages_codes = icl_get_languages_codes();
|
||||
|
||||
$table_name = $wpdb->prefix . 'icl_languages_translations';
|
||||
|
||||
if ( ! self::create_languages_translations() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! self::languages_table_is_complete() ) {
|
||||
|
||||
// First truncate the table
|
||||
$wpdb->hide_errors();
|
||||
|
||||
$sql = 'TRUNCATE ' . $table_name;
|
||||
|
||||
$truncate_result = $wpdb->query( $sql );
|
||||
|
||||
$wpdb->show_errors();
|
||||
|
||||
if ( false !== $truncate_result ) {
|
||||
$index = 1;
|
||||
|
||||
$insert_sql_parts = array();
|
||||
$languages = self::get_languages_names();
|
||||
if ( $languages ) {
|
||||
foreach ( $languages as $lang => $val ) {
|
||||
foreach ( $val['tr'] as $k => $display ) {
|
||||
$k = self::fix_language_name( $k );
|
||||
if ( ! trim( $display ) ) {
|
||||
$display = $lang;
|
||||
}
|
||||
|
||||
$inserts_language_data = array(
|
||||
'id' => $index,
|
||||
'language_code' => $languages_codes[ $lang ],
|
||||
'display_language_code' => $languages_codes[ $k ],
|
||||
'name' => $display,
|
||||
);
|
||||
|
||||
$insert_sql_parts[] = $wpdb->prepare( '(%d, %s, %s, %s)', $inserts_language_data );
|
||||
$index ++;
|
||||
}
|
||||
}
|
||||
|
||||
$insert_sql = implode( ",\n", $insert_sql_parts );
|
||||
$insert_sql = "INSERT INTO {$table_name} (id, language_code, display_language_code, name) VALUES "
|
||||
. $insert_sql;
|
||||
|
||||
if ( $wpdb->query( $insert_sql ) === false ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static function create_table( $name, $table_sql ) {
|
||||
global $wpdb;
|
||||
|
||||
$table_name = $wpdb->prefix . $name;
|
||||
$found_table = (string) $wpdb->get_var( "SHOW TABLES LIKE '{$table_name}'" );
|
||||
|
||||
return 0 === strcasecmp( $found_table, $table_name )
|
||||
|| ( $wpdb->query(
|
||||
sprintf( 'CREATE TABLE IF NOT EXISTS `%s` ', $table_name )
|
||||
. $table_sql . ' '
|
||||
. self::get_charset_collate()
|
||||
) !== false );
|
||||
}
|
||||
|
||||
private static function create_flags() {
|
||||
|
||||
$sql = "(`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
|
||||
`lang_code` VARCHAR( 10 ) NOT NULL ,
|
||||
`flag` VARCHAR( 32 ) NOT NULL ,
|
||||
`from_template` TINYINT NOT NULL DEFAULT '0',
|
||||
UNIQUE (`lang_code`)
|
||||
)";
|
||||
|
||||
return self::create_table( 'icl_flags', $sql );
|
||||
}
|
||||
|
||||
public static function fill_flags() {
|
||||
global $wpdb;
|
||||
|
||||
if ( self::create_flags() === false ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$codes = $wpdb->get_col( "SELECT code FROM {$wpdb->prefix}icl_languages" );
|
||||
foreach ( $codes as $code ) {
|
||||
if ( ! $code || $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
"SELECT lang_code
|
||||
FROM {$wpdb->prefix}icl_flags
|
||||
WHERE lang_code = %s ",
|
||||
$code
|
||||
)
|
||||
)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
$code_parts = explode( '-', $code );
|
||||
|
||||
$file = 'nil.png';
|
||||
|
||||
if ( file_exists( WPML_PLUGIN_PATH . '/res/flags/' . $code . '.png' ) ) {
|
||||
$file = $code . '.png';
|
||||
} elseif ( file_exists( WPML_PLUGIN_PATH . '/res/flags/' . $code_parts[0] . '.png' ) ) {
|
||||
$file = $code_parts[0] . '.png';
|
||||
}
|
||||
|
||||
$wpdb->insert(
|
||||
$wpdb->prefix . 'icl_flags',
|
||||
array(
|
||||
'lang_code' => $code,
|
||||
'flag' => $file,
|
||||
'from_template' => 0,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static function insert_default_category( $lang_code ) {
|
||||
global $sitepress;
|
||||
|
||||
$default_language = $sitepress->get_default_language();
|
||||
if ( $lang_code === $default_language ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get default categories.
|
||||
$default_categories = $sitepress->get_setting( 'default_categories', array() );
|
||||
if ( isset( $default_categories[ $lang_code ] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$sitepress->switch_locale( $lang_code );
|
||||
$tr_cat = __( 'Uncategorized', 'sitepress' );
|
||||
$tr_cat = $tr_cat === 'Uncategorized' && $lang_code !== 'en' ? 'Uncategorized @' . $lang_code : $tr_cat;
|
||||
$tr_term = term_exists( $tr_cat, 'category' );
|
||||
$sitepress->switch_locale();
|
||||
|
||||
// check if the term already exists
|
||||
if ( $tr_term !== 0 && $tr_term !== null ) {
|
||||
$tmp = get_term( $tr_term['term_taxonomy_id'], 'category', ARRAY_A );
|
||||
} else {
|
||||
$tmp = wp_insert_term( $tr_cat, 'category' );
|
||||
}
|
||||
|
||||
// add it to settings['default_categories']
|
||||
$default_categories[ $lang_code ] = $tmp['term_taxonomy_id'];
|
||||
|
||||
$sitepress->set_default_categories( $default_categories );
|
||||
|
||||
// update translations table
|
||||
$default_category_trid = $sitepress->get_element_trid(
|
||||
get_option( 'default_category' ),
|
||||
'tax_category'
|
||||
);
|
||||
$sitepress->set_element_language_details(
|
||||
$tmp['term_taxonomy_id'],
|
||||
'tax_category',
|
||||
$default_category_trid,
|
||||
$lang_code,
|
||||
$default_language
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,462 @@
|
||||
<?php
|
||||
|
||||
class WPML_Installation extends WPML_WPDB_And_SP_User {
|
||||
|
||||
const WPML_START_VERSION_KEY = 'wpml_start_version';
|
||||
|
||||
public static function getStartVersion() {
|
||||
return get_option( self::WPML_START_VERSION_KEY, '0.0.0' );
|
||||
}
|
||||
|
||||
function go_to_setup1() {
|
||||
// Reverse $this->prepopulate_translations()
|
||||
$this->wpdb->query( "TRUNCATE TABLE {$this->wpdb->prefix}icl_translations" );
|
||||
|
||||
// Unset or reset sitepress settings
|
||||
$settings = $this->sitepress->get_settings();
|
||||
|
||||
unset(
|
||||
$settings['default_categories'],
|
||||
$settings['default_language'],
|
||||
$settings['setup_wizard_step']
|
||||
);
|
||||
|
||||
$settings['existing_content_language_verified'] = 0;
|
||||
$settings['active_languages'] = array();
|
||||
$GLOBALS['sitepress_settings']['existing_content_language_verified'] = $settings['existing_content_language_verified'];
|
||||
update_option( 'icl_sitepress_settings', $settings );
|
||||
|
||||
// Reverse $this->maybe_set_locale()
|
||||
$this->wpdb->query( "TRUNCATE TABLE {$this->wpdb->prefix}icl_locale_map" );
|
||||
|
||||
// Make sure no language is active
|
||||
$this->wpdb->update( $this->wpdb->prefix . 'icl_languages', array( 'active' => 0 ), array( 'active' => 1 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the locale in the icl_locale_map if it has not yet been set
|
||||
*
|
||||
* @param string $initial_language_code
|
||||
*/
|
||||
private function maybe_set_locale( $initial_language_code ) {
|
||||
$q = "SELECT code FROM {$this->wpdb->prefix}icl_locale_map WHERE code=%s";
|
||||
$q_prepared = $this->wpdb->prepare( $q, $initial_language_code );
|
||||
if ( ! $this->wpdb->get_var( $q_prepared ) ) {
|
||||
$q = "SELECT default_locale FROM {$this->wpdb->prefix}icl_languages WHERE code=%s";
|
||||
$q_prepared = $this->wpdb->prepare( $q, $initial_language_code );
|
||||
$default_locale = $this->wpdb->get_var( $q_prepared );
|
||||
if ( $default_locale ) {
|
||||
$this->wpdb->insert(
|
||||
$this->wpdb->prefix . 'icl_locale_map',
|
||||
array( 'code' => $initial_language_code, 'locale' => $default_locale )
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function finish_step2( $active_languages ) {
|
||||
return $this->set_active_languages( $active_languages );
|
||||
}
|
||||
|
||||
public function set_active_languages( $arr ) {
|
||||
$tmp = $this->sanitize_language_input( $arr );
|
||||
if ( (bool) $tmp === false ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ( $tmp as $code ) {
|
||||
$default_locale_prepared = $this->wpdb->prepare(
|
||||
"SELECT default_locale FROM {$this->wpdb->prefix}icl_languages WHERE code= %s LIMIT 1",
|
||||
$code
|
||||
);
|
||||
$default_locale = $this->wpdb->get_var( $default_locale_prepared );
|
||||
if ( $default_locale ) {
|
||||
$code_exists_prepared = $this->wpdb->prepare(
|
||||
"SELECT code FROM {$this->wpdb->prefix}icl_locale_map WHERE code = %s LIMIT 1",
|
||||
$code
|
||||
);
|
||||
$code_exists = $this->wpdb->get_var( $code_exists_prepared );
|
||||
if ( $code_exists ) {
|
||||
$this->wpdb->update(
|
||||
$this->wpdb->prefix . 'icl_locale_map',
|
||||
array( 'locale' => $default_locale ),
|
||||
array( 'code' => $code )
|
||||
);
|
||||
} else {
|
||||
$this->wpdb->insert(
|
||||
$this->wpdb->prefix . 'icl_locale_map',
|
||||
array( 'code' => $code, 'locale' => $default_locale )
|
||||
);
|
||||
}
|
||||
}
|
||||
SitePress_Setup::insert_default_category( $code );
|
||||
}
|
||||
|
||||
$this->wpdb->query(
|
||||
"UPDATE {$this->wpdb->prefix}icl_languages SET active = 1 WHERE code IN (" . wpml_prepare_in( $tmp ) . " ) "
|
||||
);
|
||||
$this->wpdb->query(
|
||||
"UPDATE {$this->wpdb->prefix}icl_languages SET active = 0 WHERE code NOT IN (" . wpml_prepare_in( $tmp ) . " ) "
|
||||
);
|
||||
$this->updated_active_languages();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function sanitize_language_input( $lang_codes ) {
|
||||
$languages = $this->sitepress->get_languages( false, false, true );
|
||||
$sanitized_codes = array();
|
||||
$lang_codes = array_filter( array_unique( $lang_codes ) );
|
||||
foreach ( $lang_codes as $code ) {
|
||||
$code = esc_sql( trim( $code ) );
|
||||
if ( isset( $languages[ $code ] ) ) {
|
||||
$sanitized_codes[] = $code;
|
||||
}
|
||||
}
|
||||
|
||||
return $sanitized_codes;
|
||||
}
|
||||
|
||||
public function finish_installation( ) {
|
||||
icl_set_setting( 'store_frontend_cookie', 1 );
|
||||
|
||||
icl_set_setting( 'setup_complete', 1, true );
|
||||
|
||||
update_option( self::WPML_START_VERSION_KEY, ICL_SITEPRESS_VERSION );
|
||||
|
||||
do_action( 'wpml_setup_completed' );
|
||||
}
|
||||
|
||||
public function store_site_key( $site_key = false ) {
|
||||
if ( $site_key ) {
|
||||
icl_set_setting( 'site_key', $site_key, true );
|
||||
}
|
||||
}
|
||||
|
||||
public function finish_step3() {
|
||||
$this->maybe_move_setup( 4 );
|
||||
}
|
||||
|
||||
private function maybe_move_setup( $step ) {
|
||||
$setup_complete = icl_get_setting( 'setup_complete' );
|
||||
if ( empty( $setup_complete ) ) {
|
||||
icl_set_setting( 'setup_wizard_step', $step, true );
|
||||
}
|
||||
}
|
||||
|
||||
private function updated_active_languages() {
|
||||
wp_cache_init();
|
||||
icl_cache_clear();
|
||||
$this->refresh_active_lang_cache( wpml_get_setting_filter( false, 'default_language' ), true );
|
||||
$this->update_languages_order();
|
||||
wpml_reload_active_languages_setting( true );
|
||||
$active_langs = $this->sitepress->get_active_languages( true );
|
||||
$this->maybe_move_setup( 3 );
|
||||
if ( count( $active_langs ) > 1 ) {
|
||||
icl_set_setting( 'dont_show_help_admin_notice', true );
|
||||
}
|
||||
}
|
||||
|
||||
public function finish_step1( $initial_language_code ) {
|
||||
$this->set_initial_default_category( $initial_language_code );
|
||||
$this->prepopulate_translations( $initial_language_code );
|
||||
$this->update_active_language( $initial_language_code );
|
||||
$admin_language = $this->get_admin_language( $initial_language_code );
|
||||
$this->maybe_set_locale( $admin_language );
|
||||
icl_set_setting( 'existing_content_language_verified', 1 );
|
||||
icl_set_setting( 'default_language', $initial_language_code );
|
||||
icl_set_setting( 'setup_wizard_step', 2 );
|
||||
icl_save_settings();
|
||||
wp_cache_flush();
|
||||
$this->refresh_active_lang_cache( $initial_language_code );
|
||||
add_filter( 'locale', array( $this->sitepress, 'locale_filter' ), 10, 1 );
|
||||
|
||||
if ( ! array_key_exists( 'wp_styles', $GLOBALS ) || ! $GLOBALS['wp_styles'] ) {
|
||||
wp_styles();
|
||||
}
|
||||
|
||||
if ( $this->sitepress->is_rtl( $admin_language ) ) {
|
||||
$GLOBALS['text_direction'] = 'rtl';
|
||||
$GLOBALS['wp_styles']->text_direction = 'rtl';
|
||||
} else {
|
||||
$GLOBALS['text_direction'] = 'ltr';
|
||||
$GLOBALS['wp_styles']->text_direction = 'ltr';
|
||||
}
|
||||
|
||||
$GLOBALS['wp_locale'] = new WP_Locale();
|
||||
$GLOBALS['locale'] = $this->sitepress->get_locale( $admin_language );
|
||||
|
||||
do_action( 'icl_initial_language_set' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $initial_language_code
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_admin_language( $initial_language_code ) {
|
||||
$user_locale = get_user_meta( get_current_user_id(), 'locale', true );
|
||||
|
||||
if ( $user_locale ) {
|
||||
$lang = $this->sitepress->get_language_code_from_locale( $user_locale );
|
||||
|
||||
if ( $lang ) {
|
||||
return $lang;
|
||||
}
|
||||
}
|
||||
|
||||
return $initial_language_code;
|
||||
|
||||
}
|
||||
|
||||
private function set_initial_default_category( $initial_lang ) {
|
||||
$blog_default_cat = get_option( 'default_category' );
|
||||
$blog_default_cat_tax_id = $this->wpdb->get_var(
|
||||
$this->wpdb->prepare(
|
||||
" SELECT term_taxonomy_id
|
||||
FROM {$this->wpdb->term_taxonomy}
|
||||
WHERE term_id=%d
|
||||
AND taxonomy='category'",
|
||||
$blog_default_cat
|
||||
)
|
||||
);
|
||||
|
||||
if ($initial_lang !== 'en') {
|
||||
$this->rename_default_category_of_initial_language( $initial_lang, $blog_default_cat );
|
||||
}
|
||||
|
||||
|
||||
icl_set_setting( 'default_categories', array( $initial_lang => $blog_default_cat_tax_id ), true );
|
||||
}
|
||||
|
||||
private function rename_default_category_of_initial_language( $initial_lang, $category_id ) {
|
||||
global $sitepress;
|
||||
$sitepress->switch_locale( $initial_lang );
|
||||
$tr_cat = __( 'Uncategorized', 'sitepress' );
|
||||
$tr_cat = $tr_cat === 'Uncategorized' ? 'Uncategorized @' . $initial_lang : $tr_cat;
|
||||
$sitepress->switch_locale();
|
||||
|
||||
wp_update_term( $category_id, 'category', array(
|
||||
'name' => $tr_cat,
|
||||
'slug' => sanitize_title( $tr_cat ),
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $display_language
|
||||
* @param bool $active_only
|
||||
* @param bool $major_first
|
||||
* @param string $order_by
|
||||
*
|
||||
* @return array<string,\stdClass>
|
||||
*/
|
||||
public function refresh_active_lang_cache( $display_language, $active_only = false, $major_first = false, $order_by = 'english_name' ) {
|
||||
$active_snippet = $active_only ? " l.active = 1 AND " : "";
|
||||
$res_query
|
||||
= "
|
||||
SELECT
|
||||
l.code,
|
||||
l.id,
|
||||
english_name,
|
||||
nt.name AS native_name,
|
||||
major,
|
||||
active,
|
||||
default_locale,
|
||||
encode_url,
|
||||
tag,
|
||||
lt.name AS display_name
|
||||
FROM {$this->wpdb->prefix}icl_languages l
|
||||
JOIN {$this->wpdb->prefix}icl_languages_translations nt
|
||||
ON ( nt.language_code = l.code AND nt.display_language_code = l.code )
|
||||
LEFT OUTER JOIN {$this->wpdb->prefix}icl_languages_translations lt ON l.code=lt.language_code
|
||||
WHERE {$active_snippet}
|
||||
( lt.display_language_code = %s
|
||||
OR (lt.display_language_code = 'en'
|
||||
AND NOT EXISTS ( SELECT *
|
||||
FROM {$this->wpdb->prefix}icl_languages_translations ls
|
||||
WHERE ls.language_code = l.code
|
||||
AND ls.display_language_code = %s ) ) )
|
||||
GROUP BY l.code";
|
||||
|
||||
|
||||
$order_by_fields = array();
|
||||
if ( $major_first ) {
|
||||
$order_by_fields[] = 'major DESC';
|
||||
}
|
||||
$order_by_fields[] = ( $order_by ? $order_by : 'english_name' ) . ' ASC';
|
||||
|
||||
$res_query .= PHP_EOL . 'ORDER BY ' . implode( ', ', $order_by_fields );
|
||||
|
||||
$res_query_prepared = $this->wpdb->prepare( $res_query, $display_language, $display_language );
|
||||
$res = $this->wpdb->get_results( $res_query_prepared, ARRAY_A );
|
||||
$languages = array();
|
||||
|
||||
$icl_cache = $this->sitepress->get_language_name_cache();
|
||||
foreach ( (array) $res as $r ) {
|
||||
$languages[ $r[ 'code' ] ] = $r;
|
||||
$icl_cache->set( 'language_details_' . $r['code'] . $display_language, $r );
|
||||
}
|
||||
|
||||
if ( $active_only ) {
|
||||
$icl_cache->set( 'in_language_' . $display_language . '_' . $major_first . '_' . $order_by, $languages );
|
||||
} else {
|
||||
$icl_cache->set( 'all_language_' . $display_language . '_' . $major_first . '_' . $order_by, $languages );
|
||||
}
|
||||
|
||||
$icl_cache->save_cache_if_required();
|
||||
|
||||
return $languages;
|
||||
}
|
||||
|
||||
private function update_languages_order() {
|
||||
$needs_update = false;
|
||||
$current_order = $this->sitepress->get_setting( 'languages_order', array() );
|
||||
if ( ! is_array( $current_order ) ) {
|
||||
$current_order = array();
|
||||
}
|
||||
$languages = $this->sitepress->get_languages( false, false, true );
|
||||
$new_order = $current_order;
|
||||
foreach ( $languages as $language_code => $language ) {
|
||||
if ( ! in_array( $language_code, $new_order ) && '1' === $language['active'] ) {
|
||||
$new_order[] = $language_code;
|
||||
$needs_update = true;
|
||||
}
|
||||
if ( in_array( $language_code, $new_order ) && '1' !== $language['active'] ) {
|
||||
$new_order = array_diff( $new_order, array( $language_code ) );
|
||||
$needs_update = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $needs_update ) {
|
||||
$new_order = array_values( $new_order );
|
||||
$this->sitepress->set_setting( 'languages_order', $new_order, true );
|
||||
}
|
||||
}
|
||||
|
||||
private function prepopulate_translations( $lang ) {
|
||||
$existing_lang_verified = icl_get_setting( 'existing_content_language_verified' );
|
||||
if ( ! empty( $existing_lang_verified ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
icl_cache_clear();
|
||||
|
||||
// case of icl_sitepress_settings accidentally lost
|
||||
// if there's at least one translation do not initialize the languages for elements
|
||||
$one_translation = $this->wpdb->get_var(
|
||||
$this->wpdb->prepare(
|
||||
"SELECT translation_id FROM {$this->wpdb->prefix}icl_translations WHERE language_code<>%s",
|
||||
$lang
|
||||
)
|
||||
);
|
||||
if ( $one_translation ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->wpdb->query( "TRUNCATE TABLE {$this->wpdb->prefix}icl_translations" );
|
||||
$this->wpdb->query(
|
||||
$this->wpdb->prepare(
|
||||
"
|
||||
INSERT INTO {$this->wpdb->prefix}icl_translations(element_type, element_id, trid, language_code, source_language_code)
|
||||
SELECT CONCAT('post_',post_type), ID, ID, %s, NULL FROM {$this->wpdb->posts} WHERE post_status IN ('draft', 'publish','schedule','future','private', 'pending')
|
||||
",
|
||||
$lang
|
||||
)
|
||||
);
|
||||
|
||||
$maxtrid = 1 + (int) $this->wpdb->get_var( "SELECT MAX(trid) FROM {$this->wpdb->prefix}icl_translations" );
|
||||
|
||||
global $wp_taxonomies;
|
||||
$taxonomies = array_keys( (array) $wp_taxonomies );
|
||||
foreach ( $taxonomies as $tax ) {
|
||||
$element_type = 'tax_' . $tax;
|
||||
$insert_query
|
||||
= "
|
||||
INSERT INTO {$this->wpdb->prefix}icl_translations(element_type, element_id, trid, language_code, source_language_code)
|
||||
SELECT %s, term_taxonomy_id, %d+term_taxonomy_id, %s, NULL FROM {$this->wpdb->term_taxonomy} WHERE taxonomy = %s
|
||||
";
|
||||
$insert_prepare = $this->wpdb->prepare( $insert_query, array( $element_type, $maxtrid, $lang, $tax ) );
|
||||
$this->wpdb->query( $insert_prepare );
|
||||
$maxtrid = 1 + (int) $this->wpdb->get_var( "SELECT MAX(trid) FROM {$this->wpdb->prefix}icl_translations" );
|
||||
}
|
||||
|
||||
$this->wpdb->query(
|
||||
$this->wpdb->prepare(
|
||||
"
|
||||
INSERT INTO {$this->wpdb->prefix}icl_translations(element_type, element_id, trid, language_code, source_language_code)
|
||||
SELECT 'comment', comment_ID, {$maxtrid}+comment_ID, %s, NULL FROM {$this->wpdb->comments}
|
||||
",
|
||||
$lang
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function update_active_language( $lang ) {
|
||||
$this->wpdb->update( $this->wpdb->prefix . 'icl_languages', array( 'active' => '1' ), array( 'code' => $lang ) );
|
||||
}
|
||||
|
||||
function reset_language_data() {
|
||||
global $sitepress, $wpdb;
|
||||
|
||||
$active = $this->wpdb->get_col( "SELECT code FROM {$this->wpdb->prefix}icl_languages WHERE active = 1" );
|
||||
$this->wpdb->query( "TRUNCATE TABLE `{$this->wpdb->prefix}icl_languages`" );
|
||||
SitePress_Setup::fill_languages();
|
||||
$this->wpdb->query( "TRUNCATE TABLE `{$this->wpdb->prefix}icl_languages_translations`" );
|
||||
SitePress_Setup::fill_languages_translations();
|
||||
$this->wpdb->query( "TRUNCATE TABLE `{$this->wpdb->prefix}icl_flags`" );
|
||||
SitePress_Setup::fill_flags();
|
||||
|
||||
//restore active
|
||||
$this->wpdb->query(
|
||||
"UPDATE {$this->wpdb->prefix}icl_languages SET active=1 WHERE code IN(" . wpml_prepare_in( $active ) . ")"
|
||||
);
|
||||
|
||||
$this->wpdb->update( $this->wpdb->prefix . 'icl_flags', array( 'from_template' => 0 ), null );
|
||||
|
||||
$codes = $this->wpdb->get_col( "SELECT code FROM {$this->wpdb->prefix}icl_languages" );
|
||||
foreach ( $codes as $code ) {
|
||||
if ( ! $code || $this->wpdb->get_var(
|
||||
$this->wpdb->prepare( "SELECT lang_code FROM {$this->wpdb->prefix}icl_flags WHERE lang_code = %s", $code )
|
||||
)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
if ( ! file_exists( WPML_PLUGIN_PATH . '/res/flags/' . $code . '.png' ) ) {
|
||||
$file = 'nil.png';
|
||||
} else {
|
||||
$file = $code . '.png';
|
||||
}
|
||||
$this->wpdb->insert(
|
||||
$this->wpdb->prefix . 'icl_flags',
|
||||
array( 'lang_code' => $code, 'flag' => $file, 'from_template' => 0 )
|
||||
);
|
||||
}
|
||||
|
||||
$last_default_language = $this->sitepress !== null ? $this->sitepress->get_default_language() : 'en';
|
||||
if ( ! in_array( $last_default_language, $codes ) ) {
|
||||
$last_active_languages = $this->sitepress->get_active_languages();
|
||||
foreach ( $last_active_languages as $code => $last_active_language ) {
|
||||
if ( in_array( $code, $codes ) ) {
|
||||
$this->sitepress->set_default_language( $code );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$language_pair_records = new WPML_Language_Pair_Records( $wpdb, new WPML_Language_Records( $wpdb ) );
|
||||
|
||||
$users = get_users( [ 'fields' => [ 'ID' ] ] );
|
||||
|
||||
foreach ( $users as $user ) {
|
||||
$language_pair_records->remove_invalid_language_pairs( $user->ID );
|
||||
}
|
||||
|
||||
icl_cache_clear();
|
||||
|
||||
$sitepress->get_translations_cache()->clear();
|
||||
$sitepress->clear_flags_cache();
|
||||
$sitepress->get_language_name_cache()->clear();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
class WPML_Media_Duplication_Setup {
|
||||
|
||||
const MEDIA_SETTINGS_OPTION_KEY = '_wpml_media';
|
||||
|
||||
public static function initialize_settings() {
|
||||
if ( ! get_option( self::MEDIA_SETTINGS_OPTION_KEY, [] ) ) {
|
||||
$settings = [
|
||||
'new_content_settings' => [
|
||||
'always_translate_media' => true,
|
||||
'duplicate_media' => true,
|
||||
'duplicate_featured' => true,
|
||||
],
|
||||
'translate_media_library_texts' => false,
|
||||
];
|
||||
update_option( self::MEDIA_SETTINGS_OPTION_KEY, $settings );
|
||||
}
|
||||
}
|
||||
|
||||
public static function isTranslateMediaLibraryTextsEnabled() {
|
||||
$settings = get_option( self::MEDIA_SETTINGS_OPTION_KEY, [] );
|
||||
return \WPML\FP\Obj::propOr(false, 'translate_media_library_texts', $settings);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,315 @@
|
||||
<?php
|
||||
|
||||
class WPML_Settings_Helper {
|
||||
|
||||
const KEY_CPT_UNLOCK_OPTION = 'custom_posts_unlocked_option';
|
||||
const KEY_TAXONOMY_UNLOCK_OPTION = 'taxonomies_unlocked_option';
|
||||
|
||||
/** @var SitePress */
|
||||
protected $sitepress;
|
||||
|
||||
/** @var WPML_Post_Translation */
|
||||
protected $post_translation;
|
||||
|
||||
/**
|
||||
* @var WPML_Settings_Filters
|
||||
*/
|
||||
private $filters;
|
||||
|
||||
/**
|
||||
* @param WPML_Post_Translation $post_translation
|
||||
* @param SitePress $sitepress
|
||||
*/
|
||||
public function __construct( WPML_Post_Translation $post_translation, SitePress $sitepress ) {
|
||||
$this->sitepress = $sitepress;
|
||||
$this->post_translation = $post_translation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_Settings_Filters
|
||||
*/
|
||||
private function get_filters() {
|
||||
if ( ! $this->filters ) {
|
||||
$this->filters = new WPML_Settings_Filters();
|
||||
}
|
||||
|
||||
return $this->filters;
|
||||
}
|
||||
|
||||
function set_post_type_translatable( $post_type ) {
|
||||
$this->set_post_type_translate_mode( $post_type, WPML_CONTENT_TYPE_TRANSLATE );
|
||||
}
|
||||
|
||||
function set_post_type_display_as_translated( $post_type ) {
|
||||
$this->set_post_type_translate_mode( $post_type, WPML_CONTENT_TYPE_DISPLAY_AS_IF_TRANSLATED );
|
||||
}
|
||||
|
||||
function set_post_type_not_translatable( $post_type ) {
|
||||
$sync_settings = $this->sitepress->get_setting( 'custom_posts_sync_option', array() );
|
||||
if ( isset( $sync_settings[ $post_type ] ) ) {
|
||||
unset( $sync_settings[ $post_type ] );
|
||||
}
|
||||
|
||||
$this->clear_ls_languages_cache();
|
||||
$this->sitepress->set_setting( 'custom_posts_sync_option', $sync_settings, true );
|
||||
}
|
||||
|
||||
private function set_post_type_translate_mode( $post_type, $mode ) {
|
||||
$sync_settings = $this->sitepress->get_setting( 'custom_posts_sync_option', array() );
|
||||
$sync_settings[ $post_type ] = $mode;
|
||||
$this->clear_ls_languages_cache();
|
||||
$this->sitepress->set_setting( 'custom_posts_sync_option', $sync_settings, true );
|
||||
$this->sitepress->verify_post_translations( $post_type );
|
||||
$this->post_translation->reload();
|
||||
}
|
||||
|
||||
function set_taxonomy_translatable( $taxonomy ) {
|
||||
$this->set_taxonomy_translatable_mode( $taxonomy, WPML_CONTENT_TYPE_TRANSLATE );
|
||||
}
|
||||
|
||||
function set_taxonomy_display_as_translated( $taxonomy ) {
|
||||
$this->set_taxonomy_translatable_mode( $taxonomy, WPML_CONTENT_TYPE_DISPLAY_AS_IF_TRANSLATED );
|
||||
}
|
||||
|
||||
function set_taxonomy_translatable_mode( $taxonomy, $mode ) {
|
||||
$sync_settings = $this->sitepress->get_setting( 'taxonomies_sync_option', array() );
|
||||
$sync_settings[ $taxonomy ] = $mode;
|
||||
$this->clear_ls_languages_cache();
|
||||
$this->sitepress->set_setting( 'taxonomies_sync_option', $sync_settings, true );
|
||||
$this->sitepress->verify_taxonomy_translations( $taxonomy );
|
||||
}
|
||||
|
||||
function set_taxonomy_not_translatable( $taxonomy ) {
|
||||
$sync_settings = $this->sitepress->get_setting( 'taxonomies_sync_option', array() );
|
||||
if ( isset( $sync_settings[ $taxonomy ] ) ) {
|
||||
unset( $sync_settings[ $taxonomy ] );
|
||||
}
|
||||
|
||||
$this->clear_ls_languages_cache();
|
||||
$this->sitepress->set_setting( 'taxonomies_sync_option', $sync_settings, true );
|
||||
}
|
||||
|
||||
function set_post_type_translation_unlocked_option( $post_type, $unlocked = true ) {
|
||||
|
||||
$unlocked_settings = $this->sitepress->get_setting( 'custom_posts_unlocked_option', array() );
|
||||
|
||||
$unlocked_settings[ $post_type ] = $unlocked ? 1 : 0;
|
||||
|
||||
$this->sitepress->set_setting( 'custom_posts_unlocked_option', $unlocked_settings, true );
|
||||
}
|
||||
|
||||
function set_taxonomy_translation_unlocked_option( $taxonomy, $unlocked = true ) {
|
||||
|
||||
$unlocked_settings = $this->sitepress->get_setting( 'taxonomies_unlocked_option', array() );
|
||||
|
||||
$unlocked_settings[ $taxonomy ] = $unlocked ? 1 : 0;
|
||||
|
||||
$this->sitepress->set_setting( 'taxonomies_unlocked_option', $unlocked_settings, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use the action `wpml_activate_slug_translation` instead
|
||||
* or `WPML_ST_Post_Slug_Translation_Settings` instead (on ST side)
|
||||
*
|
||||
* @param string $post_type
|
||||
*/
|
||||
function activate_slug_translation( $post_type ) {
|
||||
$slug_settings = $this->sitepress->get_setting( 'posts_slug_translation', array() );
|
||||
$slug_settings['types'] = isset( $slug_settings['types'] )
|
||||
? $slug_settings['types'] : array();
|
||||
$slug_settings['types'][ $post_type ] = 1;
|
||||
/** @deprected key `on`, use option `wpml_base_slug_translation` instead */
|
||||
$slug_settings['on'] = 1;
|
||||
|
||||
$this->clear_ls_languages_cache();
|
||||
$this->sitepress->set_setting( 'posts_slug_translation', $slug_settings, true );
|
||||
update_option( 'wpml_base_slug_translation', 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use `WPML_ST_Post_Slug_Translation_Settings` instead (on ST side)
|
||||
*
|
||||
* @param string $post_type
|
||||
*/
|
||||
function deactivate_slug_translation( $post_type ) {
|
||||
$slug_settings = $this->sitepress->get_setting( 'posts_slug_translation', array() );
|
||||
if ( isset( $slug_settings['types'][ $post_type ] ) ) {
|
||||
unset( $slug_settings['types'][ $post_type ] );
|
||||
}
|
||||
|
||||
$this->clear_ls_languages_cache();
|
||||
$this->sitepress->set_setting( 'posts_slug_translation', $slug_settings, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array[] $taxs_obj_type
|
||||
*
|
||||
* @see \WPML_Config::maybe_add_filter
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function _override_get_translatable_taxonomies( $taxs_obj_type ) {
|
||||
global $wp_taxonomies;
|
||||
|
||||
$taxs = $taxs_obj_type['taxs'];
|
||||
$object_type = $taxs_obj_type['object_type'];
|
||||
foreach ( $taxs as $k => $tax ) {
|
||||
if ( ! $this->sitepress->is_translated_taxonomy( $tax ) ) {
|
||||
unset( $taxs[ $k ] );
|
||||
}
|
||||
}
|
||||
$tm_settings = $this->sitepress->get_setting( 'translation-management', array() );
|
||||
foreach ( $tm_settings['taxonomies_readonly_config'] as $tx => $translate ) {
|
||||
if ( $translate
|
||||
&& ! in_array( $tx, $taxs )
|
||||
&& isset( $wp_taxonomies[ $tx ] )
|
||||
&& in_array( $object_type, $wp_taxonomies[ $tx ]->object_type )
|
||||
) {
|
||||
$taxs[] = $tx;
|
||||
}
|
||||
}
|
||||
|
||||
$ret = array(
|
||||
'taxs' => $taxs,
|
||||
'object_type' => $taxs_obj_type['object_type'],
|
||||
);
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array[] $types
|
||||
*
|
||||
* @see \WPML_Config::maybe_add_filter
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function _override_get_translatable_documents( $types ) {
|
||||
$tm_settings = $this->sitepress->get_setting( 'translation-management', array() );
|
||||
$cpt_unlocked_options = $this->sitepress->get_setting( 'custom_posts_unlocked_option', array() );
|
||||
foreach ( $types as $k => $type ) {
|
||||
if ( isset( $tm_settings['custom-types_readonly_config'][ $k ] )
|
||||
&& ! $tm_settings['custom-types_readonly_config'][ $k ]
|
||||
) {
|
||||
unset( $types[ $k ] );
|
||||
}
|
||||
}
|
||||
$types = $this->get_filters()->get_translatable_documents( $types, $tm_settings['custom-types_readonly_config'], $cpt_unlocked_options );
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the custom post type translation settings with new settings.
|
||||
*
|
||||
* @param array $new_options
|
||||
*
|
||||
* @uses \SitePress::get_setting
|
||||
* @uses \SitePress::save_settings
|
||||
*
|
||||
* @return array new custom post type settings after the update
|
||||
*/
|
||||
function update_cpt_sync_settings( array $new_options ) {
|
||||
$cpt_sync_options = $this->sitepress->get_setting( WPML_Element_Sync_Settings_Factory::KEY_POST_SYNC_OPTION, array() );
|
||||
$cpt_sync_options = array_merge( $cpt_sync_options, $new_options );
|
||||
$new_options = array_filter( $new_options );
|
||||
|
||||
$this->clear_ls_languages_cache();
|
||||
|
||||
do_action( 'wpml_verify_post_translations', $new_options );
|
||||
do_action( 'wpml_save_cpt_sync_settings' );
|
||||
$this->sitepress->set_setting( WPML_Element_Sync_Settings_Factory::KEY_POST_SYNC_OPTION, $cpt_sync_options, true );
|
||||
|
||||
return $cpt_sync_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the taxonomy type translation settings with new settings.
|
||||
*
|
||||
* @param array $new_options
|
||||
*
|
||||
* @uses \SitePress::get_setting
|
||||
* @uses \SitePress::save_settings
|
||||
*
|
||||
* @return array new taxonomy type settings after the update
|
||||
*/
|
||||
function update_taxonomy_sync_settings( array $new_options ) {
|
||||
$taxonomy_sync_options = $this->sitepress->get_setting( WPML_Element_Sync_Settings_Factory::KEY_TAX_SYNC_OPTION, [] );
|
||||
$changed_sync_options = array_diff_assoc( $new_options, $taxonomy_sync_options );
|
||||
$taxonomy_sync_options = array_merge( $taxonomy_sync_options, $new_options );
|
||||
|
||||
foreach ( $changed_sync_options as $taxonomy_name => $taxonomy_sync_option ) {
|
||||
$this->sitepress->verify_taxonomy_translations( $taxonomy_name );
|
||||
}
|
||||
|
||||
$this->clear_ls_languages_cache();
|
||||
|
||||
do_action( 'wpml_save_taxonomy_sync_settings' );
|
||||
$this->sitepress->set_setting( WPML_Element_Sync_Settings_Factory::KEY_TAX_SYNC_OPTION, $taxonomy_sync_options, true );
|
||||
|
||||
return $taxonomy_sync_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the custom post type unlocked settings with new settings.
|
||||
*
|
||||
* @param array $unlock_options
|
||||
*
|
||||
* @uses \SitePress::get_setting
|
||||
* @uses \SitePress::save_settings
|
||||
*
|
||||
* @return array new custom post type unlocked settings after the update
|
||||
*/
|
||||
function update_cpt_unlocked_settings( array $unlock_options ) {
|
||||
return $this->update_unlocked_settings( $unlock_options, self::KEY_CPT_UNLOCK_OPTION );
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the taxonomy type unlocked settings with new settings.
|
||||
*
|
||||
* @param array $unlock_options
|
||||
*
|
||||
* @uses \SitePress::get_setting
|
||||
* @uses \SitePress::save_settings
|
||||
*
|
||||
* @return array new taxonomy type unlocked settings after the update
|
||||
*/
|
||||
function update_taxonomy_unlocked_settings( array $unlock_options ) {
|
||||
return $this->update_unlocked_settings( $unlock_options, self::KEY_TAXONOMY_UNLOCK_OPTION );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $unlock_options
|
||||
* @param string $setting_key
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function update_unlocked_settings( array $unlock_options, $setting_key ) {
|
||||
$cpt_unlock_options = $this->sitepress->get_setting( $setting_key, array() );
|
||||
$cpt_unlock_options = array_merge( $cpt_unlock_options, $unlock_options );
|
||||
$this->sitepress->set_setting( $setting_key, $cpt_unlock_options, true );
|
||||
return $cpt_unlock_options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $config_type
|
||||
*/
|
||||
function maybe_add_filter( $config_type ) {
|
||||
if ( $config_type === 'taxonomies' ) {
|
||||
add_filter(
|
||||
'get_translatable_taxonomies',
|
||||
array( $this, '_override_get_translatable_taxonomies' )
|
||||
);
|
||||
} elseif ( $config_type === 'custom-types' ) {
|
||||
add_filter(
|
||||
'get_translatable_documents',
|
||||
array( $this, '_override_get_translatable_documents' )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function clear_ls_languages_cache() {
|
||||
$cache = new WPML_WP_Cache( 'ls_languages' );
|
||||
$cache->flush_group_cache();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Nav_Menu_Actions
|
||||
*
|
||||
* @package wpml-core
|
||||
* @subpackage taxonomy-term-translation
|
||||
*/
|
||||
class WPML_Nav_Menu_Actions extends WPML_Full_Translation_API {
|
||||
|
||||
/**
|
||||
* @param SitePress $sitepress
|
||||
* @param wpdb $wpdb
|
||||
* @param WPML_Post_Translation $post_translations
|
||||
* @param WPML_Term_Translation $term_translations
|
||||
*/
|
||||
public function __construct( &$sitepress, &$wpdb, &$post_translations, &$term_translations ) {
|
||||
parent::__construct( $sitepress, $wpdb, $post_translations, $term_translations );
|
||||
add_action( 'wp_delete_nav_menu', array( $this, 'wp_delete_nav_menu' ) );
|
||||
add_action( 'wp_create_nav_menu', array( $this, 'wp_update_nav_menu' ), 10, 2 );
|
||||
add_action( 'wp_update_nav_menu', array( $this, 'wp_update_nav_menu' ), 10, 2 );
|
||||
add_action( 'wp_update_nav_menu_item', array( $this, 'wp_update_nav_menu_item' ), 10, 3 );
|
||||
add_action( 'delete_post', array( $this, 'wp_delete_nav_menu_item' ) );
|
||||
add_filter( 'pre_update_option_theme_mods_' . get_option( 'stylesheet' ), array( $this, 'pre_update_theme_mods_theme' ) );
|
||||
if ( is_admin() ) {
|
||||
add_filter( 'theme_mod_nav_menu_locations', array( $this, 'theme_mod_nav_menu_locations' ) );
|
||||
}
|
||||
}
|
||||
|
||||
public function wp_delete_nav_menu( $id ) {
|
||||
$menu_id_tt = $this->wpdb->get_var(
|
||||
$this->wpdb->prepare(
|
||||
"SELECT term_taxonomy_id FROM {$this->wpdb->term_taxonomy} WHERE term_id=%d AND taxonomy='nav_menu'",
|
||||
$id
|
||||
)
|
||||
);
|
||||
|
||||
$update_args = array(
|
||||
'element_id' => $menu_id_tt,
|
||||
'element_type' => 'tax_nav_menu',
|
||||
'context' => 'tax',
|
||||
);
|
||||
do_action( 'wpml_translation_update', array_merge( $update_args, array( 'type' => 'before_delete' ) ) );
|
||||
|
||||
$q = "DELETE FROM {$this->wpdb->prefix}icl_translations WHERE element_id=%d AND element_type='tax_nav_menu' LIMIT 1";
|
||||
$q_prepared = $this->wpdb->prepare( $q, $menu_id_tt );
|
||||
$this->wpdb->query( $q_prepared );
|
||||
|
||||
do_action( 'wpml_translation_update', array_merge( $update_args, array( 'type' => 'after_delete' ) ) );
|
||||
}
|
||||
|
||||
function wp_update_nav_menu( $menu_id, $menu_data = null ) {
|
||||
if ( $menu_data ) {
|
||||
$trid = $this->get_trid_from_post_data();
|
||||
$language_code = $this->get_save_lang( $menu_id );
|
||||
$menu_id_tt = $this->wpdb->get_var(
|
||||
$this->wpdb->prepare(
|
||||
"SELECT term_taxonomy_id FROM {$this->wpdb->term_taxonomy} WHERE term_id=%d AND taxonomy='nav_menu' LIMIT 1",
|
||||
$menu_id
|
||||
)
|
||||
);
|
||||
$this->term_translations->reload();
|
||||
$this->sitepress->set_element_language_details( $menu_id_tt, 'tax_nav_menu', $trid, $language_code );
|
||||
}
|
||||
}
|
||||
|
||||
function wp_update_nav_menu_item( $menu_id, $menu_item_db_id, $args ) {
|
||||
$menu_lang = $this->term_translations->lang_code_by_termid( $menu_id );
|
||||
$trid = $this->post_translations->get_element_trid( $menu_item_db_id );
|
||||
if ( array_key_exists( 'menu-item-type', $args )
|
||||
&& ( $args['menu-item-type'] === 'post_type' || $args['menu-item-type'] === 'taxonomy' )
|
||||
&& array_key_exists( 'menu-item-object-id', $args )
|
||||
&& $menu_id > 0
|
||||
) {
|
||||
$language_code_item = $args['menu-item-type'] === 'post_type'
|
||||
? $this->post_translations->get_element_lang_code( $args['menu-item-object-id'] )
|
||||
: $this->term_translations->lang_code_by_termid( $args['menu-item-object-id'] );
|
||||
$language_code_item = $language_code_item ? $language_code_item : $this->sitepress->get_current_language();
|
||||
if ( $language_code_item !== $menu_lang ) {
|
||||
wp_remove_object_terms( (int) $menu_item_db_id, (int) $menu_id, 'nav_menu' );
|
||||
}
|
||||
}
|
||||
|
||||
$language_code = isset( $language_code_item ) && $language_code_item
|
||||
? $language_code_item : ( $menu_lang ? $menu_lang : $this->sitepress->get_current_language() );
|
||||
$this->sitepress->set_element_language_details( $menu_item_db_id, 'post_nav_menu_item', $trid, $language_code );
|
||||
}
|
||||
|
||||
public function wp_delete_nav_menu_item( $menu_item_id ) {
|
||||
$post = get_post( $menu_item_id );
|
||||
if ( ! empty( $post->post_type ) && $post->post_type == 'nav_menu_item' ) {
|
||||
|
||||
$update_args = array(
|
||||
'element_id' => $menu_item_id,
|
||||
'element_type' => 'post_nav_menu_item',
|
||||
'context' => 'post',
|
||||
);
|
||||
|
||||
do_action( 'wpml_translation_update', array_merge( $update_args, array( 'type' => 'before_delete' ) ) );
|
||||
|
||||
$q = "DELETE FROM {$this->wpdb->prefix}icl_translations WHERE element_id=%d AND element_type='post_nav_menu_item' LIMIT 1";
|
||||
$q_prepared = $this->wpdb->prepare( $q, $menu_item_id );
|
||||
$this->wpdb->query( $q_prepared );
|
||||
|
||||
do_action( 'wpml_translation_update', array_merge( $update_args, array( 'type' => 'after_delete' ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
public function pre_update_theme_mods_theme( $val ) {
|
||||
$default_language = $this->sitepress->get_default_language();
|
||||
$current_language = $this->sitepress->get_current_language();
|
||||
|
||||
if ( isset( $val['nav_menu_locations'] )
|
||||
&& filter_input( INPUT_GET, 'action' ) === 'delete'
|
||||
&& $current_language !== $default_language
|
||||
) {
|
||||
$val['nav_menu_locations'] = get_theme_mod( 'nav_menu_locations' );
|
||||
}
|
||||
|
||||
if ( isset( $val['nav_menu_locations'] ) ) {
|
||||
foreach ( (array) $val['nav_menu_locations'] as $k => $v ) {
|
||||
if ( ! $v && $current_language !== $default_language ) {
|
||||
$tl = get_theme_mod( 'nav_menu_locations' );
|
||||
if ( isset( $tl[ $k ] ) ) {
|
||||
$val['nav_menu_locations'][ $k ] = $tl[ $k ];
|
||||
}
|
||||
} else {
|
||||
$val['nav_menu_locations'][ $k ] = icl_object_id(
|
||||
$val['nav_menu_locations'][ $k ],
|
||||
'nav_menu',
|
||||
true,
|
||||
$default_language
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $val;
|
||||
}
|
||||
|
||||
public function theme_mod_nav_menu_locations( $theme_locations ) {
|
||||
if ( is_admin() && (bool) $theme_locations === true ) {
|
||||
$current_lang = $this->sitepress->get_current_language();
|
||||
foreach ( (array) $theme_locations as $location => $menu_id ) {
|
||||
$translated_menu_id = $this->term_translations->term_id_in( $menu_id, $current_lang );
|
||||
if ( $translated_menu_id ) {
|
||||
$theme_locations[ $location ] = $translated_menu_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $theme_locations;
|
||||
}
|
||||
|
||||
private function get_save_lang( $menu_id ) {
|
||||
$language_code = isset( $_POST['icl_nav_menu_language'] )
|
||||
? $_POST['icl_nav_menu_language'] : $this->term_translations->lang_code_by_termid( $menu_id );
|
||||
$language_code = $language_code ? $language_code : $this->sitepress->get_current_language();
|
||||
|
||||
return $language_code;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|int|mixed|null|string
|
||||
*/
|
||||
private function get_trid_from_post_data() {
|
||||
$trid = null;
|
||||
if ( ! empty( $_POST['icl_translation_of'] ) && $_POST['icl_translation_of'] !== 'none' ) {
|
||||
$trid = $this->sitepress->get_element_trid( $_POST['icl_translation_of'], 'tax_nav_menu' );
|
||||
|
||||
return $trid;
|
||||
} elseif ( isset( $_POST['icl_nav_menu_trid'] ) ) {
|
||||
$trid = ( (int) $_POST['icl_nav_menu_trid'] );
|
||||
|
||||
return $trid;
|
||||
}
|
||||
|
||||
return $trid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
class WPML_Frontend_Tax_Filters {
|
||||
|
||||
public function __construct() {
|
||||
add_filter( 'taxonomy_template', array( $this, 'slug_template' ) );
|
||||
add_filter( 'category_template', array( $this, 'slug_template' ) );
|
||||
add_filter( 'tag_template', array( $this, 'slug_template' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust template (taxonomy-)$taxonomy-$term.php for translated term slugs and IDs
|
||||
*
|
||||
* @since 3.1
|
||||
*
|
||||
* @param string $template
|
||||
*
|
||||
* @return string The template filename if found.
|
||||
*/
|
||||
function slug_template( $template ) {
|
||||
global $sitepress;
|
||||
|
||||
$term = $this->get_queried_tax_term();
|
||||
|
||||
if ( $term === false || ! is_taxonomy_translated( $term->taxonomy ) ) {
|
||||
return $template;
|
||||
}
|
||||
|
||||
$templates = array();
|
||||
|
||||
$has_filter = remove_filter( 'get_term', array( $sitepress, 'get_term_adjust_id' ), 1 );
|
||||
|
||||
$current_language = $sitepress->get_current_language();
|
||||
$default_language = $sitepress->get_default_language();
|
||||
|
||||
$templates = $this->add_term_templates( $term, $current_language, $templates );
|
||||
$templates = $this->add_original_term_templates( $term, $default_language, $current_language, $templates );
|
||||
|
||||
if ( ! in_array( $term->taxonomy, array( 'category', 'post_tag' ), true ) ) {
|
||||
$templates[] = 'taxonomy-' . $current_language . '.php';
|
||||
$templates[] = 'taxonomy.php';
|
||||
}
|
||||
|
||||
if ( $has_filter ) {
|
||||
add_filter( 'get_term', array( $sitepress, 'get_term_adjust_id' ), 1, 1 );
|
||||
}
|
||||
|
||||
$new_template = locate_template( array_unique( $templates ) );
|
||||
$template = $new_template ? $new_template : $template;
|
||||
|
||||
return $template;
|
||||
}
|
||||
|
||||
private function get_template_prefix( $taxonomy ) {
|
||||
|
||||
$prefix = in_array( $taxonomy, array( 'category', 'post_tag' ), true ) ? '' : 'taxonomy-';
|
||||
$prefix .= $taxonomy == 'post_tag' ? 'tag' : $taxonomy;
|
||||
|
||||
return $prefix;
|
||||
}
|
||||
|
||||
private function add_term_templates( $term, $current_language, $templates ) {
|
||||
$prefix = $this->get_template_prefix( $term->taxonomy );
|
||||
$templates[] = "$prefix-{$current_language}-{$term->slug}.php";
|
||||
$templates[] = "$prefix-{$current_language}-{$term->term_id}.php";
|
||||
$templates[] = "$prefix-{$current_language}.php";
|
||||
$templates[] = "$prefix-{$term->slug}.php";
|
||||
$templates[] = "$prefix-{$term->term_id}.php";
|
||||
|
||||
return $templates;
|
||||
}
|
||||
|
||||
private function add_original_term_templates( $term, $default_language, $current_language, $templates ) {
|
||||
$taxonomy = $term->taxonomy;
|
||||
$prefix = $this->get_template_prefix( $taxonomy );
|
||||
$original_term_id = icl_object_id( $term->term_id, $taxonomy, true, $default_language );
|
||||
$original_term = get_term_by( 'id', $original_term_id, $taxonomy );
|
||||
if ( $original_term ) {
|
||||
$templates[] = "$prefix-{$current_language}-{$original_term->slug}.php";
|
||||
$templates[] = "$prefix-{$current_language}-{$original_term_id}.php";
|
||||
$templates[] = "$prefix-{$original_term->slug}.php";
|
||||
$templates[] = "$prefix-{$original_term_id}.php";
|
||||
$templates[] = "$prefix-{$current_language}.php";
|
||||
$templates[] = "$prefix.php";
|
||||
}
|
||||
|
||||
return $templates;
|
||||
}
|
||||
|
||||
private function get_queried_tax_term() {
|
||||
global $wp_query;
|
||||
/** @var WP_Query $wp_query */
|
||||
$term = $wp_query->get_queried_object();
|
||||
$res = false;
|
||||
|
||||
if ( (bool) $term === true && isset( $term->taxonomy ) && $term->taxonomy ) {
|
||||
$res = $term;
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
/**
|
||||
* WPML_Term_Filters class file.
|
||||
*
|
||||
* @package WPML\Core
|
||||
* @subpackage taxonomy-term-translation
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class WPML_Term_Filters
|
||||
*/
|
||||
class WPML_Term_Filters extends WPML_WPDB_And_SP_User {
|
||||
|
||||
/**
|
||||
* Init class.
|
||||
*/
|
||||
public function init() {
|
||||
$taxonomies = get_taxonomies();
|
||||
|
||||
foreach ( $taxonomies as $taxonomy ) {
|
||||
$this->add_hooks_to_translated_taxonomy( $taxonomy );
|
||||
}
|
||||
|
||||
add_action( 'registered_taxonomy', [ $this, 'registered_taxonomy' ], 10, 3 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $taxonomy Taxonomy slug.
|
||||
* @param array|string $object_type Object type or array of object types.
|
||||
* @param array $taxonomy_object Array of taxonomy registration arguments.
|
||||
*/
|
||||
public function registered_taxonomy( $taxonomy, $object_type, $taxonomy_object ) {
|
||||
$this->add_hooks_to_translated_taxonomy( $taxonomy );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $taxonomy Taxonomy slug.
|
||||
*/
|
||||
private function add_hooks_to_translated_taxonomy( $taxonomy ) {
|
||||
if ( is_taxonomy_translated( $taxonomy ) ) {
|
||||
add_filter( "pre_option_{$taxonomy}_children", [ $this, 'pre_option_tax_children' ], 10, 0 );
|
||||
add_action( "create_{$taxonomy}", [ $this, 'update_tax_children_option' ], 10, 0 );
|
||||
add_action( "edit_{$taxonomy}", [ $this, 'update_tax_children_option' ], 10, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
public function update_tax_children_option( $taxonomy_input = false ) {
|
||||
global $wpml_language_resolution, $wp_taxonomies;
|
||||
|
||||
$language_codes = $wpml_language_resolution->get_active_language_codes();
|
||||
$language_codes[] = 'all';
|
||||
$taxonomy = str_replace( array( 'create_', 'edit_' ), '', current_action() );
|
||||
$taxonomy = isset( $wp_taxonomies[ $taxonomy ] ) ? $taxonomy : $taxonomy_input;
|
||||
foreach ( $language_codes as $lang ) {
|
||||
$tax_children = $this->get_tax_hier_array( $taxonomy, $lang );
|
||||
$option_key = "{$taxonomy}_children_{$lang}";
|
||||
update_option( $option_key, $tax_children );
|
||||
}
|
||||
}
|
||||
|
||||
public function pre_option_tax_children() {
|
||||
$taxonomy = str_replace( array( 'pre_option_', '_children' ), '', current_filter() );
|
||||
$lang = $this->sitepress->get_current_language();
|
||||
$option_key = "{$taxonomy}_children_{$lang}";
|
||||
$tax_children = get_option( $option_key, false );
|
||||
if ( $tax_children === false ) {
|
||||
$tax_children = $this->get_tax_hier_array( $taxonomy, $lang );
|
||||
update_option( $option_key, $tax_children );
|
||||
}
|
||||
|
||||
return ! empty( $tax_children ) ? $tax_children : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $taxonomy
|
||||
* @param string $lang_code
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_tax_hier_array( $taxonomy, $lang_code ) {
|
||||
$hierarchy = array();
|
||||
|
||||
if ( $lang_code != 'all' ) {
|
||||
$terms = $this->wpdb->get_results(
|
||||
$this->wpdb->prepare(
|
||||
"SELECT term_id, parent
|
||||
FROM {$this->wpdb->term_taxonomy} tt
|
||||
JOIN {$this->wpdb->prefix}icl_translations iclt
|
||||
ON tt.term_taxonomy_id = iclt.element_id
|
||||
WHERE tt.parent > 0
|
||||
AND tt.taxonomy = %s
|
||||
AND iclt.language_code = %s
|
||||
AND iclt.element_type = %s
|
||||
ORDER BY term_id",
|
||||
$taxonomy,
|
||||
$lang_code,
|
||||
'tax_' . $taxonomy
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$terms = $this->wpdb->get_results(
|
||||
$this->wpdb->prepare(
|
||||
"SELECT term_id, parent
|
||||
FROM {$this->wpdb->term_taxonomy} tt
|
||||
WHERE tt.parent > 0
|
||||
AND tt.taxonomy = %s
|
||||
ORDER BY term_id",
|
||||
$taxonomy
|
||||
)
|
||||
);
|
||||
}
|
||||
foreach ( $terms as $term ) {
|
||||
if ( $term->parent > 0 ) {
|
||||
$hierarchy[ $term->parent ] = isset( $hierarchy[ $term->parent ] )
|
||||
? $hierarchy[ $term->parent ] : array();
|
||||
$hierarchy[ $term->parent ][] = $term->term_id;
|
||||
}
|
||||
}
|
||||
|
||||
return $hierarchy;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Term_Hierarchy_Duplication
|
||||
*
|
||||
* @package wpml-core
|
||||
* @subpackage taxonomy-term-translation
|
||||
*/
|
||||
class WPML_Term_Hierarchy_Duplication extends WPML_WPDB_And_SP_User {
|
||||
|
||||
public function duplicates_require_sync( $post_ids, $duplicates_only = true ) {
|
||||
$taxonomies = $this->sitepress->get_translatable_taxonomies( true );
|
||||
foreach ( $taxonomies as $key => $tax ) {
|
||||
if ( ! is_taxonomy_hierarchical( $tax ) ) {
|
||||
unset( $taxonomies[ $key ] );
|
||||
}
|
||||
}
|
||||
if ( (bool) $post_ids === true ) {
|
||||
$need_sync_taxonomies = $duplicates_only === true
|
||||
? $this->get_need_sync_new_dupl( $post_ids, $taxonomies )
|
||||
: $this->get_need_sync_all_terms( $taxonomies, $post_ids );
|
||||
} else {
|
||||
$need_sync_taxonomies = array();
|
||||
}
|
||||
|
||||
return array_values( array_unique( $need_sync_taxonomies ) );
|
||||
}
|
||||
|
||||
private function get_need_sync_new_dupl( $duplicated_ids, $taxonomies ) {
|
||||
$new_terms = $this->get_new_terms_just_duplicated( $duplicated_ids, $taxonomies );
|
||||
$affected_taxonomies = array();
|
||||
foreach ( $new_terms as $term ) {
|
||||
$affected_taxonomies[] = $term->taxonomy;
|
||||
}
|
||||
$affected_taxonomies = array_unique( $affected_taxonomies );
|
||||
$hierarchy_sync_helper = wpml_get_hierarchy_sync_helper( 'term' );
|
||||
|
||||
$unsynced_terms = $hierarchy_sync_helper->get_unsynced_elements(
|
||||
$affected_taxonomies,
|
||||
$this->sitepress->get_default_language()
|
||||
);
|
||||
|
||||
foreach ( $new_terms as $key => $new_term ) {
|
||||
$sync = true;
|
||||
foreach ( $unsynced_terms as $term_unsynced ) {
|
||||
if ( $term_unsynced->translated_id == $new_term->term_taxonomy_id ) {
|
||||
$sync = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( $sync === true ) {
|
||||
unset( $new_terms[ $key ] );
|
||||
}
|
||||
}
|
||||
$need_sync_taxonomies = array();
|
||||
foreach ( $new_terms as $term ) {
|
||||
$need_sync_taxonomies[] = $term->taxonomy;
|
||||
}
|
||||
|
||||
return $need_sync_taxonomies;
|
||||
}
|
||||
|
||||
private function get_need_sync_all_terms( $translated_taxonomies, $post_ids ) {
|
||||
$hierarchy_sync_helper = wpml_get_hierarchy_sync_helper( 'term' );
|
||||
$post_ids_in = wpml_prepare_in( (array) $post_ids, '%d' );
|
||||
$taxonomies_in = wpml_prepare_in( $translated_taxonomies );
|
||||
|
||||
$this->wpdb->get_col(
|
||||
"SELECT DISTINCT tt.taxonomy
|
||||
FROM {$this->wpdb->term_taxonomy} tt
|
||||
JOIN {$this->wpdb->term_relationships} tr
|
||||
ON tt.term_taxonomy_id = tr.term_taxonomy_id
|
||||
WHERE tr.object_id IN ({$post_ids_in}) AND tt.taxonomy IN ({$taxonomies_in})"
|
||||
);
|
||||
|
||||
foreach ( $translated_taxonomies as $key => $tax ) {
|
||||
$unsynced_terms = $hierarchy_sync_helper->get_unsynced_elements(
|
||||
$tax,
|
||||
$this->sitepress->get_default_language()
|
||||
);
|
||||
if ( (bool) $unsynced_terms === false ) {
|
||||
unset( $translated_taxonomies[ $key ] );
|
||||
}
|
||||
}
|
||||
|
||||
return $translated_taxonomies;
|
||||
}
|
||||
|
||||
private function get_new_terms_just_duplicated( $duplicate_ids, $taxonomies ) {
|
||||
if ( (bool) $duplicate_ids === false || (bool) $taxonomies === false ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$duplicate_ids_in = wpml_prepare_in( $duplicate_ids, '%d' );
|
||||
$taxonomies_in = wpml_prepare_in( $taxonomies );
|
||||
$terms = $this->wpdb->get_results(
|
||||
"SELECT tt.term_taxonomy_id, tt.taxonomy
|
||||
FROM {$this->wpdb->term_taxonomy} tt
|
||||
JOIN {$this->wpdb->term_relationships} tr
|
||||
ON tt.term_taxonomy_id = tr.term_taxonomy_id
|
||||
JOIN {$this->wpdb->postmeta} pm
|
||||
ON pm.post_id = tr.object_id
|
||||
JOIN {$this->wpdb->terms} t_duplicate
|
||||
ON t_duplicate.term_id = tt.term_id
|
||||
JOIN {$this->wpdb->terms} t_original
|
||||
ON t_original.name = t_duplicate.name
|
||||
JOIN {$this->wpdb->term_taxonomy} tt_master
|
||||
ON tt_master.term_id = t_original.term_id
|
||||
JOIN {$this->wpdb->term_relationships} tr_master
|
||||
ON tt_master.term_taxonomy_id = tr_master.term_taxonomy_id
|
||||
LEFT JOIN {$this->wpdb->term_relationships} tr_other
|
||||
ON tt.term_taxonomy_id = tr_other.term_taxonomy_id
|
||||
AND tr_other.object_id != tr.object_id
|
||||
AND tr_other.object_id NOT IN ({$duplicate_ids_in})
|
||||
LEFT JOIN {$this->wpdb->postmeta} pm_other
|
||||
ON pm_other.post_id = tr_other.object_id
|
||||
AND NOT (pm_other.meta_key = '_icl_lang_duplicate_of'
|
||||
AND pm_other.meta_value IN ({$duplicate_ids_in}))
|
||||
WHERE pm.meta_key = '_icl_lang_duplicate_of'
|
||||
AND tr_other.object_id IS NULL
|
||||
AND pm_other.post_id IS NULL
|
||||
AND pm.meta_value IN ({$duplicate_ids_in})
|
||||
AND tr_master.object_id IN ({$duplicate_ids_in})
|
||||
AND tt.taxonomy IN ({$taxonomies_in})"
|
||||
);
|
||||
|
||||
return $terms;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
class WPML_Term_Hierarchy_Sync extends WPML_Hierarchy_Sync {
|
||||
|
||||
protected $element_id_column = 'term_taxonomy_id';
|
||||
protected $parent_id_column = 'parent';
|
||||
protected $parent_element_id_column = 'term_id';
|
||||
protected $element_type_column = 'taxonomy';
|
||||
protected $element_type_prefix = 'tax_';
|
||||
|
||||
/**
|
||||
* @param wpdb $wpdb
|
||||
*/
|
||||
public function __construct( &$wpdb ) {
|
||||
parent::__construct( $wpdb );
|
||||
|
||||
$this->elements_table = $wpdb->term_taxonomy;
|
||||
}
|
||||
|
||||
public function is_need_sync( $taxonomy, $ref_lang = false ) {
|
||||
|
||||
return (bool) $this->get_unsynced_elements( $taxonomy, $ref_lang );
|
||||
}
|
||||
|
||||
public function sync_element_hierarchy( $element_types, $ref_lang = false ) {
|
||||
/** @var WPML_Term_Filters $wpml_term_filters_general */
|
||||
global $wpml_term_filters_general;
|
||||
|
||||
parent::sync_element_hierarchy( $element_types, $ref_lang );
|
||||
do_action( 'wpml_sync_term_hierarchy_done' );
|
||||
|
||||
$element_types = (array) $element_types;
|
||||
|
||||
foreach ( $element_types as $taxonomy ) {
|
||||
$wpml_term_filters_general->update_tax_children_option( $taxonomy );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $element_type
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_hierarchical( $element_type ) {
|
||||
return is_taxonomy_hierarchical( $element_type );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
use WPML\FP\Fns;
|
||||
|
||||
class WPML_Term_Translation_Utils extends WPML_SP_User {
|
||||
|
||||
/**
|
||||
* Duplicates all terms, that exist in the given target language,
|
||||
* from the original post to the translation in that language.
|
||||
*
|
||||
* @param int $original_post_id
|
||||
* @param string $lang
|
||||
*/
|
||||
function sync_terms( $original_post_id, $lang ) {
|
||||
$this->synchronize_terms( $original_post_id, $lang, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicates all terms on the original post to its translation in the given target language.
|
||||
* Missing terms are created with the same name as their originals.
|
||||
*
|
||||
* @param int $original_post_id
|
||||
* @param string $lang
|
||||
*/
|
||||
function duplicate_terms( $original_post_id, $lang ) {
|
||||
$this->synchronize_terms( $original_post_id, $lang, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $original_post_id
|
||||
* @param string $lang
|
||||
* @param bool $duplicate sets whether missing terms should be created by duplicating the original term
|
||||
*/
|
||||
private function synchronize_terms( $original_post_id, $lang, $duplicate ) {
|
||||
global $wpml_post_translations;
|
||||
|
||||
$returnTrue = Fns::always( true );
|
||||
add_filter( 'wpml_disable_term_adjust_id', $returnTrue );
|
||||
|
||||
$wpml_post_translations->reload();
|
||||
$translated_post_id = $wpml_post_translations->element_id_in( $original_post_id, $lang );
|
||||
if ( (bool) $translated_post_id === true ) {
|
||||
$taxonomies = get_post_taxonomies( $original_post_id );
|
||||
|
||||
foreach ( $taxonomies as $tax ) {
|
||||
$terms_on_original = wp_get_object_terms( $original_post_id, $tax );
|
||||
|
||||
if ( ! $this->sitepress->is_translated_taxonomy( $tax ) ) {
|
||||
if ( $this->sitepress->get_setting( 'sync_post_taxonomies' ) ) {
|
||||
// Taxonomy is not translated so we can just copy from the original
|
||||
foreach ( $terms_on_original as $key => $term ) {
|
||||
$terms_on_original[ $key ] = $term->term_id;
|
||||
}
|
||||
wp_set_object_terms( $translated_post_id, $terms_on_original, $tax );
|
||||
}
|
||||
} else {
|
||||
|
||||
/** @var int[] $translated_terms translated term_ids */
|
||||
$translated_terms = $this->get_translated_term_ids( $terms_on_original, $lang, $tax, $duplicate );
|
||||
wp_set_object_terms( $translated_post_id, $translated_terms, $tax );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
remove_filter( 'wpml_disable_term_adjust_id', $returnTrue );
|
||||
clean_object_term_cache( $original_post_id, get_post_type( $original_post_id ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object[] $terms
|
||||
* @param string $lang
|
||||
* @param string $taxonomy
|
||||
* @param bool $duplicate sets whether missing terms should be created by duplicating the original term
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_translated_term_ids( $terms, $lang, $taxonomy, $duplicate ) {
|
||||
/** @var WPML_Term_Translation $wpml_term_translations */
|
||||
global $wpml_term_translations;
|
||||
|
||||
$term_utils = new WPML_Terms_Translations();
|
||||
$wpml_term_translations->reload();
|
||||
$translated_terms = array();
|
||||
foreach ( $terms as $orig_term ) {
|
||||
$translated_id = (int) $wpml_term_translations->term_id_in( $orig_term->term_id, $lang );
|
||||
if ( ! $translated_id && $duplicate ) {
|
||||
$translation = $term_utils->create_automatic_translation(
|
||||
array(
|
||||
'lang_code' => $lang,
|
||||
'taxonomy' => $taxonomy,
|
||||
'trid' => $wpml_term_translations->get_element_trid( $orig_term->term_taxonomy_id ),
|
||||
'source_language' => $wpml_term_translations->get_element_lang_code(
|
||||
$orig_term->term_taxonomy_id
|
||||
),
|
||||
)
|
||||
);
|
||||
$translated_id = isset( $translation['term_id'] ) ? $translation['term_id'] : false;
|
||||
}
|
||||
if ( $translated_id ) {
|
||||
$translated_terms[] = $translated_id;
|
||||
}
|
||||
}
|
||||
|
||||
return $translated_terms;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @since 3.2
|
||||
*
|
||||
* Class WPML_Term_Translation
|
||||
*
|
||||
* Provides APIs for translating taxonomy terms
|
||||
*
|
||||
* @package wpml-core
|
||||
* @subpackage taxonomy-term-translation
|
||||
*/
|
||||
class WPML_Term_Translation extends WPML_Element_Translation {
|
||||
|
||||
/** @var array|null */
|
||||
protected $ttids;
|
||||
|
||||
/** @var array|null */
|
||||
protected $term_ids;
|
||||
|
||||
public function reload() {
|
||||
parent::reload();
|
||||
$this->term_ids = null;
|
||||
$this->ttids = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $term_id
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function lang_code_by_termid( $term_id ) {
|
||||
|
||||
return $this->get_element_lang_code( $this->adjust_ttid_for_term_id( $term_id ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts term_id into term_taxonomy_id
|
||||
*
|
||||
* @param int $term_id
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function adjust_ttid_for_term_id( $term_id ) {
|
||||
$this->maybe_warm_term_id_cache();
|
||||
|
||||
return $term_id && isset( $this->ttids[ $term_id ] ) ? end( $this->ttids[ $term_id ] ) : $term_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts term_taxonomy_id into term_id
|
||||
*
|
||||
* @param int $ttid term_taxonomy_id
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function adjust_term_id_for_ttid( $ttid ) {
|
||||
$this->maybe_warm_term_id_cache();
|
||||
|
||||
return $ttid && isset( $this->term_ids[ $ttid ] ) ? $this->term_ids[ $ttid ] : $ttid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $term_id
|
||||
* @param string $lang_code
|
||||
* @param bool|false $original_fallback if true will return the the input term_id in case no translation is found
|
||||
*
|
||||
* @return null|int
|
||||
*/
|
||||
public function term_id_in( $term_id, $lang_code, $original_fallback = false ) {
|
||||
|
||||
return $this->adjust_term_id_for_ttid(
|
||||
$this->element_id_in( $this->adjust_ttid_for_term_id( $term_id ), $lang_code, $original_fallback )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the trid for a given term_id and taxonomy or null on failure
|
||||
*
|
||||
* @param int $term_id term_id of a term
|
||||
* @param string $taxonomy taxonomy of the term
|
||||
*
|
||||
* @return null|int
|
||||
*/
|
||||
public function trid_from_tax_and_id( $term_id, $taxonomy ) {
|
||||
$this->maybe_warm_term_id_cache();
|
||||
$ttid = $term_id && isset( $this->ttids[ $term_id ][ $taxonomy ] )
|
||||
? $this->ttids[ $term_id ][ $taxonomy ] : $term_id;
|
||||
|
||||
return $this->get_element_trid( $ttid );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all post types to which a taxonomy is linked.
|
||||
*
|
||||
* @param string $taxonomy
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @since 3.2.3
|
||||
*/
|
||||
public function get_taxonomy_post_types( $taxonomy ) {
|
||||
return WPML_WP_Taxonomy::get_linked_post_types( $taxonomy );
|
||||
}
|
||||
|
||||
protected function get_element_join() {
|
||||
|
||||
return "FROM {$this->wpdb->prefix}icl_translations wpml_translations
|
||||
JOIN {$this->wpdb->term_taxonomy} tax
|
||||
ON wpml_translations.element_id = tax.term_taxonomy_id
|
||||
AND wpml_translations.element_type = CONCAT('tax_', tax.taxonomy)";
|
||||
}
|
||||
|
||||
protected function get_type_prefix() {
|
||||
return 'tax_';
|
||||
}
|
||||
|
||||
private function maybe_warm_term_id_cache() {
|
||||
|
||||
if ( ! isset( $this->ttids ) || ! isset( $this->term_ids ) ) {
|
||||
|
||||
$data = $this->wpdb->get_results(
|
||||
' SELECT wpml_translations.element_id, tax.term_id, tax.taxonomy
|
||||
' . $this->get_element_join() . "
|
||||
JOIN {$this->wpdb->terms} terms
|
||||
ON terms.term_id = tax.term_id
|
||||
WHERE tax.term_id != tax.term_taxonomy_id",
|
||||
ARRAY_A
|
||||
);
|
||||
$this->term_ids = array();
|
||||
$this->ttids = array();
|
||||
foreach ( $data as $row ) {
|
||||
$this->ttids[ $row['term_id'] ] = isset( $this->ttids[ $row['term_id'] ] )
|
||||
? $this->ttids[ $row['term_id'] ] : array();
|
||||
$this->ttids[ $row['term_id'] ][ $row['taxonomy'] ] = $row['element_id'];
|
||||
$this->term_ids[ $row['element_id'] ] = $row['term_id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $term
|
||||
* @param string $slug
|
||||
* @param string $taxonomy
|
||||
* @param string $lang_code
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function generate_unique_term_slug( $term, $slug, $taxonomy, $lang_code ) {
|
||||
if ( '' === trim( $slug ) ) {
|
||||
$slug = sanitize_title( $term );
|
||||
}
|
||||
return WPML_Terms_Translations::term_unique_slug( $slug, $taxonomy, $lang_code );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return self
|
||||
*/
|
||||
public static function getGlobalInstance() {
|
||||
global $wpml_term_translations, $wpdb;
|
||||
|
||||
if ( ! isset( $wpml_term_translations ) ) {
|
||||
$wpml_term_translations = new WPML_Term_Translation( $wpdb );
|
||||
}
|
||||
|
||||
return $wpml_term_translations;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,719 @@
|
||||
<?php
|
||||
require_once dirname( __FILE__ ) . '/wpml-update-term-action.class.php';
|
||||
|
||||
use WPML\FP\Lst;
|
||||
use WPML\FP\Fns;
|
||||
use WPML\FP\Obj;
|
||||
use WPML\FP\Logic;
|
||||
use function WPML\FP\pipe;
|
||||
|
||||
/**
|
||||
* @since 3.1.8
|
||||
*
|
||||
* Class WPML_Terms_Translations
|
||||
*
|
||||
* This class holds some basic functionality for translating taxonomy terms.
|
||||
*
|
||||
* @package wpml-core
|
||||
* @subpackage taxonomy-term-translation
|
||||
*/
|
||||
class WPML_Terms_Translations {
|
||||
|
||||
/**
|
||||
* @param array<string|\WP_Term> $terms
|
||||
* @param string[]|string $taxonomies This is only used by the WP core AJAX call that fetches the preview
|
||||
* auto-complete for flat taxonomy term adding
|
||||
*
|
||||
* @return array<\WP_Term>
|
||||
* @deprecated since Version 3.1.8.3
|
||||
*/
|
||||
public static function get_terms_filter( $terms, $taxonomies ) {
|
||||
global $wpdb, $sitepress;
|
||||
|
||||
$lang = $sitepress->get_current_language();
|
||||
|
||||
foreach ( $taxonomies as $taxonomy ) {
|
||||
|
||||
if ( $sitepress->is_translated_taxonomy( $taxonomy ) ) {
|
||||
|
||||
$element_type = 'tax_' . $taxonomy;
|
||||
|
||||
$query = $wpdb->prepare(
|
||||
"SELECT wptt.term_id
|
||||
FROM {$wpdb->prefix}icl_translations AS iclt
|
||||
JOIN {$wpdb->prefix}term_taxonomy AS wptt
|
||||
ON iclt.element_id = wptt.term_taxonomy_id
|
||||
WHERE language_code=%s AND element_type = %s",
|
||||
$lang,
|
||||
$element_type
|
||||
);
|
||||
|
||||
$element_ids_array = $wpdb->get_col( $query );
|
||||
|
||||
foreach ( $terms as $key => $term ) {
|
||||
if ( ! is_object( $term ) ) {
|
||||
$term = get_term_by( 'name', $term, $taxonomy );
|
||||
}
|
||||
if ( $term && isset( $term->taxonomy )
|
||||
&& $term->taxonomy === $taxonomy
|
||||
&& ! in_array( $term->term_id, $element_ids_array ) ) {
|
||||
unset( $terms[ $key ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $terms;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $slug
|
||||
* @param string $taxonomy
|
||||
* @param string $lang
|
||||
* Creates a unique slug for a given term, using a scheme
|
||||
* encoding the language code in the slug.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function term_unique_slug( $slug, $taxonomy, $lang ) {
|
||||
global $sitepress;
|
||||
|
||||
$default_language = $sitepress->get_default_language();
|
||||
|
||||
if ( $lang !== $default_language && self::term_slug_exists( $slug, $taxonomy ) ) {
|
||||
$slug .= '-' . $lang;
|
||||
}
|
||||
|
||||
$i = 2;
|
||||
$suffix = '-' . $i;
|
||||
|
||||
if ( self::term_slug_exists( $slug, $taxonomy ) ) {
|
||||
while ( self::term_slug_exists( $slug . $suffix, $taxonomy ) ) {
|
||||
$i ++;
|
||||
$suffix = '-' . $i;
|
||||
}
|
||||
$slug .= $suffix;
|
||||
}
|
||||
|
||||
return $slug;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $slug
|
||||
* @param bool $taxonomy
|
||||
* If $taxonomy is given, then slug existence is checked only for the specific taxonomy.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private static function term_slug_exists( $slug, $taxonomy = false ) {
|
||||
global $wpdb;
|
||||
|
||||
$existing_term_prepared_query = $wpdb->prepare(
|
||||
"SELECT t.term_id
|
||||
FROM {$wpdb->terms} t
|
||||
JOIN {$wpdb->term_taxonomy} tt
|
||||
ON t.term_id = tt.term_id
|
||||
WHERE t.slug = %s
|
||||
AND tt.taxonomy = %s
|
||||
LIMIT 1",
|
||||
$slug,
|
||||
$taxonomy
|
||||
);
|
||||
$term_id = $wpdb->get_var( $existing_term_prepared_query );
|
||||
|
||||
return (bool) $term_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function provides an action hook only used by WCML.
|
||||
* It will be removed in the future and should not be implemented in new spots.
|
||||
*
|
||||
* @deprecated deprecated since version 3.1.8.3
|
||||
*
|
||||
* @param string $taxonomy The identifier of the taxonomy the translation was just saved to.
|
||||
* @param array $translated_term The associative array holding term taxonomy id and term id,
|
||||
* as returned by wp_insert_term or wp_update_term.
|
||||
*/
|
||||
public static function icl_save_term_translation_action( $taxonomy, $translated_term ) {
|
||||
global $wpdb, $sitepress;
|
||||
|
||||
if ( is_taxonomy_hierarchical( $taxonomy ) ) {
|
||||
$term_taxonomy_id = $translated_term['term_taxonomy_id'];
|
||||
|
||||
$original_ttid = $sitepress->get_original_element_id( $term_taxonomy_id, 'tax_' . $taxonomy );
|
||||
|
||||
$original_tax_sql = "SELECT * FROM {$wpdb->term_taxonomy} WHERE taxonomy=%s AND term_taxonomy_id = %d";
|
||||
$original_tax_prepared = $wpdb->prepare( $original_tax_sql, array( $taxonomy, $original_ttid ) );
|
||||
$original_tax = $wpdb->get_row( $original_tax_prepared );
|
||||
|
||||
do_action( 'icl_save_term_translation', $original_tax, $translated_term );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a hidden div, containing the list of allowed terms for a post type in each language.
|
||||
* This is used to only display the correct categories and tags in the quick-edit fields of the post table.
|
||||
*
|
||||
* @param string $column_name
|
||||
* @param string|string[]|\WP_Post $post_type
|
||||
*/
|
||||
public static function quick_edit_terms_removal( $column_name, $post_type ) {
|
||||
global $sitepress, $wpdb;
|
||||
if ( $column_name == 'icl_translations' ) {
|
||||
$taxonomies = array_filter(
|
||||
get_object_taxonomies( $post_type ),
|
||||
array(
|
||||
$sitepress,
|
||||
'is_translated_taxonomy',
|
||||
)
|
||||
);
|
||||
$terms_by_language_and_taxonomy = array();
|
||||
|
||||
if ( ! empty( $taxonomies ) ) {
|
||||
$res = $wpdb->get_results(
|
||||
" SELECT language_code, taxonomy, term_id FROM {$wpdb->term_taxonomy} tt
|
||||
JOIN {$wpdb->prefix}icl_translations wpml_translations
|
||||
ON wpml_translations.element_id = tt.term_taxonomy_id
|
||||
AND wpml_translations.element_type = CONCAT('tax_', tt.taxonomy)
|
||||
WHERE tt.taxonomy IN (" . wpml_prepare_in( $taxonomies ) . ' )'
|
||||
);
|
||||
} else {
|
||||
$res = array();
|
||||
}
|
||||
|
||||
foreach ( $res as $term ) {
|
||||
$lang = $term->language_code;
|
||||
$tax = $term->taxonomy;
|
||||
$terms_by_language_and_taxonomy[ $lang ] = isset( $terms_by_language_and_taxonomy[ $lang ] ) ? $terms_by_language_and_taxonomy[ $lang ] : array();
|
||||
$terms_by_language_and_taxonomy[ $lang ][ $tax ] = isset( $terms_by_language_and_taxonomy[ $lang ][ $tax ] ) ? $terms_by_language_and_taxonomy[ $lang ][ $tax ] : array();
|
||||
$terms_by_language_and_taxonomy[ $lang ][ $tax ][] = $term->term_id;
|
||||
}
|
||||
$terms_json = wp_json_encode( $terms_by_language_and_taxonomy );
|
||||
$output = '<div id="icl-terms-by-lang" style="display: none;">' . wp_kses_post( $terms_json ) . '</div>';
|
||||
echo $output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new term from an argument array.
|
||||
*
|
||||
* @param array $args
|
||||
* @return array|bool
|
||||
* Returns either an array containing the term_id and term_taxonomy_id of the term resulting from this database
|
||||
* write or false on error.
|
||||
*/
|
||||
public static function create_new_term( $args ) {
|
||||
global $wpdb, $sitepress;
|
||||
|
||||
/** @var string $taxonomy */
|
||||
$taxonomy = false;
|
||||
/** @var string $lang_code */
|
||||
$lang_code = false;
|
||||
/**
|
||||
* Sets whether translations of posts are to be updated by the newly created term,
|
||||
* should they be missing a translation still.
|
||||
* During debug actions designed to synchronise post and term languages this should not be set to true,
|
||||
* doing so introduces the possibility of removing terms from posts before switching
|
||||
* them with their translation in the correct language.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
$sync = false;
|
||||
|
||||
extract( $args, EXTR_OVERWRITE );
|
||||
|
||||
require_once dirname( __FILE__ ) . '/wpml-update-term-action.class.php';
|
||||
|
||||
$new_term_action = new WPML_Update_Term_Action( $wpdb, $sitepress, $args );
|
||||
$new_term = $new_term_action->execute();
|
||||
|
||||
if ( $sync && $new_term && $taxonomy && $lang_code ) {
|
||||
self::sync_taxonomy_terms_language( $taxonomy );
|
||||
}
|
||||
|
||||
return $new_term;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<mixed> $args
|
||||
* Creates an automatic translation of a term, the name of which is set as "original" . @ "lang_code" and the slug of which is set as "original_slug" . - . "lang_code".
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
public function create_automatic_translation( $args ) {
|
||||
global $sitepress;
|
||||
|
||||
$term = false;
|
||||
$lang_code = false;
|
||||
$taxonomy = false;
|
||||
$original_id = false;
|
||||
$original_tax_id = false;
|
||||
$trid = false;
|
||||
$original_term = false;
|
||||
$update_translations = false;
|
||||
$source_language = null;
|
||||
|
||||
extract( $args, EXTR_OVERWRITE );
|
||||
|
||||
if ( $trid && ! $original_id ) {
|
||||
$original_tax_id = $sitepress->get_original_element_id_by_trid( $trid );
|
||||
$original_term = get_term_by( 'term_taxonomy_id', $original_tax_id, $taxonomy, OBJECT, 'no' );
|
||||
}
|
||||
|
||||
if ( $original_id && ! $original_tax_id ) {
|
||||
$original_term = get_term( $original_id, $taxonomy, OBJECT, 'no' );
|
||||
if ( isset( $original_term['term_taxonomy_id'] ) ) {
|
||||
$original_tax_id = $original_term['term_taxonomy_id'];
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $trid ) {
|
||||
$trid = $sitepress->get_element_trid( $original_tax_id, 'tax_' . $taxonomy );
|
||||
}
|
||||
|
||||
if ( ! $source_language ) {
|
||||
$source_language = $sitepress->get_source_language_by_trid( $trid );
|
||||
}
|
||||
|
||||
$existing_translations = $sitepress->get_element_translations( $trid, 'tax_' . $taxonomy );
|
||||
if ( $lang_code && isset( $existing_translations[ $lang_code ] ) ) {
|
||||
$new_translated_term = false;
|
||||
} else {
|
||||
|
||||
if ( ! $original_term ) {
|
||||
if ( $original_id ) {
|
||||
$original_term = get_term( $original_id, $taxonomy, OBJECT, 'no' );
|
||||
} elseif ( $original_tax_id ) {
|
||||
$original_term = get_term_by( 'term_taxonomy_id', $original_tax_id, $taxonomy, OBJECT, 'no' );
|
||||
}
|
||||
}
|
||||
$translated_slug = false;
|
||||
|
||||
if ( ! $term && isset( $original_term->name ) ) {
|
||||
$term = $original_term->name;
|
||||
|
||||
/**
|
||||
* @deprecated use 'wpml_duplicate_generic_string' instead, with the same arguments
|
||||
*/
|
||||
$term = apply_filters(
|
||||
'icl_duplicate_generic_string',
|
||||
$term,
|
||||
$lang_code,
|
||||
array(
|
||||
'context' => 'taxonomy',
|
||||
'attribute' => $taxonomy,
|
||||
'key' => $original_term->term_id,
|
||||
)
|
||||
);
|
||||
|
||||
$term = apply_filters(
|
||||
'wpml_duplicate_generic_string',
|
||||
$term,
|
||||
$lang_code,
|
||||
array(
|
||||
'context' => 'taxonomy',
|
||||
'attribute' => $taxonomy,
|
||||
'key' => $original_term->term_id,
|
||||
)
|
||||
);
|
||||
}
|
||||
if ( isset( $original_term->slug ) ) {
|
||||
$translated_slug = $original_term->slug;
|
||||
|
||||
/**
|
||||
* @deprecated use 'wpml_duplicate_generic_string' instead, with the same arguments
|
||||
*/
|
||||
$translated_slug = apply_filters(
|
||||
'icl_duplicate_generic_string',
|
||||
$translated_slug,
|
||||
$lang_code,
|
||||
array(
|
||||
'context' => 'taxonomy_slug',
|
||||
'attribute' => $taxonomy,
|
||||
'key' => $original_term->term_id,
|
||||
)
|
||||
);
|
||||
|
||||
$translated_slug = apply_filters(
|
||||
'wpml_duplicate_generic_string',
|
||||
$translated_slug,
|
||||
$lang_code,
|
||||
array(
|
||||
'context' => 'taxonomy_slug',
|
||||
'attribute' => $taxonomy,
|
||||
'key' => $original_term->term_id,
|
||||
)
|
||||
);
|
||||
|
||||
$translated_slug = self::term_unique_slug( $translated_slug, $taxonomy, $lang_code );
|
||||
}
|
||||
$new_translated_term = false;
|
||||
if ( $term ) {
|
||||
$new_term_args = array(
|
||||
'term' => $term,
|
||||
'slug' => $translated_slug,
|
||||
'taxonomy' => $taxonomy,
|
||||
'lang_code' => $lang_code,
|
||||
'original_tax_id' => $original_tax_id,
|
||||
'update_translations' => $update_translations,
|
||||
'trid' => $trid,
|
||||
'source_language' => $source_language,
|
||||
);
|
||||
|
||||
$new_translated_term = self::create_new_term( $new_term_args );
|
||||
}
|
||||
}
|
||||
|
||||
return $new_translated_term;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $taxonomy
|
||||
*
|
||||
* Sets all taxonomy terms to the correct language on each post, having at least one term from the taxonomy.
|
||||
*/
|
||||
public static function sync_taxonomy_terms_language( $taxonomy ) {
|
||||
$all_posts_in_taxonomy = get_posts( array( 'tax_query' => array( 'taxonomy' => $taxonomy ) ) );
|
||||
|
||||
foreach ( $all_posts_in_taxonomy as $post_in_taxonomy ) {
|
||||
self::sync_post_and_taxonomy_terms_language( $post_in_taxonomy->ID, $taxonomy );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
*
|
||||
* Sets all taxonomy terms ot the correct language for a given post.
|
||||
*/
|
||||
public static function sync_post_terms_language( $post_id ) {
|
||||
|
||||
$taxonomies = get_taxonomies();
|
||||
|
||||
foreach ( $taxonomies as $taxonomy ) {
|
||||
self::sync_post_and_taxonomy_terms_language( $post_id, $taxonomy );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
* @param string $taxonomy
|
||||
* Synchronizes a posts taxonomy term's languages with the posts language for all translations of the post.
|
||||
*/
|
||||
public static function sync_post_and_taxonomy_terms_language( $post_id, $taxonomy ) {
|
||||
global $sitepress;
|
||||
|
||||
$post = get_post( $post_id );
|
||||
$post_type = $post->post_type;
|
||||
$post_trid = $sitepress->get_element_trid( $post_id, 'post_' . $post_type );
|
||||
$post_translations = $sitepress->get_element_translations( $post_trid, 'post_' . $post_type );
|
||||
$terms_from_original_post = wp_get_post_terms( $post_id, $taxonomy );
|
||||
|
||||
$is_original = true;
|
||||
|
||||
if ( $sitepress->get_original_element_id( $post_id, 'post_' . $post_type ) != $post_id ) {
|
||||
$is_original = false;
|
||||
}
|
||||
|
||||
foreach ( $post_translations as $post_language => $translated_post ) {
|
||||
|
||||
$translated_post_id = $translated_post->element_id;
|
||||
if ( ! $translated_post_id ) {
|
||||
continue;
|
||||
}
|
||||
$terms_from_translated_post = wp_get_post_terms( $translated_post_id, $taxonomy );
|
||||
if ( $is_original ) {
|
||||
$duplicates = $sitepress->get_duplicates( $post_id );
|
||||
if ( in_array( $translated_post_id, $duplicates ) ) {
|
||||
$terms = array_merge( $terms_from_original_post, $terms_from_translated_post );
|
||||
} else {
|
||||
$terms = $terms_from_translated_post;
|
||||
}
|
||||
} else {
|
||||
$terms = $terms_from_translated_post;
|
||||
}
|
||||
foreach ( (array) $terms as $term ) {
|
||||
$term_original_tax_id = $term->term_taxonomy_id;
|
||||
$original_term_language_object = $sitepress->get_element_language_details( $term_original_tax_id, 'tax_' . $term->taxonomy );
|
||||
if ( $original_term_language_object && isset( $original_term_language_object->language_code ) ) {
|
||||
$original_term_language = $original_term_language_object->language_code;
|
||||
} else {
|
||||
$original_term_language = $post_language;
|
||||
}
|
||||
if ( $original_term_language != $post_language ) {
|
||||
$term_trid = $sitepress->get_element_trid( $term_original_tax_id, 'tax_' . $term->taxonomy );
|
||||
$translated_terms = $sitepress->get_element_translations( $term_trid, 'tax_' . $term->taxonomy, false, false, true );
|
||||
|
||||
$term_id = $term->term_id;
|
||||
wp_remove_object_terms( $translated_post_id, (int) $term_id, $taxonomy );
|
||||
|
||||
if ( isset( $translated_terms[ $post_language ] ) ) {
|
||||
$term_in_correct_language = $translated_terms[ $post_language ];
|
||||
wp_set_post_terms( $translated_post_id, array( (int) $term_in_correct_language->term_id ), $taxonomy, true );
|
||||
}
|
||||
|
||||
if ( isset( $term->term_taxonomy_id ) ) {
|
||||
wp_update_term_count( $term->term_taxonomy_id, $taxonomy );
|
||||
}
|
||||
}
|
||||
wp_update_term_count( $term_original_tax_id, $taxonomy );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id Object ID.
|
||||
* @param array $terms An array of object terms.
|
||||
* @param array $tt_ids An array of term taxonomy IDs.
|
||||
* @param string $taxonomy Taxonomy slug.
|
||||
* @param bool $append Whether to append new terms to the old terms.
|
||||
* @param array $old_tt_ids Old array of term taxonomy IDs.
|
||||
*/
|
||||
public static function set_object_terms_action( $post_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids ) {
|
||||
global $sitepress;
|
||||
|
||||
// TODO: [WPML 3.2] We have a better way to check if the post is an external type (e.g. Package).
|
||||
if ( get_post( $post_id ) ) {
|
||||
self::set_tags_in_proper_language( $post_id, $tt_ids, $taxonomy, $old_tt_ids );
|
||||
|
||||
if ( $sitepress->get_setting( 'sync_post_taxonomies' ) ) {
|
||||
$term_actions_helper = $sitepress->get_term_actions_helper();
|
||||
$term_actions_helper->added_term_relationships( $post_id );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id Object ID.
|
||||
* @param array $tt_ids An array of term taxonomy IDs.
|
||||
* @param string $taxonomy Taxonomy slug.
|
||||
* @param array $old_tt_ids Old array of term taxonomy IDs.
|
||||
* @param bool $isBulkEdit
|
||||
*/
|
||||
private static function set_tags_in_proper_language( $post_id, $tt_ids, $taxonomy, $old_tt_ids ) {
|
||||
$isEditAction = isset( $_POST['action'] ) && ( 'editpost' === $_POST['action'] || 'inline-save' === $_POST['action'] );
|
||||
$isBulkEdit = isset( $_REQUEST['bulk_edit'] );
|
||||
if ( $isEditAction || $isBulkEdit ) {
|
||||
$tt_ids = array_map( 'intval', $tt_ids );
|
||||
$tt_ids = array_diff( $tt_ids, $old_tt_ids );
|
||||
self::quick_edited_post_terms( $post_id, $taxonomy, $tt_ids );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
* @param string $taxonomy
|
||||
* @param array $changed_ttids
|
||||
*
|
||||
* Running this function will remove certain issues arising out of bulk adding of terms to posts of various languages.
|
||||
* This case can result in situations in which the WP Core functionality adds a term to a post, before the language assignment
|
||||
* operations of WPML are triggered. This leads to states in which terms can be assigned to a post even though their language
|
||||
* differs from that of the post.
|
||||
* This function behaves between hierarchical and flat taxonomies. Hierarchical terms from the wrong taxonomy are simply removed
|
||||
* from the post. Flat terms are added with the same name but in the correct language.
|
||||
* For flat terms this implies either the use of the existing term or the creation of a new one.
|
||||
* This function uses wpdb queries instead of the WordPress API, it is therefore save to be run out of
|
||||
* any language setting.
|
||||
*/
|
||||
public static function quick_edited_post_terms( $post_id, $taxonomy, $newlyAddedTermIds ) {
|
||||
global $wpdb, $sitepress, $wpml_post_translations;
|
||||
|
||||
$postLang = $wpml_post_translations->get_element_lang_code( $post_id ) ?: Obj::prop( 'icl_post_language', $_POST );
|
||||
if ( ! $sitepress->is_translated_taxonomy( $taxonomy ) || ! ( $postLang ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$sql = "SELECT element_id FROM {$wpdb->prefix}icl_translations WHERE language_code = %s AND element_type = %s";
|
||||
$termIdsInPostLang = $wpdb->get_col( $wpdb->prepare( $sql, $postLang, 'tax_' . $taxonomy ) );
|
||||
$termIdsInPostLang = Fns::map( \WPML\FP\Cast::toInt(), $termIdsInPostLang );
|
||||
|
||||
$newlyCreatedTermIds = [];
|
||||
|
||||
$isInPostLang = Lst::includes( Fns::__, $termIdsInPostLang );
|
||||
|
||||
if ( ! is_taxonomy_hierarchical( $taxonomy ) ) {
|
||||
$getTermInPostLang = Obj::prop( 'idInPostLang' );
|
||||
|
||||
$createTermIfNotExists = Logic::ifElse( $getTermInPostLang, Fns::identity(), self::createTerm( $taxonomy, $postLang ) );
|
||||
|
||||
$updateOrDeleteTermInPost = Logic::ifElse(
|
||||
$getTermInPostLang,
|
||||
self::updatePostTaxonomy( $post_id ),
|
||||
pipe( Obj::prop( 'id' ), self::deletePostTaxonomy( $post_id ) )
|
||||
);
|
||||
|
||||
$newlyCreatedTermIds = \wpml_collect( $newlyAddedTermIds )
|
||||
->reject( $isInPostLang )
|
||||
->map( self::appendTermName() )
|
||||
->map( self::appendTermIdCounterpartInPostLang( $termIdsInPostLang, $taxonomy ) )
|
||||
->map( $createTermIfNotExists )
|
||||
->map( $updateOrDeleteTermInPost )
|
||||
->all();
|
||||
} else {
|
||||
\wpml_collect( $newlyAddedTermIds )->reject( $isInPostLang )->each( self::deletePostTaxonomy( $post_id ) );
|
||||
}
|
||||
|
||||
// Update term counts manually here, since using sql, will not trigger the updating of term counts automatically.
|
||||
wp_update_term_count( array_merge( $newlyAddedTermIds, $newlyCreatedTermIds ), $taxonomy );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $postId
|
||||
*
|
||||
* @return Closure
|
||||
*/
|
||||
private static function deletePostTaxonomy( $postId ) {
|
||||
return function ( $termId ) use ( $postId ) {
|
||||
global $wpdb;
|
||||
|
||||
$wpdb->delete(
|
||||
$wpdb->term_relationships,
|
||||
[
|
||||
'object_id' => $postId,
|
||||
'term_taxonomy_id' => $termId,
|
||||
]
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Closure
|
||||
*/
|
||||
private static function appendTermName() {
|
||||
return function ( $termId ) {
|
||||
global $wpdb;
|
||||
|
||||
$sql = "SELECT t.name FROM {$wpdb->terms} AS t JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id WHERE tt.term_taxonomy_id=%d";
|
||||
$termName = $wpdb->get_var( $wpdb->prepare( $sql, $termId ) );
|
||||
|
||||
return [ 'id' => $termId, 'name' => $termName ];
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $termIdsInPostLang
|
||||
* @param string $taxonomy
|
||||
*
|
||||
* @return Closure
|
||||
*/
|
||||
private static function appendTermIdCounterpartInPostLang( $termIdsInPostLang, $taxonomy ) {
|
||||
return function ( $termData ) use ( $termIdsInPostLang, $taxonomy ) {
|
||||
global $wpdb;
|
||||
$idInPostLang = false;
|
||||
|
||||
if ( count( $termIdsInPostLang ) ) {
|
||||
$in = wpml_prepare_in( $termIdsInPostLang, '%d' );
|
||||
|
||||
$sql = "
|
||||
SELECT tt.term_taxonomy_id FROM {$wpdb->terms} AS t
|
||||
JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id
|
||||
WHERE t.name=%s AND tt.taxonomy=%s AND tt.term_taxonomy_id IN ({$in})
|
||||
";
|
||||
|
||||
$idInPostLang = $wpdb->get_var( $wpdb->prepare( $sql, $termData['name'], $taxonomy ) );
|
||||
}
|
||||
|
||||
return Obj::assoc( 'idInPostLang', $idInPostLang, $termData );
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $taxonomy
|
||||
* @param string $postLang
|
||||
*
|
||||
* @return Closure
|
||||
*/
|
||||
private static function createTerm( $taxonomy, $postLang ) {
|
||||
return function ( $termData ) use ( $taxonomy, $postLang ) {
|
||||
global $sitepress;
|
||||
|
||||
$idInCorrectId = false;
|
||||
$newTerm = wp_insert_term( $termData['name'], $taxonomy, [ 'slug' => self::term_unique_slug( sanitize_title( $termData['name'] ), $taxonomy, $postLang ) ] );
|
||||
if ( isset( $newTerm['term_taxonomy_id'] ) ) {
|
||||
$idInCorrectId = $newTerm['term_taxonomy_id'];
|
||||
$trid = $sitepress->get_element_trid( $termData['id'], 'tax_' . $taxonomy );
|
||||
$sitepress->set_element_language_details( $idInCorrectId, 'tax_' . $taxonomy, $trid, $postLang );
|
||||
}
|
||||
|
||||
return Obj::assoc( 'idInPostLang', $idInCorrectId, $termData );
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $postId
|
||||
*
|
||||
* @return Closure
|
||||
*/
|
||||
private static function updatePostTaxonomy( $postId ) {
|
||||
return function ( $termData ) use ( $postId ) {
|
||||
global $wpdb;
|
||||
|
||||
$wpdb->update(
|
||||
$wpdb->term_relationships,
|
||||
[ 'term_taxonomy_id' => $termData['idInPostLang'] ],
|
||||
[
|
||||
'object_id' => $postId,
|
||||
'term_taxonomy_id' => $termData['id'],
|
||||
]
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all terms, that have a language suffix on them.
|
||||
* This is used by troubleshooting functionality.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_all_terms_with_language_suffix() {
|
||||
global $wpdb;
|
||||
|
||||
$lang_codes = $wpdb->get_col( "SELECT code FROM {$wpdb->prefix}icl_languages" );
|
||||
|
||||
/*
|
||||
Build the expression to find all potential candidates for renaming.
|
||||
* These must have the part "<space>@lang_code<space>" in them.
|
||||
*/
|
||||
|
||||
$where_parts = array();
|
||||
|
||||
foreach ( $lang_codes as $key => $code ) {
|
||||
$where_parts[ $key ] = "t.name LIKE '" . '% @' . esc_sql( $code ) . "%'";
|
||||
}
|
||||
|
||||
$where = '(' . join( ' OR ', $where_parts ) . ')';
|
||||
|
||||
$terms_with_suffix = $wpdb->get_results( "SELECT t.name, t.term_id, tt.taxonomy FROM {$wpdb->terms} AS t JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id WHERE {$where}" );
|
||||
|
||||
$terms = array();
|
||||
|
||||
foreach ( $terms_with_suffix as $term ) {
|
||||
|
||||
if ( $term->name == WPML_Troubleshooting_Terms_Menu::strip_language_suffix( $term->name ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$term_id = $term->term_id;
|
||||
|
||||
$term_taxonomy_label = $term->taxonomy;
|
||||
|
||||
$taxonomy = get_taxonomy( $term->taxonomy );
|
||||
|
||||
if ( $taxonomy && isset( $taxonomy->labels ) && isset( $taxonomy->labels->name ) ) {
|
||||
$term_taxonomy_label = $taxonomy->labels->name;
|
||||
}
|
||||
|
||||
if ( isset( $terms[ $term_id ] ) && isset( $terms[ $term_id ]['taxonomies'] ) ) {
|
||||
if ( ! in_array( $term_taxonomy_label, $terms[ $term_id ]['taxonomies'] ) ) {
|
||||
$terms[ $term_id ]['taxonomies'][] = $term_taxonomy_label;
|
||||
}
|
||||
} else {
|
||||
$terms[ $term_id ] = array(
|
||||
'name' => $term->name,
|
||||
'taxonomies' => array( $term_taxonomy_label ),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $terms;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Update_Term_Action
|
||||
*
|
||||
* This class holds the functionality for creating or editing a taxonomy term.
|
||||
*
|
||||
* @package wpml-core
|
||||
* @subpackage taxonomy-term-translation
|
||||
*/
|
||||
class WPML_Update_Term_Action extends WPML_WPDB_And_SP_User {
|
||||
|
||||
/**
|
||||
* TRUE if this object represents valid data for the update or creation of a term, false otherwise.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $is_valid = true;
|
||||
/**
|
||||
* TRUE if this object represents term update action, false if it represents a term creation action.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $is_update;
|
||||
/**
|
||||
* Argument array containing arguments in a format that can and is used as input to \wp_update_term or
|
||||
* \wp_insert_term
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $wp_new_term_args = array();
|
||||
/**
|
||||
* The taxonomy in which this action takes place.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $taxonomy;
|
||||
/**
|
||||
* Trid value in the icl_translations table to which this action is to be written.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $trid;
|
||||
/**
|
||||
* Language of the term that is to result from this action.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $lang_code;
|
||||
/**
|
||||
* Source language of the term that is to result from this action.
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
private $source_lang_code = null;
|
||||
/**
|
||||
* Array holding translations of the term created by this object prior to it's creation.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $existing_translations = array();
|
||||
/**
|
||||
* The term id of the term to be updated or resulting from this action.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private $term_id;
|
||||
/**
|
||||
* This only gets set for update actions. In this case the new slug has to be compared with the old slug,
|
||||
* to decide whether any slug name sanitation has to happen.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $old_slug;
|
||||
|
||||
/**
|
||||
* @param wpdb $wpdb
|
||||
* @param SitePress $sitepress
|
||||
* @param array $args
|
||||
*/
|
||||
public function __construct( &$wpdb, &$sitepress, $args ) {
|
||||
parent::__construct( $wpdb, $sitepress );
|
||||
/**
|
||||
* Actual name of the term. Same as the name input argument to \wp_update_term or \wp_insert_term
|
||||
*
|
||||
* @var string|bool
|
||||
*/
|
||||
$term = false;
|
||||
$slug = '';
|
||||
$taxonomy = '';
|
||||
/** @var string $lang_code */
|
||||
$lang_code = '';
|
||||
$trid = null;
|
||||
/** @var int|bool $original_tax_id */
|
||||
$original_tax_id = false;
|
||||
/**
|
||||
* Taxonomy_term_id of the parent element
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
$parent = 0;
|
||||
$description = false;
|
||||
$term_group = false;
|
||||
$source_language = null;
|
||||
|
||||
extract( $args, EXTR_OVERWRITE );
|
||||
|
||||
// We cannot create a term unless we at least know its name
|
||||
if ( (string) $term !== '' && $taxonomy ) {
|
||||
$this->wp_new_term_args['name'] = $term;
|
||||
$this->taxonomy = $taxonomy;
|
||||
} else {
|
||||
$this->is_valid = false;
|
||||
|
||||
return;
|
||||
}
|
||||
if ( $parent ) {
|
||||
$this->wp_new_term_args['parent'] = $parent;
|
||||
}
|
||||
if ( $description ) {
|
||||
$this->wp_new_term_args['description'] = $description;
|
||||
}
|
||||
if ( $term_group ) {
|
||||
$this->wp_new_term_args['term_group'] = $term_group;
|
||||
}
|
||||
$this->wp_new_term_args['term_group'] = $term_group;
|
||||
$this->is_valid = $this->set_language_information( $trid, $original_tax_id, $lang_code, $source_language );
|
||||
$this->set_action_type();
|
||||
if ( ! $this->is_update || ( $this->is_update && $slug != $this->old_slug && ! empty( $slug ) ) ) {
|
||||
if ( trim( $slug ) == '' ) {
|
||||
$slug = sanitize_title( $term );
|
||||
}
|
||||
$slug = WPML_Terms_Translations::term_unique_slug( $slug, $taxonomy, $lang_code );
|
||||
$this->wp_new_term_args['slug'] = $slug;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the term update or creation action saved in this object to the database.
|
||||
*
|
||||
* @return array|false
|
||||
* Returns either an array containing the term_id and term_taxonomy_id of the term resulting from this database
|
||||
* write or false on error.
|
||||
*/
|
||||
public function execute() {
|
||||
global $sitepress;
|
||||
|
||||
$switch_lang = new WPML_Temporary_Switch_Language( $sitepress, $this->lang_code );
|
||||
|
||||
remove_action( 'create_term', array( $sitepress, 'create_term' ), 1 );
|
||||
remove_action( 'edit_term', array( $sitepress, 'create_term' ), 1 );
|
||||
add_action( 'create_term', array( $this, 'add_term_language_action' ), 1, 3 );
|
||||
$new_term = false;
|
||||
|
||||
if ( $this->is_valid ) {
|
||||
if ( $this->is_update && $this->term_id ) {
|
||||
$new_term = wp_update_term( $this->term_id, $this->taxonomy, $this->wp_new_term_args );
|
||||
} else {
|
||||
$new_term = wp_insert_term( $this->wp_new_term_args['name'], $this->taxonomy, $this->wp_new_term_args );
|
||||
}
|
||||
}
|
||||
add_action( 'create_term', array( $sitepress, 'create_term' ), 1, 3 );
|
||||
add_action( 'edit_term', array( $sitepress, 'create_term' ), 1, 3 );
|
||||
remove_action( 'create_term', array( $this, 'add_term_language_action' ), 1 );
|
||||
|
||||
if ( ! is_array( $new_term ) ) {
|
||||
$new_term = false;
|
||||
}
|
||||
|
||||
unset( $switch_lang );
|
||||
return $new_term;
|
||||
}
|
||||
|
||||
/**
|
||||
* This action is to be hooked to the WP create_term and edit_term hooks.
|
||||
* It sets the correct language information after a term is saved.
|
||||
*
|
||||
* @param int|string $term_id
|
||||
* @param int|string $term_taxonomy_id
|
||||
* @param string $taxonomy
|
||||
*/
|
||||
public function add_term_language_action( $term_id, $term_taxonomy_id, $taxonomy ) {
|
||||
if ( $this->is_valid && ! $this->is_update && $this->taxonomy == $taxonomy ) {
|
||||
$this->sitepress->set_element_language_details(
|
||||
$term_taxonomy_id,
|
||||
'tax_' . $taxonomy,
|
||||
$this->trid,
|
||||
$this->lang_code,
|
||||
$this->source_lang_code
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the language variables for this object.
|
||||
*
|
||||
* @param bool|int $trid
|
||||
* @param bool|int $original_tax_id
|
||||
* @param string $lang_code
|
||||
* @param bool|string $source_language
|
||||
* @return bool True if the given language parameters allowed for determining valid language information, false
|
||||
* otherwise.
|
||||
*/
|
||||
private function set_language_information( $trid, $original_tax_id, $lang_code, $source_language ) {
|
||||
if ( ! $lang_code || ! $this->sitepress->is_active_language( $lang_code ) ) {
|
||||
return false;
|
||||
} else {
|
||||
$this->lang_code = $lang_code;
|
||||
}
|
||||
if ( ! $trid && $original_tax_id ) {
|
||||
$trid = $this->sitepress->get_element_trid( $original_tax_id, 'tax_' . $this->taxonomy );
|
||||
}
|
||||
if ( $trid ) {
|
||||
$this->trid = $trid;
|
||||
$this->existing_translations = $this->sitepress->get_element_translations( $trid, 'tax_' . $this->taxonomy );
|
||||
|
||||
foreach ( $this->existing_translations as $lang => $translation ) {
|
||||
if ( $original_tax_id && isset( $translation->element_id ) && $translation->element_id == $original_tax_id && isset( $translation->language_code ) && $translation->language_code ) {
|
||||
$this->source_lang_code = $translation->language_code;
|
||||
break;
|
||||
} elseif ( isset( $translation->language_code ) && $translation->language_code && ! $translation->source_language_code ) {
|
||||
$this->source_lang_code = $translation->language_code;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the action type of this object.
|
||||
* In case of this action being an update the is_update flag is set true.
|
||||
* Also the term_id of the existing term is saved in $this->term_id.
|
||||
*/
|
||||
private function set_action_type() {
|
||||
if ( ! $this->trid ) {
|
||||
$this->is_update = false;
|
||||
} elseif ( isset( $this->existing_translations[ $this->lang_code ] ) ) {
|
||||
$existing_db_entry = $this->existing_translations[ $this->lang_code ];
|
||||
if ( isset( $existing_db_entry->element_id ) && $existing_db_entry->element_id ) {
|
||||
// Term update actions need information about the term_id, not the term_taxonomy_id saved in the element_id column of icl_translations.
|
||||
/** @var \stdClass $term */
|
||||
$term = $this->wpdb->get_row(
|
||||
$this->wpdb->prepare(
|
||||
"SELECT t.term_id, t.slug FROM {$this->wpdb->terms} AS t
|
||||
JOIN {$this->wpdb->term_taxonomy} AS tt ON t.term_id=tt.term_id
|
||||
WHERE term_taxonomy_id=%d",
|
||||
$existing_db_entry->element_id
|
||||
)
|
||||
);
|
||||
if ( $term->term_id && $term->slug ) {
|
||||
$this->is_update = true;
|
||||
$this->term_id = $term->term_id;
|
||||
$this->old_slug = $term->slug;
|
||||
} else {
|
||||
$this->is_update = false;
|
||||
}
|
||||
} else {
|
||||
$this->sitepress->delete_element_translation( $this->trid, 'tax_' . $this->taxonomy, $this->lang_code );
|
||||
$this->is_update = false;
|
||||
}
|
||||
} else {
|
||||
$this->is_update = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
/**
|
||||
* WPML Sunrise Script - START
|
||||
*
|
||||
* @author OnTheGoSystems
|
||||
* @version 3.7.0
|
||||
*
|
||||
* Place this script in the wp-content folder and add "define('SUNRISE', 'on');" in wp-config.php
|
||||
* in order to enable using different domains for different languages in multisite mode
|
||||
*
|
||||
* Experimental feature
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class WPML_Sunrise_Lang_In_Domains
|
||||
*
|
||||
* @author OnTheGoSystems
|
||||
*/
|
||||
class WPML_Sunrise_Lang_In_Domains {
|
||||
|
||||
/** @var wpdb $wpdb */
|
||||
private $wpdb;
|
||||
|
||||
/** @var string $table_prefix */
|
||||
private $table_prefix;
|
||||
|
||||
/** @var string $current_blog */
|
||||
private $current_blog;
|
||||
|
||||
/** @var bool $no_recursion */
|
||||
private $no_recursion;
|
||||
|
||||
/**
|
||||
* Method init
|
||||
*/
|
||||
public function init() {
|
||||
if ( ! defined( 'WPML_SUNRISE_MULTISITE_DOMAINS' ) ) {
|
||||
define( 'WPML_SUNRISE_MULTISITE_DOMAINS', true );
|
||||
}
|
||||
|
||||
add_filter( 'query', array( $this, 'query_filter' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $q
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function query_filter( $q ) {
|
||||
$this->set_private_properties();
|
||||
|
||||
if ( ! $this->current_blog && ! $this->no_recursion ) {
|
||||
|
||||
$this->no_recursion = true;
|
||||
|
||||
$domains = $this->extract_variables_from_query( $q, 'domain' );
|
||||
|
||||
if ( $domains && $this->query_has_no_result( $q ) ) {
|
||||
$q = $this->transpose_query_if_one_domain_is_matching( $q, $domains );
|
||||
}
|
||||
|
||||
$this->no_recursion = false;
|
||||
}
|
||||
|
||||
return $q;
|
||||
}
|
||||
|
||||
/**
|
||||
* method set_private_properties
|
||||
*/
|
||||
private function set_private_properties() {
|
||||
global $wpdb, $table_prefix, $current_blog;
|
||||
|
||||
$this->wpdb = $wpdb;
|
||||
$this->table_prefix = $table_prefix;
|
||||
$this->current_blog = $current_blog;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $query
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function extract_variables_from_query( $query, $field ) {
|
||||
$variables = array();
|
||||
$patterns = array(
|
||||
'#WHERE\s+' . $field . '\s+IN\s*\(([^\)]+)\)#',
|
||||
'#WHERE\s+' . $field . '\s*=\s*([^\s]+)#',
|
||||
'#AND\s+' . $field . '\s+IN\s*\(([^\)]+)\)#',
|
||||
'#AND\s+' . $field . '\s*=\s*([^\s]+)#',
|
||||
);
|
||||
|
||||
foreach ( $patterns as $pattern ) {
|
||||
$found = preg_match( $pattern, $query, $matches );
|
||||
if ( $found && array_key_exists( 1, $matches ) ) {
|
||||
$variables = $matches[1];
|
||||
$variables = preg_replace( '/\s+/', '', $variables );
|
||||
$variables = preg_replace( '/[\'"]/', '', $variables );
|
||||
$variables = explode( ',', $variables );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $variables;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $q
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function query_has_no_result( $q ) {
|
||||
return ! (bool) $this->wpdb->get_row( $q );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $q
|
||||
* @param array $domains
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function transpose_query_if_one_domain_is_matching( $q, $domains ) {
|
||||
$paths = $this->extract_variables_from_query( $q, 'path' );
|
||||
|
||||
// Create as many placeholders as $paths we have.
|
||||
$placeholders = implode( ',', array_fill( 0, sizeof( $paths ), '%s' ) );
|
||||
|
||||
// Array with all the parameters for preparing the SQL.
|
||||
$parameters = $paths;
|
||||
$parameters[] = BLOG_ID_CURRENT_SITE;
|
||||
|
||||
// The ORDER is there to get the default site at the end of the results.
|
||||
$blogs = $this->wpdb->get_col(
|
||||
$this->wpdb->prepare(
|
||||
"SELECT blog_id FROM {$this->wpdb->blogs} WHERE path IN ($placeholders) ORDER BY blog_id = %d",
|
||||
$parameters
|
||||
)
|
||||
);
|
||||
|
||||
$found_blog_id = null;
|
||||
foreach ( (array) $blogs as $blog_id ) {
|
||||
$prefix = $this->table_prefix;
|
||||
|
||||
if ( $blog_id > 1 ) {
|
||||
$prefix .= $blog_id . '_';
|
||||
}
|
||||
|
||||
$icl_settings = $this->wpdb->get_var( "SELECT option_value FROM {$prefix}options WHERE option_name = 'icl_sitepress_settings'" );
|
||||
|
||||
if ( $icl_settings ) {
|
||||
$icl_settings = unserialize( $icl_settings );
|
||||
|
||||
if ( $icl_settings && 2 === (int) $icl_settings['language_negotiation_type'] ) {
|
||||
$found_blog_id = $this->get_blog_id_from_domain( $domains, $icl_settings, $blog_id );
|
||||
if ( $found_blog_id ) {
|
||||
$q = $this->wpdb->prepare( "SELECT blog_id FROM {$this->wpdb->blogs} WHERE blog_id = %d", $found_blog_id );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $q;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $domains
|
||||
* @param array $wpml_settings
|
||||
* @param int $blog_id
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function get_blog_id_from_domain( array $domains, array $wpml_settings, $blog_id ) {
|
||||
foreach ( $domains as $domain ) {
|
||||
if ( in_array( 'http://' . $domain, $wpml_settings['language_domains'], true ) ) {
|
||||
return $blog_id;
|
||||
} elseif ( in_array( $domain, $wpml_settings['language_domains'], true ) ) {
|
||||
return $blog_id;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
$wpml_sunrise_lang_in_domains = new WPML_Sunrise_Lang_In_Domains();
|
||||
$wpml_sunrise_lang_in_domains->init();
|
||||
|
||||
/**
|
||||
* WPML Sunrise Script - END
|
||||
*/
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
class WPML_Translation_Batch_Factory {
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
*
|
||||
* @return WPML_Translation_Batch
|
||||
*/
|
||||
public function create( $id ) {
|
||||
global $sitepress;
|
||||
|
||||
$wpdb = $sitepress->get_wpdb();
|
||||
return new WPML_Translation_Batch( $wpdb, $id );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
<?php
|
||||
|
||||
use WPML\TM\ATE\Review\ReviewStatus;
|
||||
|
||||
/**
|
||||
* Represents a helper class for building the SQL statement which retrieves the job,
|
||||
* as well as for converting this collection to specific implementations of \WPML_Element_Translation_Job.
|
||||
*
|
||||
* @package WPML\TM
|
||||
*/
|
||||
class WPML_Abstract_Job_Collection {
|
||||
/**
|
||||
* Instance of \wpdb.
|
||||
*
|
||||
* @var \wpdb $wpdb
|
||||
*/
|
||||
public $wpdb;
|
||||
|
||||
/**
|
||||
* Instance of \SitePress.
|
||||
*
|
||||
* @var \SitePress
|
||||
*/
|
||||
private $sitepress;
|
||||
|
||||
/**
|
||||
* WPML_Abstract_Job_Collection constructor.
|
||||
*
|
||||
* @param WPDB $wpdb An instance of \wpdb.
|
||||
*/
|
||||
public function __construct( WPDB $wpdb ) {
|
||||
$this->wpdb = $wpdb;
|
||||
|
||||
global $sitepress;
|
||||
$this->sitepress = $sitepress;
|
||||
}
|
||||
|
||||
/**
|
||||
* It gets the (INNER) JOIN clause of the query.
|
||||
*
|
||||
* @param bool $single It should only return the last job revision.
|
||||
* @param string $icl_translate_alias The alias for `{$this->wpdb->prefix}icl_translate_job`.
|
||||
* @param string $icl_translations_translated_alias The alias for translated documents in `{$this->wpdb->prefix}icl_translations`.
|
||||
* @param string $icl_translations_original_alias The alias for original documents in `{$this->wpdb->prefix}icl_translations`.
|
||||
* @param string $icl_translation_status_alias The alias for `{$this->wpdb->prefix}icl_translation_status`.
|
||||
* @param string $icl_translate_job_alias The alias for `{$this->wpdb->prefix}icl_translate_job`.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_table_join(
|
||||
$single = false,
|
||||
$icl_translate_alias = 'iclt',
|
||||
$icl_translations_translated_alias = 't',
|
||||
$icl_translations_original_alias = 'ito',
|
||||
$icl_translation_status_alias = 's',
|
||||
$icl_translate_job_alias = 'j'
|
||||
) {
|
||||
$wpdb = &$this->wpdb;
|
||||
|
||||
$max_rev_snippet = '';
|
||||
if ( true !== $single ) {
|
||||
$max_rev_snippet = "JOIN (SELECT rid, MAX(job_id) job_id FROM {$wpdb->prefix}icl_translate_job GROUP BY rid ) jobmax
|
||||
ON ( {$icl_translate_job_alias}.revision IS NULL
|
||||
AND {$icl_translate_job_alias}.rid = jobmax.rid)
|
||||
OR ( {$icl_translate_job_alias}.job_id = jobmax.job_id
|
||||
AND {$icl_translate_job_alias}.translated = 1)";
|
||||
}
|
||||
|
||||
return "{$wpdb->prefix}icl_translate_job {$icl_translate_job_alias}
|
||||
JOIN {$wpdb->prefix}icl_translation_status {$icl_translation_status_alias}
|
||||
ON {$icl_translate_job_alias}.rid = {$icl_translation_status_alias}.rid
|
||||
JOIN {$wpdb->prefix}icl_translations {$icl_translations_translated_alias}
|
||||
ON {$icl_translation_status_alias}.translation_id = {$icl_translations_translated_alias}.translation_id
|
||||
JOIN {$wpdb->prefix}icl_translate {$icl_translate_alias}
|
||||
ON {$icl_translate_alias}.job_id = {$icl_translate_job_alias}.job_id
|
||||
JOIN {$wpdb->prefix}icl_translations {$icl_translations_original_alias}
|
||||
ON {$icl_translations_original_alias}.element_id = {$icl_translate_alias}.field_data
|
||||
AND {$icl_translations_original_alias}.trid = {$icl_translations_translated_alias}.trid
|
||||
{$max_rev_snippet}";
|
||||
}
|
||||
|
||||
/**
|
||||
* It gets the LEFT JOIN clause of the query.
|
||||
*
|
||||
* @param string $icl_translations_original_alias The alias for original documents in `{$this->wpdb->prefix}icl_translations`.
|
||||
* @param string $posts_alias The alias for `{$this->wpdb->prefix}posts`.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function left_join_post( $icl_translations_original_alias = 'ito', $posts_alias = 'p' ) {
|
||||
|
||||
$join = "LEFT JOIN {$this->wpdb->prefix}posts {$posts_alias}
|
||||
ON {$icl_translations_original_alias}.element_id = {$posts_alias}.ID
|
||||
AND {$icl_translations_original_alias}.element_type = CONCAT('post_', {$posts_alias}.post_type)";
|
||||
$select = "SUBSTRING_INDEX({$icl_translations_original_alias}.element_type, '_', 1 ) as element_type_prefix";
|
||||
|
||||
return array( $select, $join );
|
||||
}
|
||||
|
||||
/**
|
||||
* It converts an array of \stdClass jobs into an array of \WPML_Element_Translation_Job instances.
|
||||
*
|
||||
* @param array $jobs The array of \stdClass jobs.
|
||||
*
|
||||
* @return \WPML_Element_Translation_Job[]|\WPML_Post_Translation_Job[]|\WPML_String_Translation_Job[]|\WPML_External_Translation_Job[]
|
||||
*/
|
||||
protected function plain_objects_to_job_instances( $jobs ) {
|
||||
foreach ( $jobs as $key => $job ) {
|
||||
if ( ! is_object( $job ) || ! isset( $job->element_type_prefix ) || ! isset( $job->job_id ) ) {
|
||||
unset( $jobs[ $key ] );
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( 'post' === $job->element_type_prefix ) {
|
||||
$post_translation_job = new WPML_Post_Translation_Job( $job->job_id, $job->batch_id );
|
||||
if ( $post_translation_job->is_translatable_post_type() ) {
|
||||
$jobs[ $key ] = $post_translation_job;
|
||||
} else {
|
||||
unset( $jobs[ $key ] );
|
||||
}
|
||||
} elseif ( 'string' === $job->element_type_prefix ) {
|
||||
$jobs[ $key ] = new WPML_String_Translation_Job( $job->job_id );
|
||||
} else {
|
||||
$jobs[ $key ] = new WPML_External_Translation_Job( $job->job_id, $job->batch_id );
|
||||
}
|
||||
}
|
||||
|
||||
return $jobs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional arguments to filter the results.
|
||||
*
|
||||
* @param array $args {
|
||||
* Optional. An array of arguments.
|
||||
*
|
||||
* @type int translator_id
|
||||
* @type int status
|
||||
* @type int status__not
|
||||
* @type bool include_unassigned
|
||||
* @type int limit_no
|
||||
* @type array language_pairs
|
||||
* @type string service
|
||||
* @type string from
|
||||
* @type string to
|
||||
* @type string type
|
||||
* @type bool overdue
|
||||
* @type string title
|
||||
* }
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function build_where_clause( array $args ) {
|
||||
$defaults_args = array(
|
||||
'translator_id' => 0,
|
||||
'status' => false,
|
||||
'status__not' => false,
|
||||
'include_unassigned' => false,
|
||||
'language_pairs' => array(),
|
||||
'service' => 0,
|
||||
'from' => null,
|
||||
'to' => null,
|
||||
'type' => null,
|
||||
'overdue' => false,
|
||||
'title' => null,
|
||||
);
|
||||
|
||||
$args = array_merge( $defaults_args, $args );
|
||||
|
||||
$translator_id = $args['translator_id'];
|
||||
$status = (int) $args['status'];
|
||||
$status__not = $args['status__not'];
|
||||
$include_unassigned = $args['include_unassigned'];
|
||||
$language_pairs = $args['language_pairs'];
|
||||
$service = $args['service'];
|
||||
$from = $args['from'];
|
||||
$to = $args['to'];
|
||||
$type = $args['type'];
|
||||
$overdue = $args['overdue'];
|
||||
$title = $args['title'];
|
||||
|
||||
$where = sprintf( ' s.status NOT IN ( %d, %d )', ICL_TM_NOT_TRANSLATED, ICL_TM_ATE_CANCELLED );
|
||||
|
||||
if ( $status ) {
|
||||
if ( $status === ICL_TM_NEEDS_REVIEW ) {
|
||||
$where .= $this->wpdb->prepare( ' AND (s.review_status = %s OR s.review_status = %s) ', ReviewStatus::EDITING, ReviewStatus::NEEDS_REVIEW );
|
||||
} else {
|
||||
$where .= $this->wpdb->prepare( ' AND s.status = %d AND (s.review_status IS NULL OR s.review_status = %s)', (int) $status, ReviewStatus::ACCEPTED );
|
||||
}
|
||||
}
|
||||
if ( ICL_TM_DUPLICATE !== $status ) {
|
||||
$where .= $this->wpdb->prepare( ' AND s.status <> %d ', ICL_TM_DUPLICATE );
|
||||
}
|
||||
if ( false !== $status__not ) {
|
||||
$where .= $this->wpdb->prepare( ' AND s.status <> %d ', $status__not );
|
||||
}
|
||||
if ( $from ) {
|
||||
$where .= $this->wpdb->prepare( ' AND t.source_language_code = %s ', $from );
|
||||
}
|
||||
if ( $to ) {
|
||||
$where .= $this->wpdb->prepare( ' AND t.language_code = %s ', $to );
|
||||
}
|
||||
if ( $title ) {
|
||||
$where .= $this->wpdb->prepare( ' AND p.post_title LIKE %s ', '%' . $title . '%' );
|
||||
}
|
||||
|
||||
if ( '' !== $translator_id ) {
|
||||
if ( ! is_numeric( $translator_id ) ) {
|
||||
$_exp = explode( '-', $translator_id );
|
||||
$service = isset( $_exp[1] ) ? implode( '-', array_slice( $_exp, 1 ) ) : 'local';
|
||||
$translator_id = isset( $_exp[2] ) ? $_exp[2] : false;
|
||||
} elseif ( ! $service && ( ! isset( $args['any_translation_service'] ) || ! $args['any_translation_service'] ) ) {
|
||||
$service = 'local';
|
||||
}
|
||||
|
||||
$translator_id_query_parts = array();
|
||||
if ( 0 !== (int) $translator_id ) {
|
||||
$translator_id_query_parts[] = $this->wpdb->prepare( 'j.translator_id = %d', $translator_id );
|
||||
if ( $include_unassigned ) {
|
||||
$review_status = 's.review_status IS NOT NULL';
|
||||
$translator_id_query_parts[] = ' j.translator_id = 0 OR j.translator_id IS NULL OR ' . $review_status;
|
||||
}
|
||||
if ( true === (bool) $translator_id_query_parts ) {
|
||||
$where .= ' AND (' . join( ' OR ', $translator_id_query_parts ) . ') ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$where .= ! empty( $service ) ? $this->wpdb->prepare( ' AND s.translation_service=%s ', $service ) : '';
|
||||
|
||||
if ( $this->sitepress ) {
|
||||
$post_types = array_keys( $this->sitepress->get_translatable_documents() );
|
||||
if ( $post_types ) {
|
||||
$where .= ' AND (p.post_type IS NULL OR p.post_type IN (' . wpml_prepare_in( $post_types, '%s' ) . ' )) ';
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $from ) && false !== (bool) $language_pairs && is_array( $language_pairs ) && $translator_id ) {
|
||||
/**
|
||||
* Only if we filter by translator, make sure to use just the 'from' languages that apply
|
||||
* in no translator_id, omit condition and all will be pulled.
|
||||
*/
|
||||
if ( ! empty( $to ) ) {
|
||||
/**
|
||||
* Get 'from' languages corresponding to $to (to $translator_id).
|
||||
*/
|
||||
$from_languages = array();
|
||||
foreach ( $language_pairs as $fl => $tls ) {
|
||||
if ( isset( $tls[ $to ] ) ) {
|
||||
$from_languages[] = $fl;
|
||||
}
|
||||
}
|
||||
if ( $from_languages ) {
|
||||
$where .= ' AND t.source_language_code IN (' . wpml_prepare_in( $from_languages ) . ') ';
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* All to all case.
|
||||
* Get all possible combinations for $translator_id.
|
||||
*/
|
||||
$from_languages = array_keys( $language_pairs );
|
||||
$where_conditions = array();
|
||||
foreach ( $from_languages as $fl ) {
|
||||
$prepared_in_values = wpml_prepare_in( array_keys( $language_pairs[ $fl ] ) );
|
||||
$where_conditions[] = ' (' . $this->wpdb->prepare( 't.source_language_code = %s', $fl ) . ' AND t.language_code IN (' . $prepared_in_values . ')) ';
|
||||
}
|
||||
|
||||
if ( ! empty( $where_conditions ) ) {
|
||||
$where .= ' AND ( ' . join( ' OR ', $where_conditions ) . ') ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $to ) && $translator_id && ! empty( $from ) && isset( $language_pairs[ $from ] ) && false !== (bool) $language_pairs[ $from ] ) {
|
||||
/**
|
||||
* Only if we filter by translator, make sure to use just the 'from' languages that apply
|
||||
* in no translator_id, omit condition and all will be pulled.
|
||||
* Get languages the user can translate into from $from.
|
||||
*/
|
||||
$where .= ' AND t.language_code IN(' . wpml_prepare_in( array_keys( $language_pairs[ $from ] ) ) . ')';
|
||||
}
|
||||
|
||||
$where .= ! empty( $type ) ? $this->wpdb->prepare( ' AND ito.element_type=%s ', $type ) : '';
|
||||
|
||||
if ( $overdue ) {
|
||||
$today_date = date( 'Y-m-d' );
|
||||
|
||||
$statusCond = wpml_prepare_in( [ ICL_TM_WAITING_FOR_TRANSLATOR, ICL_TM_IN_PROGRESS ], '%d' );
|
||||
$where .= $this->wpdb->prepare( " AND j.deadline_date IS NOT NULL AND s.status IN ({$statusCond}) AND j.deadline_date < %s AND j.deadline_date <> '0000-00-00 00:00:00'", $today_date );
|
||||
}
|
||||
|
||||
return $where;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,451 @@
|
||||
<?php
|
||||
|
||||
class WPML_Save_Translation_Data_Action extends WPML_Translation_Job_Helper_With_API {
|
||||
|
||||
/** @var WPML_TM_Records $tm_records */
|
||||
private $tm_records;
|
||||
|
||||
/** @var array $data */
|
||||
private $data;
|
||||
|
||||
private $redirect_target = false;
|
||||
private $translate_link_targets_in_posts;
|
||||
private $translate_link_targets_in_strings;
|
||||
|
||||
public function __construct( $data, $tm_records ) {
|
||||
global $wpdb, $ICL_Pro_Translation, $sitepress;
|
||||
parent::__construct();
|
||||
$this->data = $data;
|
||||
$this->tm_records = $tm_records;
|
||||
$translate_link_targets_global_state = new WPML_Translate_Link_Target_Global_State( $sitepress );
|
||||
$this->translate_link_targets_in_posts = new WPML_Translate_Link_Targets_In_Posts( $translate_link_targets_global_state, $wpdb, $ICL_Pro_Translation );
|
||||
$this->translate_link_targets_in_strings = new WPML_Translate_Link_Targets_In_Strings( $translate_link_targets_global_state, $wpdb, new WPML_WP_API(), $ICL_Pro_Translation );
|
||||
|
||||
}
|
||||
|
||||
function save_translation() {
|
||||
global $wpdb, $sitepress, $iclTranslationManagement, $wpml_post_translations;
|
||||
|
||||
$new_post_id = false;
|
||||
$is_incomplete = false;
|
||||
$data = $this->data;
|
||||
/** @var stdClass $job */
|
||||
$job = ! empty( $data['job_id'] ) ? $this->get_translation_job( $data['job_id'], true ) : null;
|
||||
$needs_second_update = $job && $job->needs_update ? 1 : 0;
|
||||
$original_post = null;
|
||||
$element_type_prefix = null;
|
||||
if ( is_object( $job ) ) {
|
||||
$element_type_prefix = $iclTranslationManagement->get_element_type_prefix_from_job( $job );
|
||||
$original_post = $iclTranslationManagement->get_post( $job->original_doc_id, $element_type_prefix );
|
||||
}
|
||||
|
||||
$is_external = apply_filters( 'wpml_is_external', false, $element_type_prefix );
|
||||
$data_to_validate = array(
|
||||
'original_post' => $original_post,
|
||||
'type_prefix' => $element_type_prefix,
|
||||
'data' => $data,
|
||||
'is_external' => $is_external,
|
||||
);
|
||||
|
||||
$validation_results = $this->get_validation_results( $job, $data_to_validate );
|
||||
|
||||
if ( ! $validation_results['is_valid'] ) {
|
||||
$this->handle_failed_validation( $validation_results, $data_to_validate );
|
||||
$res = false;
|
||||
} else {
|
||||
foreach ( $data['fields'] as $fieldname => $field ) {
|
||||
if ( substr( $fieldname, 0, 6 ) === 'field-' ) {
|
||||
$field = apply_filters( 'wpml_tm_save_translation_cf', $field, $fieldname, $data );
|
||||
}
|
||||
$this->save_translation_field( $field['tid'], $field );
|
||||
if ( ! isset( $field['finished'] ) || ! $field['finished'] ) {
|
||||
$is_incomplete = true;
|
||||
}
|
||||
}
|
||||
|
||||
$icl_translate_job = $this->tm_records->icl_translate_job_by_job_id( $data['job_id'] );
|
||||
$rid = $icl_translate_job->rid();
|
||||
$translation_status = $this->tm_records->icl_translation_status_by_rid( $rid );
|
||||
$translation_id = $translation_status->translation_id();
|
||||
if ( ( $is_incomplete === true || empty( $data['complete'] ) ) && empty( $data['resign'] ) ) {
|
||||
$iclTranslationManagement->update_translation_status(
|
||||
array(
|
||||
'translation_id' => $translation_id,
|
||||
'status' => ICL_TM_IN_PROGRESS,
|
||||
)
|
||||
);
|
||||
$icl_translate_job->update( array( 'translated' => 0 ) );
|
||||
|
||||
self::notify_job_in_progress( $element_type_prefix, $job );
|
||||
}
|
||||
|
||||
$element_id = $translation_status->element_id();
|
||||
delete_post_meta( $element_id, '_icl_lang_duplicate_of' );
|
||||
|
||||
if ( ! empty( $data['complete'] ) && ! $is_incomplete ) {
|
||||
$icl_translate_job->update(
|
||||
array(
|
||||
'translated' => 1,
|
||||
'completed_date' => date( 'Y-m-d H:i:s' ),
|
||||
)
|
||||
);
|
||||
$job = $this->get_translation_job( $data['job_id'], true );
|
||||
|
||||
if ( $is_external ) {
|
||||
self::save_external( $element_type_prefix, $job, [ $this, 'decode_field_data' ] );
|
||||
} else {
|
||||
if ( $element_id ) {
|
||||
$postarr['ID'] = $_POST['post_ID'] = $element_id;
|
||||
} else {
|
||||
$postarr['post_status'] = ! $sitepress->get_setting( 'translated_document_status' ) ? 'draft' : $original_post->post_status;
|
||||
}
|
||||
|
||||
foreach ( $job->elements as $field ) {
|
||||
switch ( $field->field_type ) {
|
||||
case 'title':
|
||||
$postarr['post_title'] = $this->decode_field_data( $field->field_data_translated, $field->field_format );
|
||||
break;
|
||||
case 'body':
|
||||
$postarr['post_content'] = $this->decode_field_data(
|
||||
$field->field_data_translated,
|
||||
$field->field_format
|
||||
);
|
||||
break;
|
||||
case 'excerpt':
|
||||
$postarr['post_excerpt'] = $this->decode_field_data( $field->field_data_translated, $field->field_format );
|
||||
break;
|
||||
case 'URL':
|
||||
$postarr['post_name'] = $this->decode_field_data( $field->field_data_translated, $field->field_format );
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$postarr['post_author'] = $original_post->post_author;
|
||||
$postarr['post_type'] = $original_post->post_type;
|
||||
|
||||
if ( $sitepress->get_setting( 'sync_comment_status' ) ) {
|
||||
$postarr['comment_status'] = $original_post->comment_status;
|
||||
}
|
||||
if ( $sitepress->get_setting( 'sync_ping_status' ) ) {
|
||||
$postarr['ping_status'] = $original_post->ping_status;
|
||||
}
|
||||
if ( $sitepress->get_setting( 'sync_page_ordering' ) ) {
|
||||
$postarr['menu_order'] = $original_post->menu_order;
|
||||
}
|
||||
if ( $sitepress->get_setting( 'sync_private_flag' ) && $original_post->post_status == 'private' ) {
|
||||
$postarr['post_status'] = 'private';
|
||||
}
|
||||
if ( $sitepress->get_setting( 'sync_password' ) && $original_post->post_password ) {
|
||||
$postarr['post_password'] = $original_post->post_password;
|
||||
}
|
||||
if ( $sitepress->get_setting( 'sync_post_date' ) ) {
|
||||
$postarr['post_date'] = $original_post->post_date;
|
||||
}
|
||||
|
||||
if ( $original_post->post_parent ) {
|
||||
$parent_id = $wpml_post_translations->element_id_in( $original_post->post_parent, $job->language_code );
|
||||
}
|
||||
|
||||
if ( isset( $parent_id ) && $sitepress->get_setting( 'sync_page_parent' ) ) {
|
||||
$_POST['post_parent'] = $postarr['post_parent'] = $parent_id;
|
||||
$_POST['parent_id'] = $postarr['parent_id'] = $parent_id;
|
||||
}
|
||||
|
||||
$_POST['trid'] = $translation_status->trid();
|
||||
$_POST['lang'] = $job->language_code;
|
||||
$_POST['skip_sitepress_actions'] = true;
|
||||
$_POST['needs_second_update'] = $needs_second_update;
|
||||
|
||||
/* @deprecated Use `wpml_pre_save_pro_translation` instead */
|
||||
$postarr = apply_filters( 'icl_pre_save_pro_translation', $postarr );
|
||||
|
||||
$postarr = apply_filters( 'wpml_pre_save_pro_translation', $postarr, $job );
|
||||
|
||||
// it's an update and user do not want to translate urls so do not change the url
|
||||
if ( $element_id ) {
|
||||
if ( $sitepress->get_setting( 'translated_document_page_url' ) !== 'translate' ) {
|
||||
$postarr['post_name'] = $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
"SELECT post_name
|
||||
FROM {$wpdb->posts}
|
||||
WHERE ID=%d
|
||||
LIMIT 1",
|
||||
$element_id
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$existing_post = get_post( $element_id );
|
||||
$postarr['post_date'] = $existing_post->post_date;
|
||||
$postarr['post_date_gmt'] = $existing_post->post_date_gmt;
|
||||
}
|
||||
|
||||
$new_post_id = wpml_get_create_post_helper()->insert_post( $postarr, $job->language_code );
|
||||
|
||||
icl_cache_clear( $postarr['post_type'] . 's_per_language' ); // clear post counter per language in cache
|
||||
|
||||
// set taxonomies for users with limited caps
|
||||
if ( ! current_user_can( 'manage-categories' ) && ! empty( $postarr['tax_input'] ) ) {
|
||||
foreach ( $postarr['tax_input'] as $taxonomy => $terms ) {
|
||||
wp_set_post_terms( $new_post_id, $terms, $taxonomy, false ); // true to append to existing tags | false to replace existing tags
|
||||
}
|
||||
}
|
||||
|
||||
$data['fields'] = apply_filters( 'wpml_tm_job_fields', $data['fields'], $job );
|
||||
|
||||
do_action( 'icl_pro_translation_saved', $new_post_id, $data['fields'], $job );
|
||||
do_action( 'wpml_translation_job_saved', $new_post_id, $data['fields'], $job );
|
||||
|
||||
// update body translation with the links fixed
|
||||
$new_post_content = $wpdb->get_var( $wpdb->prepare( "SELECT post_content FROM {$wpdb->posts} WHERE ID=%d", $new_post_id ) );
|
||||
foreach ( $job->elements as $job_element ) {
|
||||
if ( $job_element->field_type === 'body' ) {
|
||||
$fields_data_translated = apply_filters( 'wpml_tm_job_data_post_content', $new_post_content );
|
||||
$fields_data_translated = $this->encode_field_data( $fields_data_translated );
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'icl_translate',
|
||||
array( 'field_data_translated' => $fields_data_translated ),
|
||||
array(
|
||||
'job_id' => $data['job_id'],
|
||||
'field_type' => 'body',
|
||||
)
|
||||
);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$sitepress->copy_custom_fields( $original_post->ID, $new_post_id );
|
||||
|
||||
// set specific custom fields
|
||||
$copied_custom_fields = array( '_top_nav_excluded', '_cms_nav_minihome' );
|
||||
foreach ( $copied_custom_fields as $ccf ) {
|
||||
$val = get_post_meta( $original_post->ID, $ccf, true );
|
||||
update_post_meta( $new_post_id, $ccf, $val );
|
||||
}
|
||||
|
||||
// sync _wp_page_template
|
||||
if ( $sitepress->get_setting( 'sync_page_template' ) ) {
|
||||
$_wp_page_template = get_post_meta( $original_post->ID, '_wp_page_template', true );
|
||||
if ( ! empty( $_wp_page_template ) ) {
|
||||
update_post_meta( $new_post_id, '_wp_page_template', $_wp_page_template );
|
||||
}
|
||||
}
|
||||
|
||||
$this->package_helper->save_job_custom_fields(
|
||||
$job,
|
||||
$new_post_id,
|
||||
\WPML\TM\Settings\Repository::getCustomFields()
|
||||
);
|
||||
|
||||
$link = get_edit_post_link( $new_post_id );
|
||||
if ( $link == '' ) {
|
||||
// the current user can't edit so just include permalink
|
||||
$link = get_permalink( $new_post_id );
|
||||
}
|
||||
|
||||
if ( ! $element_id ) {
|
||||
$wpdb->delete(
|
||||
$wpdb->prefix . 'icl_translations',
|
||||
array(
|
||||
'element_id' => $new_post_id,
|
||||
'element_type' => 'post_' . $postarr['post_type'],
|
||||
)
|
||||
);
|
||||
$wpdb->update( $wpdb->prefix . 'icl_translations', array( 'element_id' => $new_post_id ), array( 'translation_id' => $translation_id ) );
|
||||
$user_message = __( 'Translation added: ', 'wpml-translation-management' ) . '<a href="' . $link . '">' . $postarr['post_title'] . '</a>.';
|
||||
} else {
|
||||
$user_message = __( 'Translation updated: ', 'wpml-translation-management' ) . '<a href="' . $link . '">' . $postarr['post_title'] . '</a>.';
|
||||
}
|
||||
|
||||
// set stickiness
|
||||
// is the original post a sticky post?
|
||||
$sticky_posts = get_option( 'sticky_posts' );
|
||||
$is_original_sticky = $original_post->post_type == 'post' && in_array( $original_post->ID, $sticky_posts );
|
||||
|
||||
if ( $is_original_sticky && $sitepress->get_setting( 'sync_sticky_flag' ) ) {
|
||||
stick_post( $new_post_id );
|
||||
} else {
|
||||
if ( $original_post->post_type == 'post' && ! is_null( $element_id ) ) {
|
||||
unstick_post( $new_post_id ); // just in case - if this is an update and the original post stickiness has changed since the post was sent for translation
|
||||
}
|
||||
}
|
||||
|
||||
$this->add_message(
|
||||
array(
|
||||
'type' => 'updated',
|
||||
'text' => $user_message,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( $this->get_tm_setting( array( 'notification', 'completed' ) ) != ICL_TM_NOTIFICATION_NONE
|
||||
&& $data['job_id']
|
||||
) {
|
||||
do_action( 'wpml_tm_complete_job_notification', $data['job_id'], ! is_null( $element_id ) );
|
||||
}
|
||||
|
||||
$iclTranslationManagement->set_page_url( $new_post_id );
|
||||
|
||||
if ( isset( $job ) && isset( $job->language_code ) && isset( $job->source_language_code ) ) {
|
||||
$this->save_terms_for_job( $data['job_id'] );
|
||||
}
|
||||
|
||||
// sync post format
|
||||
// Must be after save terms otherwise it gets lost.
|
||||
if ( $sitepress->get_setting( 'sync_post_format' ) ) {
|
||||
$_wp_post_format = get_post_format( $original_post->ID );
|
||||
set_post_format( $new_post_id, $_wp_post_format );
|
||||
}
|
||||
|
||||
do_action( 'icl_pro_translation_completed', $new_post_id, $data['fields'], $job );
|
||||
do_action( 'wpml_pro_translation_completed', $new_post_id, $data['fields'], $job );
|
||||
|
||||
$translation_status->update( [
|
||||
'status' => apply_filters( 'wpml_tm_applied_job_status', ICL_TM_COMPLETE, $job, $new_post_id ),
|
||||
'needs_update' => $needs_second_update,
|
||||
] );
|
||||
|
||||
$this->translate_link_targets_in_posts->new_content();
|
||||
$this->translate_link_targets_in_strings->new_content();
|
||||
|
||||
if ( ! defined( 'REST_REQUEST' ) && ! defined( 'XMLRPC_REQUEST' ) && ! defined( 'DOING_AJAX' ) && ! isset( $_POST['xliff_upload'] ) ) {
|
||||
$action_type = is_null( $element_id ) ? 'added' : 'updated';
|
||||
$element_id = is_null( $element_id ) ? $new_post_id : $element_id;
|
||||
$this->redirect_target = admin_url( sprintf( 'admin.php?page=%s&%s=%d&element_type=%s', WPML_TM_FOLDER . '/menu/translations-queue.php', $action_type, $element_id, $element_type_prefix ) );
|
||||
}
|
||||
} else {
|
||||
$this->add_message(
|
||||
array(
|
||||
'type' => 'updated',
|
||||
'text' => __( 'Translation (incomplete) saved.', 'wpml-translation-management' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$res = true;
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false if after saving the translation no redirection is to happen or the target of the redirection
|
||||
* in case saving the data is followed by a redirect.
|
||||
*
|
||||
* @return false|string
|
||||
*/
|
||||
function get_redirect_target() {
|
||||
|
||||
return $this->redirect_target;
|
||||
}
|
||||
|
||||
private function save_translation_field( $tid, $field ) {
|
||||
global $wpdb;
|
||||
|
||||
$update = [];
|
||||
if ( isset( $field['data'] ) ) {
|
||||
$update['field_data_translated'] = $this->encode_field_data( $field['data'] );
|
||||
}
|
||||
$update['field_finished'] = isset( $field['finished'] ) && $field['finished'] ? 1 : 0;
|
||||
|
||||
$wpdb->update( $wpdb->prefix . 'icl_translate', $update, array( 'tid' => $tid ) );
|
||||
}
|
||||
|
||||
private function handle_failed_validation( $validation_results, $data_to_validate ) {
|
||||
if ( isset( $validation_results['messages'] ) ) {
|
||||
$messages = (array) $validation_results['messages'];
|
||||
if ( $messages ) {
|
||||
foreach ( $messages as $message ) {
|
||||
$this->add_message(
|
||||
array(
|
||||
'type' => 'error',
|
||||
'text' => $message,
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$this->add_message(
|
||||
array(
|
||||
'type' => 'error',
|
||||
'text' => __( 'Submitted data is not valid.', 'wpml-translation-management' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
do_action( 'wpml_translation_validation_failed', $validation_results, $data_to_validate );
|
||||
}
|
||||
|
||||
private function get_validation_results( $job, $data_to_validate ) {
|
||||
$is_valid = true;
|
||||
$original_post = $data_to_validate['original_post'];
|
||||
$element_type_prefix = $data_to_validate['type_prefix'];
|
||||
$validation_default_results = array(
|
||||
'is_valid' => $is_valid,
|
||||
'messages' => array(),
|
||||
);
|
||||
if ( ! $job || ! $original_post || ! $element_type_prefix ) {
|
||||
$is_valid = false;
|
||||
if ( ! $job ) {
|
||||
$validation_default_results['messages'][] = __( 'Job ID is missing', 'wpml-translation-management' );
|
||||
}
|
||||
if ( ! $original_post ) {
|
||||
$validation_default_results['messages'][] = __( 'The original post cannot be retrieved', 'wpml-translation-management' );
|
||||
}
|
||||
if ( ! $element_type_prefix ) {
|
||||
$validation_default_results['messages'][] = __( 'The type of the post cannot be retrieved', 'wpml-translation-management' );
|
||||
}
|
||||
} elseif ( ! $this->tm_records->icl_translate_job_by_job_id( $job->job_id )->is_open() ) {
|
||||
$is_valid = false;
|
||||
$validation_default_results['messages'][] = __( 'This job cannot be edited anymore because a newer job for this element exists.', 'wpml-translation-management' );
|
||||
}
|
||||
$validation_default_results['is_valid'] = $is_valid;
|
||||
$validation_results = apply_filters( 'wpml_translation_validation_data', $validation_default_results, $data_to_validate );
|
||||
$validation_results = array_merge( $validation_default_results, $validation_results );
|
||||
|
||||
if ( ! $is_valid && $validation_results['is_valid'] ) {
|
||||
$validation_results['is_valid'] = $is_valid;
|
||||
}
|
||||
|
||||
return $validation_results;
|
||||
}
|
||||
|
||||
private function save_terms_for_job( $job_id ) {
|
||||
require_once WPML_TM_PATH . '/inc/translation-jobs/wpml-translation-jobs-collection.class.php';
|
||||
|
||||
$job = new WPML_Post_Translation_Job( $job_id );
|
||||
$job->save_terms_to_post();
|
||||
}
|
||||
|
||||
private function add_message( $message ) {
|
||||
global $iclTranslationManagement;
|
||||
|
||||
$iclTranslationManagement->add_message( $message );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $element_type_prefix
|
||||
* @param object $job
|
||||
* @param callable $decoder
|
||||
*/
|
||||
private static function save_external( $element_type_prefix, $job, $decoder ) {
|
||||
do_action( 'wpml_save_external', $element_type_prefix, $job, $decoder );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $element_type_prefix
|
||||
* @param object $job
|
||||
*/
|
||||
private static function notify_job_in_progress( $element_type_prefix, $job ) {
|
||||
/**
|
||||
* The action triggered when a job is marked as in progress
|
||||
*
|
||||
* @param string $element_type_prefix
|
||||
* @param object $job
|
||||
* @since 2.10.0
|
||||
*/
|
||||
do_action( 'wpml_tm_job_in_progress', $element_type_prefix, $job );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
class WPML_Translation_Job_Helper_With_API extends WPML_Translation_Job_Helper {
|
||||
|
||||
/** @var WPML_Element_Translation_Package $package_helper */
|
||||
protected $package_helper;
|
||||
|
||||
function __construct() {
|
||||
$this->package_helper = new WPML_Element_Translation_Package();
|
||||
}
|
||||
|
||||
protected function get_translation_job( $job_id, $include_non_translatable_elements = false, $revisions = 0 ) {
|
||||
return wpml_tm_load_job_factory()->get_translation_job( $job_id, $include_non_translatable_elements, $revisions );
|
||||
}
|
||||
|
||||
protected function get_lang_by_rid( $rid ) {
|
||||
global $wpdb;
|
||||
|
||||
return $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
"SELECT i.language_code
|
||||
FROM {$wpdb->prefix}icl_translations i
|
||||
JOIN {$wpdb->prefix}icl_translation_status s
|
||||
ON s.translation_id = i.translation_id
|
||||
WHERE s.rid = %d
|
||||
LIMIT 1",
|
||||
$rid
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
class WPML_Translation_Job_Helper {
|
||||
|
||||
public function encode_field_data( $data ) {
|
||||
return null === $data ? '' : base64_encode( $data );
|
||||
}
|
||||
|
||||
public function decode_field_data( $data, $format ) {
|
||||
return $this->get_core_translation_management()->decode_field_data( $data, $format );
|
||||
}
|
||||
|
||||
protected function get_tm_setting( $indexes ) {
|
||||
$core_tm = $this->get_core_translation_management();
|
||||
if ( empty( $core_tm->settings ) ) {
|
||||
$core_tm->init();
|
||||
}
|
||||
|
||||
$settings = $core_tm->get_settings();
|
||||
|
||||
foreach ( $indexes as $index ) {
|
||||
$settings = isset( $settings[ $index ] ) ? $settings[ $index ] : null;
|
||||
if ( ! isset( $settings ) ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TranslationManagement
|
||||
*/
|
||||
public static function get_core_translation_management() {
|
||||
/** TranslationManagement $iclTranslationManagement */
|
||||
global $iclTranslationManagement;
|
||||
|
||||
return $iclTranslationManagement;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
require_once WPML_TM_PATH . '/inc/translation-jobs/helpers/wpml-update-translation-data-action.class.php';
|
||||
|
||||
class WPML_TM_Update_External_Translation_Data_Action extends WPML_TM_Update_Translation_Data_Action {
|
||||
|
||||
protected function populate_prev_translation( $rid, array $package ) {
|
||||
list( $prev_job_id ) = $this->get_prev_job_data( $rid );
|
||||
|
||||
$prev_translation = [];
|
||||
$prev_job = $this->get_translation_job( $prev_job_id );
|
||||
/** @var stdClass $prev_job */
|
||||
if ( isset( $prev_job->original_doc_id ) ) {
|
||||
foreach ( $prev_job->elements as $element ) {
|
||||
$prev_translation[ $element->field_type ] = new WPML_TM_Translated_Field(
|
||||
$element->field_data,
|
||||
$element->field_data_translated,
|
||||
$element->field_finished
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return apply_filters( 'wpml_tm_populate_prev_translation', $prev_translation, $package, $this->get_lang_by_rid( $rid ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
require_once WPML_TM_PATH . '/inc/translation-jobs/helpers/wpml-update-translation-data-action.class.php';
|
||||
|
||||
class WPML_TM_Update_Post_Translation_Data_Action extends WPML_TM_Update_Translation_Data_Action {
|
||||
|
||||
protected function populate_prev_translation( $rid, array $package ) {
|
||||
global $wpml_post_translations;
|
||||
|
||||
$prev_translation = array();
|
||||
if ( (bool) ( $lang = $this->get_lang_by_rid( $rid ) ) === true ) {
|
||||
list( $prev_job_id ) = $this->get_prev_job_data( $rid );
|
||||
$prev_job = $this->get_translation_job( $prev_job_id );
|
||||
|
||||
if ( $prev_job ) {
|
||||
foreach ( $package['contents'] as $field_name => $field ) {
|
||||
if ( array_key_exists( 'translate', $field ) && $field['translate'] ) {
|
||||
$element = $this->get_previous_element( $prev_job, $field_name );
|
||||
if ( $element ) {
|
||||
$prev_translation[ $field_name ] = new WPML_TM_Translated_Field(
|
||||
$element->field_data,
|
||||
$element->field_data_translated,
|
||||
$element->field_finished
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$translated_post_id = $wpml_post_translations->element_id_in( $package['contents']['original_id']['data'], $lang );
|
||||
if ( $translated_post_id ) {
|
||||
$package_trans = $this->package_helper->create_translation_package( $translated_post_id );
|
||||
$translated_contents = $package_trans['contents'];
|
||||
|
||||
foreach ( $package['contents'] as $field_name => $field ) {
|
||||
if ( ! array_key_exists( $field_name, $prev_translation )
|
||||
&& array_key_exists( $field_name, $translated_contents )
|
||||
&& array_key_exists( 'data', $translated_contents[ $field_name ] )
|
||||
) {
|
||||
$prev_translation[ $field_name ] = new WPML_TM_Translated_Field(
|
||||
'',
|
||||
$translated_contents[ $field_name ]['data'],
|
||||
false );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$prev_translation = apply_filters( 'wpml_tm_populate_prev_translation', $prev_translation, $package, $lang );
|
||||
}
|
||||
|
||||
return $prev_translation;
|
||||
}
|
||||
|
||||
private function get_previous_element( $prev_job, $field_name ) {
|
||||
foreach ( $prev_job->elements as $element ) {
|
||||
if ( $element->field_type == $field_name ) {
|
||||
return $element;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
use WPML\FP\Obj;
|
||||
use WPML\TM\API\Job\Map;
|
||||
|
||||
abstract class WPML_TM_Update_Translation_Data_Action extends WPML_Translation_Job_Helper_With_API {
|
||||
|
||||
function get_prev_job_data( $rid ) {
|
||||
global $wpdb;
|
||||
|
||||
// if we have a previous job_id for this rid mark it as the top (last) revision
|
||||
return $wpdb->get_row(
|
||||
$wpdb->prepare(
|
||||
"SELECT job_id, translated
|
||||
FROM {$wpdb->prefix}icl_translate_job
|
||||
WHERE rid=%d
|
||||
AND revision IS NULL
|
||||
LIMIT 1",
|
||||
$rid
|
||||
),
|
||||
ARRAY_N
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a translation job record in icl_translate_job
|
||||
*
|
||||
* @param mixed $rid
|
||||
* @param mixed $translator_id
|
||||
* @param $translation_package
|
||||
* @param array $batch_options
|
||||
*
|
||||
* @return bool|int
|
||||
*/
|
||||
function add_translation_job( $rid, $translator_id, array $translation_package, array $batch_options ) {
|
||||
global $wpdb, $current_user;
|
||||
|
||||
$previousStatus = \WPML_TM_ICL_Translation_Status::makeByRid( $rid )->previous();
|
||||
if (
|
||||
$previousStatus->map( Obj::prop( 'status' ) )->getOrElse( null ) === (string) ICL_TM_ATE_CANCELLED
|
||||
) {
|
||||
$job_id = Map::fromRid( $rid );
|
||||
} else {
|
||||
|
||||
$translation_status = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}icl_translation_status WHERE rid=%d", $rid ) );
|
||||
$prev_translation = $this->get_translated_field_values( $rid, $translation_package );
|
||||
if ( ! $current_user->ID ) {
|
||||
$manager_id = $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
"SELECT manager_id FROM {$wpdb->prefix}icl_translate_job WHERE rid=%d ORDER BY job_id DESC LIMIT 1",
|
||||
$rid
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$manager_id = $current_user->ID;
|
||||
}
|
||||
|
||||
$translate_job_insert_data = array(
|
||||
'rid' => $rid,
|
||||
'translator_id' => $translator_id,
|
||||
'translated' => 0,
|
||||
'manager_id' => (int) $manager_id,
|
||||
);
|
||||
|
||||
if ( isset( $batch_options['deadline_date'] ) ) {
|
||||
$translate_job_insert_data['deadline_date'] = $batch_options['deadline_date'];
|
||||
}
|
||||
|
||||
if ( isset( $translation_package['title'] ) ) {
|
||||
$translate_job_insert_data['title'] = mb_substr( $translation_package['title'], 0, 160 );
|
||||
}
|
||||
|
||||
$wpdb->insert( $wpdb->prefix . 'icl_translate_job', $translate_job_insert_data );
|
||||
$job_id = $wpdb->insert_id;
|
||||
|
||||
$this->package_helper->save_package_to_job( $translation_package, $job_id, $prev_translation );
|
||||
if ( (int) $translation_status->status !== ICL_TM_DUPLICATE ) {
|
||||
$this->fire_notification_actions( $job_id, $translation_status, $translator_id );
|
||||
}
|
||||
}
|
||||
|
||||
return $job_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $prev_id
|
||||
* @param array $package
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
abstract protected function populate_prev_translation( $prev_id, array $package );
|
||||
|
||||
/**
|
||||
* @param int $rid
|
||||
* @param array $package
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function get_translated_field_values( $rid, array $package ) {
|
||||
global $wpdb;
|
||||
|
||||
$prev_translations = $this->populate_prev_translation( $rid, $package );
|
||||
|
||||
if ( ! $prev_translations ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
// if we have a previous job_id for this rid mark it as the top (last) revision
|
||||
list( $prev_job_id, $prev_job_translated ) = $this->get_prev_job_data( $rid );
|
||||
|
||||
if ( ! is_null( $prev_job_id ) ) {
|
||||
$last_rev_prepare = $wpdb->prepare(
|
||||
"
|
||||
SELECT MAX(revision)
|
||||
FROM {$wpdb->prefix}icl_translate_job
|
||||
WHERE rid=%d
|
||||
AND ( revision IS NOT NULL OR translated = 1 )
|
||||
",
|
||||
$rid
|
||||
);
|
||||
$last_rev = $wpdb->get_var( $last_rev_prepare );
|
||||
$wpdb->update( $wpdb->prefix . 'icl_translate_job', array( 'revision' => $last_rev + 1 ), array( 'job_id' => $prev_job_id ) );
|
||||
}
|
||||
|
||||
return $prev_translations;
|
||||
}
|
||||
|
||||
protected function fire_notification_actions( $job_id, $translation_status, $translator_id ) {
|
||||
$job = wpml_tm_load_job_factory()->get_translation_job( $job_id, false, 0, true );
|
||||
if ( $job && $translation_status->translation_service === 'local' ) {
|
||||
if ( $this->get_tm_setting( array( 'notification', 'new-job' ) ) == ICL_TM_NOTIFICATION_IMMEDIATELY ) {
|
||||
if ( $job_id ) {
|
||||
if ( empty( $translator_id ) ) {
|
||||
do_action( 'wpml_tm_new_job_notification', $job );
|
||||
} else {
|
||||
do_action( 'wpml_tm_assign_job_notification', $job, $translator_id );
|
||||
}
|
||||
}
|
||||
}
|
||||
do_action( 'wpml_added_local_translation_job', $job_id );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,393 @@
|
||||
<?php
|
||||
|
||||
require_once WPML_TM_PATH . '/inc/translation-jobs/jobs/wpml-translation-job.class.php';
|
||||
|
||||
use WPML\FP\Obj;
|
||||
|
||||
abstract class WPML_Element_Translation_Job extends WPML_Translation_Job {
|
||||
|
||||
protected $original_del_text;
|
||||
|
||||
/** @var WPML_Translation_Job_Factory $job_factory */
|
||||
protected $job_factory;
|
||||
|
||||
private $original_doc_id = false;
|
||||
private $translation_id = false;
|
||||
|
||||
/**
|
||||
* @param int $job_id
|
||||
* @param null|int $batch_id
|
||||
* @param null|TranslationManagement $tm_instance
|
||||
* @param null|WPML_Translation_Job_Factory $job_factory
|
||||
*/
|
||||
function __construct( $job_id, $batch_id = null, &$tm_instance = null, $job_factory = null ) {
|
||||
parent::__construct( $job_id, $batch_id, $tm_instance );
|
||||
$this->original_del_text = __( 'The original has been deleted!', 'sitepress' );
|
||||
$this->job_factory = $job_factory ?: wpml_tm_load_job_factory();
|
||||
}
|
||||
|
||||
function get_type() {
|
||||
return 'Post';
|
||||
}
|
||||
|
||||
function to_array() {
|
||||
$this->maybe_load_basic_data();
|
||||
$data_array = $this->basic_data_to_array( $this->basic_data );
|
||||
$data_array['id'] = Obj::prop('job_id', $this->basic_data);
|
||||
$data_array['translation_id'] = Obj::prop('translation_id', $this->basic_data);
|
||||
$data_array['status'] = $this->get_status();
|
||||
$data_array['translation_edit_url'] = $this->get_url();
|
||||
$data_array['original_url'] = $this->get_url( true );
|
||||
$data_array['post_title'] = esc_html( $this->get_title() );
|
||||
|
||||
return $data_array;
|
||||
}
|
||||
|
||||
function to_xliff_file() {
|
||||
$xliff = new WPML_TM_Xliff_Writer( $this->job_factory );
|
||||
|
||||
return $xliff->get_job_xliff_file( $this->get_id() );
|
||||
}
|
||||
|
||||
function get_original_element_id() {
|
||||
if ( ! $this->original_doc_id ) {
|
||||
$this->original_doc_id = $this->get_iclt_field( 'element_id', false );
|
||||
}
|
||||
|
||||
return $this->original_doc_id;
|
||||
}
|
||||
|
||||
function get_translation_id() {
|
||||
if ( ! $this->translation_id ) {
|
||||
$translation_id = $this->get_iclt_field( 'translation_id', true );
|
||||
$this->translation_id = $translation_id;
|
||||
} else {
|
||||
$translation_id = $this->translation_id;
|
||||
}
|
||||
|
||||
return $translation_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the job data in this object to the database (e.g. to a post)
|
||||
*
|
||||
* @param bool $complete whether or not to set the status
|
||||
* of the target element to complete
|
||||
*/
|
||||
public function save_to_element( $complete = false ) {
|
||||
global $wpdb, $wpml_post_translations, $wpml_term_translations;
|
||||
|
||||
$wpml_tm_records = new WPML_TM_Records( $wpdb, $wpml_post_translations, $wpml_term_translations );
|
||||
$save_data_action = new WPML_Save_Translation_Data_Action(
|
||||
array(
|
||||
'job_id' => $this->get_id(),
|
||||
'complete' => $complete,
|
||||
'fields' => array(),
|
||||
),
|
||||
$wpml_tm_records
|
||||
);
|
||||
$save_data_action->save_translation();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
function estimate_word_count() {
|
||||
$fields = $this->get_original_fields();
|
||||
$combined_string = join( ' ', $fields );
|
||||
$calculator = new WPML_TM_Word_Calculator( new WPML_PHP_Functions() );
|
||||
return $calculator->count_words( $combined_string, $this->get_source_language_code() );
|
||||
}
|
||||
|
||||
function get_original_fields() {
|
||||
global $wpdb;
|
||||
|
||||
$fields = $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
"SELECT field_type, field_data, field_format
|
||||
FROM {$wpdb->prefix}icl_translate
|
||||
WHERE job_id = %d
|
||||
AND field_translate = 1",
|
||||
$this->get_id()
|
||||
)
|
||||
);
|
||||
|
||||
$res = array();
|
||||
foreach ( $fields as $field ) {
|
||||
$res[ $field->field_type ] = base64_decode( $field->field_data );
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function cancel() {
|
||||
global $wpdb;
|
||||
|
||||
$deleted = false;
|
||||
$rid_query = "SELECT rid FROM {$wpdb->prefix}icl_translate_job WHERE job_id=%d";
|
||||
$rid_prepare = $wpdb->prepare( $rid_query, array( $this->job_id ) );
|
||||
$rid = $wpdb->get_var( $rid_prepare );
|
||||
$translation_id_query = "SELECT translation_id FROM {$wpdb->prefix}icl_translation_status WHERE rid=%d";
|
||||
$translation_id_prepare = $wpdb->prepare( $translation_id_query, array( $rid ) );
|
||||
$translation_id = $wpdb->get_var( $translation_id_prepare );
|
||||
if ( $rid ) {
|
||||
$wpdb->delete( $wpdb->prefix . 'icl_translate_job', array( 'job_id' => $this->job_id ) );
|
||||
$wpdb->delete( $wpdb->prefix . 'icl_translate', array( 'job_id' => $this->job_id ) );
|
||||
$deleted = true;
|
||||
}
|
||||
|
||||
if ( $translation_id ) {
|
||||
$wpdb->delete( $wpdb->prefix . 'icl_translations', array( 'translation_id' => $translation_id ) );
|
||||
if ( $rid ) {
|
||||
$wpdb->delete(
|
||||
$wpdb->prefix . 'icl_translation_status',
|
||||
array(
|
||||
'translation_id' => $translation_id,
|
||||
'rid' => $rid,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TranslationProxy_Project $project
|
||||
* @param int $translator_id
|
||||
* @param WPML_TM_CMS_ID $cms_id_helper
|
||||
* @param TranslationManagement $tm_instance
|
||||
* @param null|string $note
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function send_to_tp( $project, $translator_id, &$cms_id_helper, &$tm_instance, $note = null ) {
|
||||
global $wpdb;
|
||||
|
||||
$this->maybe_load_basic_data();
|
||||
|
||||
$file = $this->to_xliff_file();
|
||||
$title = $this->get_title();
|
||||
$cms_id = $cms_id_helper->cms_id_from_job_id( $this->get_id() );
|
||||
$url = $this->get_url( true );
|
||||
$word_count = $this->estimate_word_count();
|
||||
$note = isset( $note ) ? $note : '';
|
||||
$source_language = $this->get_source_language_code();
|
||||
$target_language = $this->get_language_code();
|
||||
$uuid = $this->get_uuid();
|
||||
|
||||
try {
|
||||
$tp_job_id = $project->send_to_translation_batch_mode( $file, $title, $cms_id, $url, $source_language, $target_language, $word_count, $translator_id, $note, $uuid );
|
||||
} catch ( Exception $err ) {
|
||||
// The translation entry will be removed
|
||||
$project->errors[] = $err;
|
||||
$tp_job_id = 0;
|
||||
}
|
||||
|
||||
$translation_id = $this->get_translation_id();
|
||||
|
||||
if ( $tp_job_id ) {
|
||||
$tm_instance->update_translation_status(
|
||||
array(
|
||||
'translation_id' => $translation_id,
|
||||
'translator_id' => $translator_id,
|
||||
'status' => ICL_TM_IN_PROGRESS,
|
||||
'needs_update' => 0,
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$previous_state = $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
" SELECT _prevstate
|
||||
FROM {$wpdb->prefix}icl_translation_status
|
||||
WHERE translation_id=%d
|
||||
LIMIT 1",
|
||||
$translation_id
|
||||
)
|
||||
);
|
||||
if ( ! empty( $previous_state ) ) {
|
||||
$previous_state = unserialize( $previous_state );
|
||||
$data = array(
|
||||
'status' => $previous_state['status'],
|
||||
'translator_id' => $previous_state['translator_id'],
|
||||
'needs_update' => $previous_state['needs_update'],
|
||||
'md5' => $previous_state['md5'],
|
||||
'translation_service' => $previous_state['translation_service'],
|
||||
'translation_package' => $previous_state['translation_package'],
|
||||
'timestamp' => $previous_state['timestamp'],
|
||||
'links_fixed' => $previous_state['links_fixed'],
|
||||
);
|
||||
$data_where = array( 'translation_id' => $translation_id );
|
||||
$wpdb->update( $wpdb->prefix . 'icl_translation_status', $data, $data_where );
|
||||
} else {
|
||||
$data = array(
|
||||
'status' => ICL_TM_NOT_TRANSLATED,
|
||||
'needs_update' => 0,
|
||||
);
|
||||
$data_where = array( 'translation_id' => $translation_id );
|
||||
$wpdb->update( $wpdb->prefix . 'icl_translation_status', $data, $data_where );
|
||||
}
|
||||
$err = true;
|
||||
}
|
||||
|
||||
return array( isset( $err ) ? $err : false, $project, $tp_job_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool|false $original
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract function get_url( $original = false );
|
||||
|
||||
/**
|
||||
* @return WP_Post|WPML_Package|mixed
|
||||
*/
|
||||
abstract function get_original_document();
|
||||
|
||||
protected function load_status() {
|
||||
$this->maybe_load_basic_data();
|
||||
|
||||
$status = ! empty( $this->basic_data->translated ) ? ICL_TM_COMPLETE : Obj::prop('status', $this->basic_data);
|
||||
|
||||
return TranslationManagement::get_job_status_string( $status, Obj::prop( 'needs_update', $this->basic_data ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $job_id
|
||||
*
|
||||
* @return bool|stdClass|WPML_Element_Translation_Job
|
||||
*/
|
||||
protected function load_job_data( $job_id ) {
|
||||
if ( $this->job_factory ) {
|
||||
return $this->job_factory->get_translation_job( $job_id, false, 1 );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function save_updated_assignment() {
|
||||
global $wpdb;
|
||||
|
||||
$job_id = $this->get_id();
|
||||
$service = $this->get_translation_service();
|
||||
list( $prev_translator_id, $rid ) = $wpdb->get_row( $wpdb->prepare( "SELECT translator_id, rid FROM {$wpdb->prefix}icl_translate_job WHERE job_id=%d", $job_id ), ARRAY_N );
|
||||
|
||||
$translator_id = $this->get_translator_id();
|
||||
$assigned_correctly = $translator_id == $prev_translator_id;
|
||||
$assigned_correctly = apply_filters( 'wpml_job_assigned_to_after_assignment', $assigned_correctly, $job_id, $translator_id, $service );
|
||||
|
||||
if ( $assigned_correctly ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'translator_id' => $translator_id,
|
||||
'status' => ICL_TM_WAITING_FOR_TRANSLATOR,
|
||||
'translation_service' => $service,
|
||||
);
|
||||
$data_where = array( 'rid' => $rid );
|
||||
$wpdb->update( $wpdb->prefix . 'icl_translation_status', $data, $data_where );
|
||||
$wpdb->update( $wpdb->prefix . 'icl_translate_job', array( 'translator_id' => $translator_id ), array( 'job_id' => $job_id ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the batch ID for job elements using the
|
||||
* `icl_translation_status` and `icl_translate_job` tables
|
||||
*/
|
||||
protected function load_batch_id() {
|
||||
global $wpdb;
|
||||
|
||||
$this->batch_id = $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
"SELECT batch_id
|
||||
FROM {$wpdb->prefix}icl_translation_status as ts
|
||||
LEFT JOIN {$wpdb->prefix}icl_translate_job as tj ON tj.rid = ts.rid
|
||||
WHERE tj.job_id = %d AND tj.revision IS NULL
|
||||
LIMIT 1",
|
||||
$this->job_id
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private function get_iclt_field( $field_name, $translation ) {
|
||||
global $wpdb;
|
||||
|
||||
$column_name = ( $translation === true ? 'i' : 'o' ) . '.' . $field_name;
|
||||
|
||||
$query = " SELECT {$column_name}
|
||||
FROM {$wpdb->prefix}icl_translations o
|
||||
JOIN {$wpdb->prefix}icl_translations i
|
||||
ON i.trid = o.trid
|
||||
AND i.source_language_code = o.language_code
|
||||
JOIN {$wpdb->prefix}icl_translation_status s
|
||||
ON s.translation_id = i.translation_id
|
||||
JOIN {$wpdb->prefix}icl_translate_job j
|
||||
ON j.rid = s.rid
|
||||
WHERE j.job_id = %d
|
||||
LIMIT 1";
|
||||
$args = array( $this->get_id() );
|
||||
$prepared_query = $wpdb->prepare( $query, $args );
|
||||
return $wpdb->get_var( $prepared_query );
|
||||
}
|
||||
|
||||
/**
|
||||
* If the job does not have deadline date,
|
||||
* we consider that the job was completed on time.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_completed_on_time() {
|
||||
return $this->get_number_of_days_overdue() <= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return false|int Negative integer if the job was completed before the deadline, or positive either.
|
||||
* False is the job has no deadline date
|
||||
*/
|
||||
public function get_number_of_days_overdue() {
|
||||
$deadline = $this->get_deadline_date();
|
||||
$completed = $this->get_completed_date();
|
||||
|
||||
if ( ! $deadline ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! $completed ) {
|
||||
$completed = strtotime( 'now' );
|
||||
} else {
|
||||
$completed = strtotime( $completed );
|
||||
}
|
||||
|
||||
$deadline = strtotime( $deadline );
|
||||
|
||||
return (int) floor( ( $completed - $deadline ) / DAY_IN_SECONDS );
|
||||
}
|
||||
|
||||
/** @return string|null */
|
||||
public function get_deadline_date() {
|
||||
return $this->get_basic_data_property( 'deadline_date' );
|
||||
}
|
||||
|
||||
/** @return string|null */
|
||||
public function get_completed_date() {
|
||||
return $this->get_basic_data_property( 'completed_date' );
|
||||
}
|
||||
|
||||
/** @return string|null */
|
||||
public function get_manager_id() {
|
||||
return $this->get_basic_data_property( 'manager_id' );
|
||||
}
|
||||
|
||||
/** @return string|null */
|
||||
protected function get_title_from_db() {
|
||||
return $this->get_basic_data_property( 'title' );
|
||||
}
|
||||
|
||||
/** @return string|null */
|
||||
protected function get_uuid() {
|
||||
return $this->get_basic_data_property( 'uuid' );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
require_once WPML_TM_PATH . '/inc/translation-jobs/jobs/wpml-translation-job.class.php';
|
||||
|
||||
class WPML_External_Translation_Job extends WPML_Element_Translation_Job {
|
||||
|
||||
function get_original_document() {
|
||||
|
||||
return apply_filters(
|
||||
'wpml_get_translatable_item',
|
||||
null,
|
||||
$this->get_original_element_id(),
|
||||
isset( $this->basic_data->original_post_type ) ? $this->basic_data->original_post_type : null
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool|false $original
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_url( $original = false ) {
|
||||
|
||||
$url = null;
|
||||
$element_id = null;
|
||||
|
||||
if ( $original ) {
|
||||
$element_id = $this->get_original_element_id();
|
||||
$url = apply_filters( 'wpml_external_item_url', '', $element_id );
|
||||
}
|
||||
|
||||
return apply_filters( 'wpml_element_translation_job_url', $url, $original, $element_id, $this->get_original_document() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_title() {
|
||||
$title = $this->get_title_from_db();
|
||||
|
||||
if ( $title ) {
|
||||
return $title;
|
||||
}
|
||||
|
||||
$original_element = $this->get_original_document();
|
||||
|
||||
return $original_element
|
||||
? apply_filters( 'wpml_tm_external_translation_job_title', $this->title_from_job_fields(), $original_element->ID )
|
||||
: $this->original_del_text;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_type_title() {
|
||||
$original_element = $this->get_original_document();
|
||||
return $original_element->kind;
|
||||
}
|
||||
|
||||
protected function load_resultant_element_id() {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function title_from_job_fields() {
|
||||
global $wpdb;
|
||||
|
||||
$title_and_name = $wpdb->get_row(
|
||||
$wpdb->prepare(
|
||||
"
|
||||
SELECT n.field_data AS name, t.field_data AS title
|
||||
FROM {$wpdb->prefix}icl_translate AS n
|
||||
JOIN {$wpdb->prefix}icl_translate AS t
|
||||
ON n.job_id = t.job_id
|
||||
WHERE n.job_id = %d
|
||||
AND n.field_type = 'name'
|
||||
AND t.field_type = 'title'
|
||||
LIMIT 1
|
||||
",
|
||||
$this->get_id()
|
||||
)
|
||||
);
|
||||
|
||||
return $title_and_name !== null ? ( $title_and_name->name ?
|
||||
base64_decode( $title_and_name->name )
|
||||
: base64_decode( $title_and_name->title ) ) : '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
<?php
|
||||
|
||||
use WPML\FP\Obj;
|
||||
use WPML\TM\Jobs\FieldId;
|
||||
use WPML\TM\Jobs\TermMeta;
|
||||
use WPML\FP\Lst;
|
||||
|
||||
require_once WPML_TM_PATH . '/inc/translation-jobs/jobs/wpml-translation-job.class.php';
|
||||
|
||||
class WPML_Post_Translation_Job extends WPML_Element_Translation_Job {
|
||||
|
||||
function get_original_document() {
|
||||
|
||||
return get_post( $this->get_original_element_id() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool|false $original
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_url( $original = false ) {
|
||||
$url = null;
|
||||
$element_id = null;
|
||||
|
||||
if ( $original ) {
|
||||
$element_id = $this->get_original_element_id();
|
||||
$url = get_permalink( $element_id );
|
||||
} else {
|
||||
$element_id = $this->get_resultant_element_id();
|
||||
$url = get_edit_post_link( $element_id );
|
||||
}
|
||||
|
||||
return apply_filters( 'wpml_element_translation_job_url', $url, $original, $element_id, $this->get_original_document() );
|
||||
}
|
||||
|
||||
/**
|
||||
* It checks that the post type is translatable.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function is_translatable_post_type() {
|
||||
$post_type = $this->get_post_type();
|
||||
|
||||
if ( $post_type ) {
|
||||
/** @var SitePress $sitepress */
|
||||
global $sitepress;
|
||||
if ( $sitepress ) {
|
||||
$post_types = array_keys( $sitepress->get_translatable_documents() );
|
||||
|
||||
return in_array( $post_type, $post_types, true );
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function update_fields_from_post() {
|
||||
global $iclTranslationManagement, $wpdb;
|
||||
|
||||
$job_id = $this->get_id();
|
||||
$post_id = $this->get_resultant_element_id();
|
||||
$data['complete'] = 1;
|
||||
$data['job_id'] = $job_id;
|
||||
$job = wpml_tm_load_job_factory()->get_translation_job( $job_id, 1 );
|
||||
$term_names = $this->get_term_field_array_for_post();
|
||||
$post = get_post( $post_id );
|
||||
if ( is_object( $job ) && is_array( $job->elements ) && is_object( $post ) ) {
|
||||
foreach ( $job->elements as $element ) {
|
||||
$field_data = '';
|
||||
switch ( $element->field_type ) {
|
||||
case 'title':
|
||||
$field_data = $this->encode_field_data( $post->post_title);
|
||||
break;
|
||||
case 'body':
|
||||
$field_data = $this->encode_field_data( $post->post_content);
|
||||
break;
|
||||
case 'excerpt':
|
||||
$field_data = $this->encode_field_data( $post->post_excerpt);
|
||||
break;
|
||||
case 'URL':
|
||||
$field_data = $this->encode_field_data( $post->post_name);
|
||||
break;
|
||||
default:
|
||||
if ( isset( $term_names[ $element->field_type ] ) ) {
|
||||
$field_data = $this->encode_field_data( $term_names[ $element->field_type ]);
|
||||
}
|
||||
}
|
||||
if ( $field_data ) {
|
||||
$wpdb->update( $wpdb->prefix . 'icl_translate',
|
||||
array(
|
||||
'field_data_translated' => $field_data,
|
||||
'field_finished' => 1
|
||||
),
|
||||
array( 'tid' => $element->tid )
|
||||
);
|
||||
}
|
||||
}
|
||||
$iclTranslationManagement->mark_job_done( $job_id );
|
||||
}
|
||||
}
|
||||
|
||||
function save_terms_to_post() {
|
||||
/** @var SitePress $sitepress */
|
||||
global $sitepress, $wpdb;
|
||||
|
||||
$lang_code = $this->get_language_code();
|
||||
|
||||
if ( $sitepress->get_setting( 'tm_block_retranslating_terms' ) ) {
|
||||
$this->load_terms_from_post_into_job( true );
|
||||
}
|
||||
$terms = $this->get_terms_in_job_rows();
|
||||
foreach ( $terms as $term ) {
|
||||
$new_term_action = new WPML_Update_Term_Action( $wpdb, $sitepress, [
|
||||
'term' => base64_decode( $term->field_data_translated ),
|
||||
'description' => TermMeta::getTermDescription( $this->get_id(), $term->term_taxonomy_id ),
|
||||
'lang_code' => $lang_code,
|
||||
'trid' => $term->trid,
|
||||
'taxonomy' => $term->taxonomy
|
||||
] );
|
||||
$new_term = $new_term_action->execute();
|
||||
|
||||
foreach ( TermMeta::getTermMeta( $this->get_id(), $term->term_taxonomy_id ) as $meta ) {
|
||||
update_term_meta( $new_term['term_taxonomy_id'], FieldId::getTermMetaKey( $meta->field_type ), $meta->field_data_translated );
|
||||
}
|
||||
}
|
||||
|
||||
$term_helper = wpml_get_term_translation_util();
|
||||
$term_helper->sync_terms( $this->get_original_element_id(), $this->get_language_code() );
|
||||
}
|
||||
|
||||
function load_terms_from_post_into_job( $delete = null ) {
|
||||
global $sitepress;
|
||||
|
||||
$delete = isset( $delete ) ? $delete : $sitepress->get_setting( 'tm_block_retranslating_terms' );
|
||||
$this->set_translated_term_values( $delete );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_title() {
|
||||
$title = $this->get_title_from_db();
|
||||
|
||||
if ( $title ) {
|
||||
return $title;
|
||||
}
|
||||
|
||||
$original_post = $this->get_original_document();
|
||||
|
||||
return is_object( $original_post ) && isset( $original_post->post_title )
|
||||
? $original_post->post_title : $this->original_del_text;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_type_title() {
|
||||
$post_type = get_post_type_object( $this->get_post_type() );
|
||||
|
||||
return $post_type->labels->singular_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_post_type() {
|
||||
$original_post = $this->get_original_document();
|
||||
|
||||
return $original_post->post_type;
|
||||
}
|
||||
|
||||
protected function load_resultant_element_id() {
|
||||
global $wpdb;
|
||||
$this->maybe_load_basic_data();
|
||||
|
||||
return $wpdb->get_var( $wpdb->prepare( "SELECT element_id
|
||||
FROM {$wpdb->prefix}icl_translations
|
||||
WHERE translation_id = %d
|
||||
LIMIT 1",
|
||||
$this->basic_data->translation_id ) );
|
||||
}
|
||||
|
||||
protected function get_terms_in_job_rows(){
|
||||
global $wpdb;
|
||||
|
||||
$query_for_terms_in_job = $wpdb->prepare(" SELECT
|
||||
tt.taxonomy,
|
||||
tt.term_taxonomy_id,
|
||||
iclt.trid,
|
||||
j.field_data_translated
|
||||
FROM {$wpdb->term_taxonomy} tt
|
||||
JOIN {$wpdb->prefix}icl_translations iclt
|
||||
ON iclt.element_id = tt.term_taxonomy_id
|
||||
AND CONCAT('tax_', tt.taxonomy) = iclt.element_type
|
||||
JOIN {$wpdb->prefix}icl_translate j
|
||||
ON j.field_type = CONCAT('t_', tt.term_taxonomy_id)
|
||||
WHERE j.job_id = %d ", $this->get_id());
|
||||
|
||||
return $wpdb->get_results( $query_for_terms_in_job );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves an array of all terms associated with a post. This array is indexed by indexes of the for {t_}{term_taxonomy_id}.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_term_field_array_for_post() {
|
||||
global $wpdb;
|
||||
|
||||
$post_id = $this->get_resultant_element_id();
|
||||
$query = $wpdb->prepare( "SELECT o.term_taxonomy_id, t.name
|
||||
FROM {$wpdb->term_relationships} o
|
||||
JOIN {$wpdb->term_taxonomy} tt ON tt.term_taxonomy_id = o.term_taxonomy_id
|
||||
JOIN {$wpdb->terms} t ON t.term_id = tt.term_id
|
||||
WHERE o.object_id = %d",
|
||||
$post_id );
|
||||
$res = $wpdb->get_results( $query );
|
||||
|
||||
$result = array();
|
||||
|
||||
foreach ( $res as $term ) {
|
||||
$result[ 't_' . $term->term_taxonomy_id ] = $term->name;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
protected function set_translated_term_values( $delete ) {
|
||||
global $wpdb;
|
||||
$translations_table = $wpdb->prefix . 'icl_translations';
|
||||
$translate_table = $wpdb->prefix . 'icl_translate';
|
||||
|
||||
$job_id = $this->get_id();
|
||||
$get_target_terms_for_job_query = $wpdb->prepare("
|
||||
SELECT
|
||||
{$wpdb->terms}.name,
|
||||
{$wpdb->term_taxonomy}.description,
|
||||
SUBSTR(translate.field_type, 3) original_term_id,
|
||||
{$wpdb->terms}.term_id translated_term_id
|
||||
FROM {$translate_table} translate
|
||||
INNER JOIN {$translations_table} original_translation ON original_translation.element_id = SUBSTR(translate.field_type, 3)
|
||||
INNER JOIN {$translations_table} translation ON translation.trid = original_translation.trid AND translation.language_code = %s
|
||||
INNER JOIN {$wpdb->term_taxonomy} ON {$wpdb->term_taxonomy}.term_taxonomy_id = translation.element_id AND CONCAT('tax_', {$wpdb->term_taxonomy}.taxonomy) = translation.element_type
|
||||
INNER JOIN {$wpdb->terms} ON {$wpdb->terms}.term_id = {$wpdb->term_taxonomy}.term_id
|
||||
WHERE translate.job_id = %d AND translate.field_type LIKE 't\_%'
|
||||
", $this->get_language_code(), $job_id );
|
||||
|
||||
$term_values = $wpdb->get_results( $get_target_terms_for_job_query );
|
||||
foreach ( $term_values as $term ) {
|
||||
if ( $delete ) {
|
||||
$conditions = [
|
||||
"field_type LIKE 'tfield-%-{$term->original_term_id}'", // Term fields
|
||||
"field_type LIKE 'tfield-%-{$term->original_term_id}\_%'", // Term fields as array
|
||||
"field_type = 't_{$term->original_term_id}'",
|
||||
"field_type = 'tdesc_{$term->original_term_id}'",
|
||||
];
|
||||
$wpdb->query(
|
||||
"DELETE FROM {$translate_table} WHERE job_id = $job_id AND "
|
||||
. "(" . Lst::join( ' OR ', $conditions ) . ")"
|
||||
);
|
||||
} else {
|
||||
$wpdb->update(
|
||||
$translate_table,
|
||||
[ 'field_data_translated' => base64_encode( $term->name ), 'field_finished' => 1 ],
|
||||
[ 'field_type' => 't_' . $term->original_term_id, 'job_id' => $job_id ]
|
||||
);
|
||||
$wpdb->update(
|
||||
$translate_table,
|
||||
[ 'field_data_translated' => base64_encode( $term->description ), 'field_finished' => 1 ],
|
||||
[ 'field_type' => 'tdesc_' . $term->original_term_id, 'job_id' => $job_id ]
|
||||
);
|
||||
|
||||
$meta_values = $wpdb->get_results( "SELECT meta_key, meta_value FROM {$wpdb->termmeta} WHERE term_id = {$term->translated_term_id}" );
|
||||
foreach ( $meta_values as $meta ) {
|
||||
$wpdb->update(
|
||||
$translate_table,
|
||||
[ 'field_finished' => 1, 'field_data_translated' => base64_encode( $meta->meta_value ) ],
|
||||
[ 'job_id' => $job_id, 'field_type' => 'tfield-' . $meta->meta_key . '-' . $term->original_term_id ]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $args
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function filter_is_translator_args( array $args ) {
|
||||
return Obj::assoc( 'post_id', $this->get_original_element_id(), $args );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
require_once WPML_TM_PATH . '/inc/translation-jobs/jobs/wpml-translation-job.class.php';
|
||||
|
||||
class WPML_String_Translation_Job extends WPML_Translation_Job {
|
||||
|
||||
protected function load_job_data( $string_translation_id ) {
|
||||
global $wpdb;
|
||||
|
||||
$query = $wpdb->prepare(
|
||||
"SELECT st.id,
|
||||
s.language AS source_language_code,
|
||||
st.language AS language_code,
|
||||
IF(cs.status IS NULL, st.status, cs.status) as status,
|
||||
st.string_id,
|
||||
s.name,
|
||||
s.value,
|
||||
tb.id AS batch_id,
|
||||
st.translation_service,
|
||||
st.translator_id,
|
||||
u.display_name as translator_name,
|
||||
COUNT( st.id ) as strings_count
|
||||
FROM {$wpdb->prefix}icl_string_translations AS st
|
||||
INNER JOIN {$wpdb->prefix}icl_strings AS s
|
||||
ON st.string_id = s.id
|
||||
INNER JOIN {$wpdb->prefix}icl_translation_batches AS tb
|
||||
ON tb.id = st.batch_id
|
||||
LEFT JOIN {$wpdb->users} u
|
||||
ON st.translator_id = u.ID
|
||||
LEFT JOIN {$wpdb->prefix}icl_string_status ss ON ss.string_translation_id = st.id
|
||||
LEFT JOIN {$wpdb->prefix}icl_core_status cs ON cs.rid = ss.rid
|
||||
WHERE st.id = %d
|
||||
LIMIT 1",
|
||||
$string_translation_id
|
||||
);
|
||||
|
||||
return $wpdb->get_row( $query );
|
||||
}
|
||||
|
||||
public function get_title() {
|
||||
$this->maybe_load_basic_data();
|
||||
|
||||
return esc_html( $this->basic_data->value );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_id() {
|
||||
|
||||
return 'string|' . parent::get_id();
|
||||
}
|
||||
|
||||
public function get_type() {
|
||||
return 'String';
|
||||
}
|
||||
|
||||
public function get_original_element_id() {
|
||||
if ( ! $this->basic_data ) {
|
||||
$this->maybe_load_basic_data();
|
||||
}
|
||||
|
||||
return $this->basic_data->string_id;
|
||||
}
|
||||
|
||||
public function cancel() {
|
||||
global $WPML_String_Translation, $wpdb;
|
||||
/** @var WPML_String_Translation $WPML_String_Translation */
|
||||
if ( $WPML_String_Translation ) {
|
||||
$rid = $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
"SELECT rid
|
||||
FROM {$wpdb->prefix}icl_string_status
|
||||
WHERE string_translation_id = %d
|
||||
LIMIT 1",
|
||||
$this->job_id
|
||||
)
|
||||
);
|
||||
if ( $rid ) {
|
||||
$WPML_String_Translation->cancel_remote_translation( $rid );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function load_status() {
|
||||
$this->maybe_load_basic_data();
|
||||
$this->status = WPML_Remote_String_Translation::get_string_status_label( $this->basic_data->status );
|
||||
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
public function to_array() {
|
||||
$this->maybe_load_basic_data();
|
||||
$this->basic_data->value = $this->get_title();
|
||||
$data_array = $this->basic_data_to_array( $this->basic_data );
|
||||
$data_array['job_id'] = 'string|' . $this->job_id;
|
||||
$data_array['translation_id'] = $this->basic_data->id;
|
||||
$data_array['status'] = $this->get_status();
|
||||
$data_array['id'] = $this->get_id();
|
||||
|
||||
return $data_array;
|
||||
}
|
||||
|
||||
protected function load_resultant_element_id() {
|
||||
global $wpdb;
|
||||
|
||||
return $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
"SELECT id FROM {$wpdb->prefix}icl_string_translations
|
||||
WHERE string_id = %d AND language = %s",
|
||||
$this->get_original_element_id(),
|
||||
$this->get_language_code()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
protected function save_updated_assignment() {
|
||||
global $wpdb;
|
||||
|
||||
return $wpdb->update(
|
||||
$wpdb->prefix . 'icl_string_translations',
|
||||
array(
|
||||
'translator_id' => $this->get_translator_id(),
|
||||
'translation_service' => $this->get_translation_service(),
|
||||
),
|
||||
array(
|
||||
'string_id' => $this->get_original_element_id(),
|
||||
'language' => $this->get_language_code(),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the batch ID for a string job
|
||||
*/
|
||||
protected function load_batch_id() {
|
||||
global $wpdb;
|
||||
|
||||
$this->batch_id = $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
"SELECT batch_id
|
||||
FROM {$wpdb->prefix}icl_string_translations
|
||||
WHERE id = %d
|
||||
LIMIT 1",
|
||||
$this->job_id
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,431 @@
|
||||
<?php
|
||||
|
||||
use WPML\FP\Obj;
|
||||
|
||||
abstract class WPML_Translation_Job extends WPML_Translation_Job_Helper {
|
||||
protected $basic_data;
|
||||
protected $element_id = - 1;
|
||||
protected $status = - 1;
|
||||
protected $job_id;
|
||||
protected $batch_id;
|
||||
|
||||
/** @var WPML_TM_Blog_Translators $blog_translators */
|
||||
protected $blog_translators;
|
||||
|
||||
/**
|
||||
* @param int $job_id
|
||||
* @param int|null $batch_id
|
||||
* @param WPML_TM_Blog_Translators $blog_translators
|
||||
*/
|
||||
function __construct( $job_id, $batch_id = null, &$blog_translators = null ) {
|
||||
$this->job_id = $job_id;
|
||||
$batch_id = $batch_id ? $batch_id : $this->get_batch_id();
|
||||
$this->batch_id = $batch_id ? $batch_id : TranslationProxy_Batch::update_translation_batch();
|
||||
$this->blog_translators = $blog_translators ? $blog_translators : wpml_tm_load_blog_translators();
|
||||
}
|
||||
|
||||
abstract public function cancel();
|
||||
|
||||
abstract public function get_original_element_id();
|
||||
|
||||
abstract public function to_array();
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
abstract function get_title();
|
||||
|
||||
public function get_status() {
|
||||
if ( $this->status == - 1 ) {
|
||||
$this->status = $this->load_status();
|
||||
}
|
||||
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
public function get_status_value() {
|
||||
$this->maybe_load_basic_data();
|
||||
|
||||
return $this->basic_data->status;
|
||||
}
|
||||
|
||||
public function get_review_status() {
|
||||
$this->maybe_load_basic_data();
|
||||
|
||||
return $this->basic_data->review_status;
|
||||
}
|
||||
|
||||
public function get_id() {
|
||||
return $this->job_id;
|
||||
}
|
||||
|
||||
public function get_resultant_element_id( $force = false ) {
|
||||
if ( $this->element_id == - 1 || $force === true ) {
|
||||
$this->element_id = $this->load_resultant_element_id();
|
||||
}
|
||||
|
||||
return $this->element_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the input user is allowed to edit this job
|
||||
*
|
||||
* @param WP_User $user
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function user_can_translate( $user ) {
|
||||
$translator_id = $this->get_translator_id();
|
||||
$user_can_take_this_job = 0 === $translator_id
|
||||
|| $this->is_current_user_allowed_to_translate(
|
||||
$user,
|
||||
$translator_id
|
||||
);
|
||||
|
||||
$translator_has_job_language_pairs = $this->blog_translators->is_translator(
|
||||
$user->ID,
|
||||
$this->filter_is_translator_args( [
|
||||
'lang_from' => $this->get_source_language_code(),
|
||||
'lang_to' => $this->get_language_code(),
|
||||
] )
|
||||
);
|
||||
|
||||
$user_can_translate = ( $user_can_take_this_job && $translator_has_job_language_pairs )
|
||||
|| user_can( $user, 'manage_options' );
|
||||
return apply_filters( 'wpml_user_can_translate', $user_can_translate, $user );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $args
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function filter_is_translator_args( array $args ) {
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_User $user
|
||||
* @param int $translator_id
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_current_user_allowed_to_translate( WP_User $user, $translator_id ) {
|
||||
$allowed_translators = apply_filters( 'wpml_tm_allowed_translators_for_job', array(), $this );
|
||||
$allowed_translators[] = $translator_id;
|
||||
|
||||
return in_array( (int) $user->ID, $allowed_translators, true );
|
||||
}
|
||||
|
||||
public function get_batch_id() {
|
||||
if ( ! isset( $this->batch_id ) ) {
|
||||
$this->load_batch_id();
|
||||
}
|
||||
|
||||
return $this->batch_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool|false $as_name if true will return the language's display name if applicable
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function get_language_code( $as_name = false ) {
|
||||
$this->maybe_load_basic_data();
|
||||
$code = isset( $this->basic_data->language_code ) ? $this->basic_data->language_code : false;
|
||||
|
||||
return $code && $as_name ? $this->lang_code_to_name( $code ) : $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool|false $as_name if true will return the language's display name if applicable
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
function get_source_language_code( $as_name = false ) {
|
||||
$this->maybe_load_basic_data();
|
||||
$code = isset( $this->basic_data->source_language_code ) ? $this->basic_data->source_language_code : false;
|
||||
|
||||
return $code && $as_name ? $this->lang_code_to_name( $code ) : $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|false
|
||||
*/
|
||||
public function get_translator_name() {
|
||||
$this->maybe_load_basic_data();
|
||||
if ( Obj::prop( 'translation_service', $this->basic_data ) == TranslationProxy::get_current_service_id() ) {
|
||||
$this->basic_data->translator_name = TranslationProxy_Translator::get_translator_name( Obj::prop('translator_id', $this->basic_data) );
|
||||
} else {
|
||||
$this->basic_data->translator_name = false;
|
||||
}
|
||||
|
||||
return $this->basic_data->translator_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of the assigned translator or 0 if no translator is assigned to the job
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_translator_id() {
|
||||
$this->maybe_load_basic_data();
|
||||
|
||||
$this->basic_data->translator_id = ! empty( $this->basic_data->translator_id )
|
||||
? $this->basic_data->translator_id : 0;
|
||||
|
||||
return (int) $this->basic_data->translator_id;
|
||||
}
|
||||
|
||||
public function get_basic_data() {
|
||||
$this->maybe_load_basic_data();
|
||||
|
||||
return $this->basic_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $translator_id
|
||||
* @param string $service
|
||||
*
|
||||
* @return bool true on success false on failure
|
||||
*/
|
||||
public function assign_to( $translator_id, $service = 'local' ) {
|
||||
$this->maybe_load_basic_data();
|
||||
$prev_translator_id = $this->get_translator_id();
|
||||
$prev_service = $this->get_translation_service();
|
||||
if ( $translator_id == $prev_translator_id && $service = $this->get_translation_service() ) {
|
||||
|
||||
return true;
|
||||
}
|
||||
$this->basic_data->translator_id = $translator_id;
|
||||
$this->basic_data->translation_service = $service;
|
||||
|
||||
if ( $this->save_updated_assignment() === false ) {
|
||||
$this->basic_data->translator_id = $prev_translator_id;
|
||||
$this->basic_data->translation_service = $prev_service;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$job_id = $this->get_id();
|
||||
if ( $this->get_tm_setting( array( 'notification', 'resigned' ) ) == ICL_TM_NOTIFICATION_IMMEDIATELY
|
||||
&& ! empty( $prev_translator_id )
|
||||
&& $prev_translator_id != $translator_id
|
||||
&& $job_id ) {
|
||||
do_action( 'wpml_tm_remove_job_notification', $prev_translator_id, $this );
|
||||
}
|
||||
|
||||
if ( $this->get_tm_setting( array( 'notification', 'new-job' ) ) == ICL_TM_NOTIFICATION_IMMEDIATELY ) {
|
||||
if ( empty( $translator_id ) ) {
|
||||
do_action( 'wpml_tm_new_job_notification', $this );
|
||||
} else {
|
||||
do_action( 'wpml_tm_assign_job_notification', $this, $translator_id );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns either the translation service id for the job or 'local' for local jobs
|
||||
*
|
||||
* @return int|string
|
||||
*/
|
||||
public function get_translation_service() {
|
||||
$this->maybe_load_basic_data();
|
||||
$this->basic_data->translation_service = ! empty( $this->basic_data->translation_service )
|
||||
? $this->basic_data->translation_service : 'local';
|
||||
|
||||
return $this->basic_data->translation_service;
|
||||
}
|
||||
|
||||
abstract protected function save_updated_assignment();
|
||||
|
||||
abstract protected function load_resultant_element_id();
|
||||
|
||||
abstract protected function load_status();
|
||||
|
||||
abstract protected function load_job_data( $id );
|
||||
|
||||
abstract function get_type();
|
||||
|
||||
protected function basic_data_to_array( $job_data ) {
|
||||
$this->maybe_load_basic_data();
|
||||
$data_array = (array) $job_data;
|
||||
if ( isset( $data_array['post_title'] ) ) {
|
||||
$data_array['post_title'] = esc_html( $data_array['post_title'] );
|
||||
}
|
||||
$data_array['translator_name'] = $this->get_translator_name();
|
||||
$data_array['batch_id'] = Obj::prop('batch_id', $job_data);
|
||||
$data_array['source_language_code'] = Obj::prop('source_language_code', $this->basic_data);
|
||||
$data_array['language_code'] = Obj::prop('language_code', $this->basic_data);
|
||||
$data_array['translator_html'] = $this->get_translator_html( $this->basic_data );
|
||||
$data_array['type'] = $this->get_type();
|
||||
$data_array['lang_text'] = $this->generate_lang_text();
|
||||
|
||||
return $data_array;
|
||||
}
|
||||
|
||||
protected function maybe_load_basic_data() {
|
||||
if ( ! $this->basic_data ) {
|
||||
$this->basic_data = $this->load_job_data( $this->job_id );
|
||||
$this->basic_data = $this->basic_data ? $this->basic_data : new stdClass();
|
||||
}
|
||||
}
|
||||
|
||||
private function get_inactive_translation_service( $translation_service_id ) {
|
||||
$cache_key = $translation_service_id;
|
||||
$cache_group = 'get_inactive_translation_service';
|
||||
$cache_found = false;
|
||||
|
||||
$service = wp_cache_get( $cache_key, $cache_group, false, $cache_found );
|
||||
|
||||
if ( ! $cache_found ) {
|
||||
try {
|
||||
$service = TranslationProxy_Service::get_service( $translation_service_id );
|
||||
} catch ( WPMLTranslationProxyApiException $ex ) {
|
||||
$service = false;
|
||||
}
|
||||
if ( ! $service ) {
|
||||
$service = new stdClass();
|
||||
$service->name = __( '(inactive and unknown service)', 'wpml-translation-management' );
|
||||
}
|
||||
wp_cache_set( $cache_key, $service, $cache_group );
|
||||
}
|
||||
|
||||
return $service;
|
||||
}
|
||||
|
||||
protected function get_translator_html( $job ) {
|
||||
|
||||
$job = (object) $job;
|
||||
$current_service_name = TranslationProxy::get_current_service_name();
|
||||
$translation_services = array( 'local', TranslationProxy::get_current_service_id() );
|
||||
|
||||
if ( isset( $job->translation_service ) && ! in_array( $job->translation_service, $translation_services ) ) {
|
||||
$inactive_service = $this->get_inactive_translation_service( $job->translation_service );
|
||||
$current_service_name = $inactive_service->name;
|
||||
}
|
||||
$translator = '';
|
||||
|
||||
if ( Obj::prop( 'translation_service', $job ) !== 'local' ) {
|
||||
try {
|
||||
$project = TranslationProxy::get_current_project();
|
||||
if ( $project ) {
|
||||
$translator .= $current_service_name;
|
||||
} else {
|
||||
$translator .= esc_html( $job->translator_name );
|
||||
}
|
||||
} catch ( Exception $e ) {
|
||||
// Just doesn't create the output
|
||||
}
|
||||
} elseif ( $job->status == ICL_TM_COMPLETE ) {
|
||||
$translator_data = get_userdata( $job->translator_id );
|
||||
$translator_name = $translator_data ? $translator_data->display_name : '';
|
||||
$translator = '<span class="icl-finished-local-name">' . $translator_name . '</span>';
|
||||
} else {
|
||||
$translator .= '<span class="icl_tj_select_translator">';
|
||||
$selected_translator = isset( $job->translator_id ) ? $job->translator_id : false;
|
||||
$disabled = false;
|
||||
if ( $job->translation_service
|
||||
&& $job->translation_service !== 'local'
|
||||
&& is_numeric( $job->translation_service ) ) {
|
||||
$selected_translator = TranslationProxy_Service::get_wpml_translator_id(
|
||||
$job->translation_service,
|
||||
$job->translator_id
|
||||
);
|
||||
$disabled = true;
|
||||
}
|
||||
|
||||
$job_id = isset( $job->job_id ) ? $job->job_id : $job->id;
|
||||
$local_only = isset( $job->local_only ) ? $job->local_only : true;
|
||||
$args = array(
|
||||
'id' => 'icl_tj_translator_for_' . $job_id,
|
||||
'name' => 'icl_tj_translator_for_' . ( $job_id ),
|
||||
'from' => $job->source_language_code,
|
||||
'to' => $job->language_code,
|
||||
'selected' => $selected_translator,
|
||||
'services' => $translation_services,
|
||||
'disabled' => $disabled,
|
||||
'echo' => false,
|
||||
'local_only' => $local_only,
|
||||
);
|
||||
|
||||
$translator .= wpml_tm_get_translators_dropdown()->render( $args );
|
||||
$translator .= '<input type="hidden" id="icl_tj_ov_'
|
||||
. $job_id
|
||||
. '" value="'
|
||||
. (int) $job->translator_id
|
||||
. '" />';
|
||||
$translator .= '<input type="hidden" id="icl_tj_ty_'
|
||||
. $job_id
|
||||
. '" value="'
|
||||
. strtolower( $this->get_type() )
|
||||
. '" />';
|
||||
$translator .= '<span class="icl_tj_select_translator_controls" id="icl_tj_tc_' . ( $job_id ) . '">';
|
||||
$translator .= '<input type="button" class="button-secondary icl_tj_ok" value="'
|
||||
. __(
|
||||
'Send',
|
||||
'wpml-translation-management'
|
||||
)
|
||||
. '" /> ';
|
||||
$translator .= '<input type="button" class="button-secondary icl_tj_cancel" value="'
|
||||
. __(
|
||||
'Cancel',
|
||||
'wpml-translation-management'
|
||||
)
|
||||
. '" />';
|
||||
$translator .= '</span>';
|
||||
}
|
||||
|
||||
return $translator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the batch ID associated to the job ID
|
||||
*/
|
||||
abstract protected function load_batch_id();
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
protected function generate_lang_text() {
|
||||
$this->maybe_load_basic_data();
|
||||
|
||||
return $this->lang_code_to_name( $this->get_source_language_code() )
|
||||
. html_entity_decode( ' » ' )
|
||||
. $this->lang_code_to_name( $this->get_language_code() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function lang_code_to_name( $code ) {
|
||||
global $sitepress;
|
||||
|
||||
$lang_details = $sitepress->get_language_details( $code );
|
||||
|
||||
return isset( $lang_details['display_name'] ) ? $lang_details['display_name'] : $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_basic_data_property( $name ) {
|
||||
$this->maybe_load_basic_data();
|
||||
|
||||
return Obj::prop( $name, $this->basic_data );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function set_basic_data_property( $name, $value ) {
|
||||
$this->basic_data = Obj::assoc( $name, $value, $this->basic_data );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
|
||||
class WPML_Translation_Batch extends WPML_Abstract_Job_Collection {
|
||||
|
||||
private $name = false;
|
||||
private $id = false;
|
||||
private $url = false;
|
||||
/** @var WPML_Translation_Job[] $job_objects */
|
||||
private $job_objects = array();
|
||||
|
||||
/**
|
||||
* @param wpdb $wpdb
|
||||
* @param int $batch_id
|
||||
*/
|
||||
public function __construct( &$wpdb, $batch_id = 0 ) {
|
||||
parent::__construct( $wpdb );
|
||||
$this->id = $batch_id > 0 ? $batch_id : $this->retrieve_generic_batch_id();
|
||||
$this->name = $batch_id <= 0 ? TranslationProxy_Batch::get_generic_batch_name() : false;
|
||||
}
|
||||
|
||||
public function reload() {
|
||||
global $wpdb;
|
||||
|
||||
list( $type_select, $post_join ) = $this->left_join_post();
|
||||
|
||||
$jobs = $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
" SELECT j.job_id,
|
||||
s.batch_id,
|
||||
{$type_select}
|
||||
FROM " . $this->get_table_join() . "
|
||||
{$post_join}
|
||||
WHERE s.batch_id = %d
|
||||
AND j.revision IS NULL",
|
||||
$this->id
|
||||
)
|
||||
);
|
||||
$jobs = $this->plain_objects_to_job_instances( $jobs );
|
||||
foreach ( $jobs as $job ) {
|
||||
$this->add_job( $job );
|
||||
}
|
||||
}
|
||||
|
||||
public function get_batch_url() {
|
||||
if ( $this->url === false ) {
|
||||
$this->url = TranslationManagement::get_batch_url( $this->id );
|
||||
}
|
||||
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
public function get_batch_meta_array() {
|
||||
$in_active_ts = $this->belongs_to_active_ts();
|
||||
$notifications = $this->ts_supports_notifications();
|
||||
$batch_id = $this->get_batch_tp_id();
|
||||
$batch_url = $this->get_batch_url();
|
||||
$batch_name = $batch_url ? $this->get_batch_name() : '';
|
||||
$item_count = $this->get_item_count();
|
||||
|
||||
return array(
|
||||
'in_active_ts' => $in_active_ts,
|
||||
'notifications' => $notifications,
|
||||
'batch_id' => $batch_id,
|
||||
'batch_url' => $batch_url,
|
||||
'batch_name' => $batch_name,
|
||||
'item_count' => $item_count,
|
||||
'last_update' => $this->get_last_update(),
|
||||
'status_array' => $this->get_status_array(),
|
||||
'display_from' => 1,
|
||||
'display_to' => $item_count,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels all translation jobs in this batch
|
||||
*/
|
||||
public function cancel_all_jobs() {
|
||||
/**
|
||||
* @var wpdb $wpdb
|
||||
* @var TranslationManagement $iclTranslationManagement
|
||||
* @var WPML_String_Translation $WPML_String_Translation
|
||||
*/
|
||||
global $wpdb, $iclTranslationManagement, $WPML_String_Translation;
|
||||
|
||||
$translation_ids = $wpdb->get_col(
|
||||
$wpdb->prepare(
|
||||
"SELECT translation_id
|
||||
FROM {$wpdb->prefix}icl_translation_status
|
||||
WHERE batch_id = %d",
|
||||
$this->id
|
||||
)
|
||||
);
|
||||
foreach ( $translation_ids as $translation_id ) {
|
||||
$iclTranslationManagement->cancel_translation_request( $translation_id );
|
||||
}
|
||||
|
||||
$string_translation_ids = $wpdb->get_col(
|
||||
$wpdb->prepare(
|
||||
"SELECT id FROM {$wpdb->prefix}icl_string_translations WHERE batch_id = %d",
|
||||
$this->id
|
||||
)
|
||||
);
|
||||
foreach ( $string_translation_ids as $st_trans_id ) {
|
||||
$rid = $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
"SELECT MAX(rid)
|
||||
FROM {$wpdb->prefix}icl_string_status
|
||||
WHERE string_translation_id = %d",
|
||||
$st_trans_id
|
||||
)
|
||||
);
|
||||
if ( $rid ) {
|
||||
$WPML_String_Translation->cancel_remote_translation( $rid );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// todo: [WPML 3.2.1] This method and other similar methods can likely be removed
|
||||
public function get_last_update() {
|
||||
return TranslationManagement::get_batch_last_update( $this->id );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WPML_Translation_Job $job
|
||||
*/
|
||||
public function add_job( $job ) {
|
||||
$this->job_objects[ $job->get_id() ] = $job;
|
||||
}
|
||||
|
||||
public function get_jobs_as_array() {
|
||||
$res = array();
|
||||
krsort( $this->job_objects );
|
||||
foreach ( $this->job_objects as $job ) {
|
||||
$res[] = $job->to_array();
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function get_item_count() {
|
||||
|
||||
return count( $this->job_objects );
|
||||
}
|
||||
|
||||
public function get_id() {
|
||||
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function get_batch_name() {
|
||||
if ( $this->name == false ) {
|
||||
$this->name = TranslationManagement::get_batch_name( $this->get_id() );
|
||||
}
|
||||
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function get_batch_tp_id() {
|
||||
return TranslationManagement::get_batch_tp_id( $this->id );
|
||||
}
|
||||
|
||||
public function get_status_array() {
|
||||
$status_array = array();
|
||||
foreach ( $this->job_objects as $job ) {
|
||||
if ( ! isset( $status_array[ $job->get_status() ] ) ) {
|
||||
$status_array[ $job->get_status() ] = 0;
|
||||
}
|
||||
$status_array[ $job->get_status() ] ++;
|
||||
}
|
||||
|
||||
return $status_array;
|
||||
}
|
||||
|
||||
private function retrieve_generic_batch_id() {
|
||||
return TranslationProxy_Batch::update_translation_batch( TranslationProxy_Batch::get_generic_batch_name() );
|
||||
}
|
||||
|
||||
private function belongs_to_active_ts() {
|
||||
global $wpdb;
|
||||
|
||||
$service_id = TranslationProxy::get_current_service_id();
|
||||
$batch_id = $this->get_id();
|
||||
|
||||
$result = false;
|
||||
if ( $service_id ) {
|
||||
$result = $wpdb->get_var( $wpdb->prepare( "SELECT rid FROM {$wpdb->prefix}icl_translation_status WHERE batch_id = %d AND translation_service = %s LIMIT 1", array( $batch_id, $service_id ) ) );
|
||||
$result |= $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$wpdb->prefix}icl_string_translations WHERE batch_id = %d AND translation_service = %s LIMIT 1", array( $batch_id, $service_id ) ) );
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function ts_supports_notifications() {
|
||||
$translation_service = TranslationProxy::get_current_service();
|
||||
return $supports_notifications = isset( $translation_service->notification ) ? $translation_service->notification : true;
|
||||
}
|
||||
|
||||
public function clear_batch_data() {
|
||||
TranslationProxy_Basket::set_batch_data( null );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,268 @@
|
||||
<?php
|
||||
require_once WPML_TM_PATH . '/inc/translation-jobs/jobs/wpml-element-translation-job.class.php';
|
||||
require_once WPML_TM_PATH . '/inc/translation-jobs/jobs/wpml-external-translation-job.class.php';
|
||||
require_once WPML_TM_PATH . '/inc/translation-jobs/jobs/wpml-post-translation-job.class.php';
|
||||
require_once WPML_TM_PATH . '/inc/translation-jobs/jobs/wpml-string-translation-job.class.php';
|
||||
|
||||
class WPML_Translation_Jobs_Collection extends WPML_Abstract_Job_Collection {
|
||||
|
||||
/** @var WPML_Translation_Batch[] $translation_batches */
|
||||
private $translation_batches = array();
|
||||
|
||||
private $count = 0;
|
||||
private $first_count;
|
||||
private $last_count;
|
||||
private $before_count = 0;
|
||||
private $after_count = 0;
|
||||
/** @var array $filter */
|
||||
private $filter;
|
||||
|
||||
/** @var string $jobs_union_table_sql */
|
||||
private $jobs_union_table_sql;
|
||||
|
||||
/**
|
||||
* @param wpdb $wpdb
|
||||
* @param array $icl_translation_filter
|
||||
*/
|
||||
public function __construct( &$wpdb, $icl_translation_filter ) {
|
||||
parent::__construct( $wpdb );
|
||||
$this->filter = $icl_translation_filter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $page
|
||||
* @param int $per_page
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_paginated_batches( $page, $per_page ) {
|
||||
$this->load_translation_jobs( $page, $per_page );
|
||||
|
||||
$metrics = array();
|
||||
$batches = array();
|
||||
if ( $this->translation_batches ) {
|
||||
krsort( $this->translation_batches );
|
||||
foreach ( $this->translation_batches as $id => $batch ) {
|
||||
$metrics[ $id ] = $batch->get_batch_meta_array();
|
||||
$batches[ $id ] = $batch;
|
||||
}
|
||||
}
|
||||
|
||||
$first_batch_metric = array_shift( $metrics );
|
||||
$first_batch_metric['display_from'] = $this->before_count + 1;
|
||||
$first_batch_metric['item_count'] = $this->first_count;
|
||||
array_unshift( $metrics, $first_batch_metric );
|
||||
$last_batch_metric = array_pop( $metrics );
|
||||
$last_batch_metric['display_to'] = $this->last_count - $this->after_count;
|
||||
$last_batch_metric['item_count'] = $this->last_count;
|
||||
$metrics[] = $last_batch_metric;
|
||||
|
||||
return array(
|
||||
'batches' => $batches,
|
||||
'metrics' => $metrics,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of jobs that meet the filter \WPML_Translation_Jobs_Collection::$filter in the database
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function get_count() {
|
||||
|
||||
return $this->count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WPML_Translation_Job $job
|
||||
*/
|
||||
public function add_job( $job ) {
|
||||
$batch_id = $job->get_batch_id();
|
||||
$batch = array_key_exists( $batch_id, $this->translation_batches )
|
||||
? $this->translation_batches[ $batch_id ] : new WPML_Translation_Batch( $this->wpdb, $batch_id );
|
||||
|
||||
$batch->add_job( $job );
|
||||
$this->translation_batches[ $batch->get_id() ] = $batch;
|
||||
}
|
||||
|
||||
private function load_translation_jobs( $page, $per_page ) {
|
||||
$this->translation_batches = array();
|
||||
list( $jobs, $count, $before_count, $after_count, $first_count, $last_count ) = $this->get_jobs_table(
|
||||
$this->filter,
|
||||
array(
|
||||
'page' => $page,
|
||||
'per_page' => $per_page,
|
||||
)
|
||||
);
|
||||
$this->count = $count;
|
||||
$this->after_count = $after_count;
|
||||
$this->before_count = $before_count;
|
||||
$this->first_count = $first_count;
|
||||
$this->last_count = $last_count;
|
||||
if ( is_array( $jobs ) ) {
|
||||
foreach ( $jobs as $job ) {
|
||||
$this->add_job( $job );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $args
|
||||
* @param array $pagination_args
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_jobs_table( array $args = array(), array $pagination_args = array(
|
||||
'page' => 1,
|
||||
'per_page' => 10,
|
||||
) ) {
|
||||
list( $data, $found_rows ) = $this->get_jobs_in_db( $args, $pagination_args );
|
||||
|
||||
if ( $data ) {
|
||||
$result = $this->calculate_batch_counts( $data, $found_rows, $pagination_args );
|
||||
} else {
|
||||
$result = $this->get_default_batch_counts( $found_rows );
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $found_rows
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_default_batch_counts( $found_rows ) {
|
||||
return array( array(), $found_rows, 0, 0, 0, 0 );
|
||||
}
|
||||
|
||||
private function get_jobs_in_db( array $args = array(), array $pagination_args = null ) {
|
||||
$where_jobs = $this->build_where_clause( $args );
|
||||
$jobs_table_union = $this->get_jobs_union_table_sql( $where_jobs, $args );
|
||||
|
||||
$only_ids_query = 'SELECT SQL_CALC_FOUND_ROWS ';
|
||||
$only_ids_query .= 'jobs.job_id, jobs.translator_id, jobs.job_id, jobs.batch_id, jobs.element_type_prefix ';
|
||||
$only_ids_query .= 'FROM ' . $jobs_table_union . ' ';
|
||||
|
||||
if ( $pagination_args ) {
|
||||
$only_ids_query .= 'LIMIT %d, %d';
|
||||
$prepare_args[] = max( ( $pagination_args['page'] - 1 ), 0 ) * $pagination_args['per_page'];
|
||||
$prepare_args[] = $pagination_args['per_page'];
|
||||
$only_ids_query = $this->wpdb->prepare( $only_ids_query, $prepare_args );
|
||||
}
|
||||
|
||||
$data = $this->wpdb->get_results( $only_ids_query );
|
||||
$found_rows = (int) $this->wpdb->get_var( 'SELECT FOUND_ROWS()' );
|
||||
|
||||
return array( $data, $found_rows );
|
||||
}
|
||||
|
||||
public function get_jobs( array $args = array() ) {
|
||||
list( $jobs_in_db, $found_rows ) = $this->get_jobs_in_db( $args );
|
||||
$this->count = $found_rows;
|
||||
return $this->plain_objects_to_job_instances( $jobs_in_db );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param int $count
|
||||
* @param array $pagination_args
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function calculate_batch_counts( $data, $count, $pagination_args ) {
|
||||
$first_job = reset( $data );
|
||||
$last_job = end( $data );
|
||||
$first_batch = $first_job->batch_id;
|
||||
$last_batch = $last_job->batch_id;
|
||||
$count_select_from_snippet = 'SELECT COUNT(jdata.job_id) FROM (SELECT job_id, batch_id FROM ' . $this->jobs_union_table_sql;
|
||||
$count_where_snippet = ' ) AS jdata WHERE jdata.batch_id = %d';
|
||||
$before_count_query = $count_select_from_snippet . ' LIMIT %d' . $count_where_snippet;
|
||||
$page = $pagination_args['page'];
|
||||
$per_page = $pagination_args['per_page'];
|
||||
$count_before = $page > 1 ? $this->wpdb->get_var(
|
||||
$this->wpdb->prepare(
|
||||
$before_count_query,
|
||||
array(
|
||||
( $page - 1 ) * $per_page,
|
||||
$first_batch,
|
||||
)
|
||||
)
|
||||
) : 0;
|
||||
$count_first = $this->wpdb->get_var(
|
||||
$this->wpdb->prepare(
|
||||
$before_count_query,
|
||||
array( PHP_INT_MAX, $first_batch )
|
||||
)
|
||||
);
|
||||
$after_count_query = $count_select_from_snippet . ' LIMIT %d, %d' . $count_where_snippet;
|
||||
$count_after = $page * $per_page > $count ? 0 : $this->wpdb->get_var(
|
||||
$this->wpdb->prepare(
|
||||
$after_count_query,
|
||||
array(
|
||||
$page * $per_page,
|
||||
PHP_INT_MAX,
|
||||
$last_batch,
|
||||
)
|
||||
)
|
||||
);
|
||||
$count_last = $this->wpdb->get_var(
|
||||
$this->wpdb->prepare(
|
||||
$after_count_query,
|
||||
array( 0, PHP_INT_MAX, $last_batch )
|
||||
)
|
||||
);
|
||||
|
||||
return array(
|
||||
$this->plain_objects_to_job_instances( $data ),
|
||||
$count,
|
||||
$count_before,
|
||||
$count_after,
|
||||
$count_first,
|
||||
$count_last,
|
||||
);
|
||||
}
|
||||
|
||||
private function get_jobs_union_table_sql( $where_jobs, $args ) {
|
||||
$union_sql = '';
|
||||
$sql_statements = array();
|
||||
|
||||
if ( $where_jobs ) {
|
||||
$sql_statements[] = "SELECT s.translator_id,
|
||||
j.job_id,
|
||||
IF(p.post_type IS NOT NULL, 'post', 'package') AS element_type_prefix,
|
||||
p.post_type AS post_type,
|
||||
s.batch_id
|
||||
FROM {$this->wpdb->prefix}icl_translation_status s
|
||||
JOIN {$this->wpdb->prefix}icl_translations t
|
||||
ON t.translation_id = s.translation_id
|
||||
JOIN {$this->wpdb->prefix}icl_translate_job j
|
||||
ON j.rid = s.rid
|
||||
AND j.revision IS NULL
|
||||
JOIN {$this->wpdb->prefix}icl_translations o
|
||||
ON o.trid = t.trid
|
||||
AND o.language_code = t.source_language_code
|
||||
JOIN " . apply_filters( 'wpml_post_translation_original_table', $this->wpdb->posts ) . " p
|
||||
ON o.element_id = p.ID
|
||||
AND ( o.element_type = CONCAT('post_', p.post_type) OR p.post_type IS NULL )
|
||||
JOIN {$this->wpdb->prefix}icl_translate tr_rows
|
||||
ON tr_rows.job_id = j.job_id
|
||||
AND tr_rows.field_type = 'original_id'
|
||||
AND tr_rows.field_data = o.element_id
|
||||
WHERE " . $where_jobs;
|
||||
}
|
||||
|
||||
$sql_statements = apply_filters( 'wpml_tm_jobs_union_table_sql', $sql_statements, $args );
|
||||
|
||||
if ( count( $sql_statements ) > 0 ) {
|
||||
$union_sql = '(' . implode( "\nUNION ALL\n", $sql_statements ) . ") jobs
|
||||
INNER JOIN {$this->wpdb->prefix}icl_translation_batches b
|
||||
ON b.id = jobs.batch_id
|
||||
ORDER BY jobs.batch_id DESC, jobs.element_type_prefix, jobs.job_id DESC";
|
||||
}
|
||||
|
||||
$this->jobs_union_table_sql = $union_sql;
|
||||
|
||||
return $union_sql;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
class WPML_Translator {
|
||||
/** @var int */
|
||||
public $ID;
|
||||
|
||||
/** @var string */
|
||||
public $display_name;
|
||||
|
||||
/** @var string */
|
||||
public $user_login;
|
||||
|
||||
/**
|
||||
* Array where key represents a source language code and values are codes of target languages.
|
||||
*
|
||||
* @var array<string, string[]>
|
||||
*/
|
||||
public $language_pairs;
|
||||
|
||||
/**
|
||||
* @param string $property
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function __get( $property ) {
|
||||
if ( $property == 'translator_id' ) {
|
||||
return $this->ID;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $property
|
||||
* @param int $value
|
||||
*
|
||||
* @return null
|
||||
*/
|
||||
public function __set( $property, $value ) {
|
||||
if ( $property == 'translator_id' ) {
|
||||
$this->ID = $value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
function translation_service_details( $service, $show_project = false ) {
|
||||
$service_details = '';
|
||||
if ( defined( 'OTG_SANDBOX_DEBUG' ) && OTG_SANDBOX_DEBUG ) {
|
||||
$service_details .= '<h3>Service details:</h3>' . PHP_EOL;
|
||||
$service_details .= '<pre>' . PHP_EOL;
|
||||
$service_details .= print_r( $service, true );
|
||||
$service_details .= '</pre>' . PHP_EOL;
|
||||
|
||||
if ( $show_project ) {
|
||||
$project = TranslationProxy::get_current_project();
|
||||
echo '<pre>$project' . PHP_EOL;
|
||||
echo print_r( $project, true );
|
||||
echo '</pre>';
|
||||
}
|
||||
}
|
||||
|
||||
return $service_details;
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'object_to_array' ) ) {
|
||||
function object_to_array( $obj ) {
|
||||
if ( is_object( $obj ) ) {
|
||||
$obj = (array) $obj;
|
||||
}
|
||||
if ( is_array( $obj ) ) {
|
||||
$new = array();
|
||||
foreach ( $obj as $key => $val ) {
|
||||
$new[ $key ] = object_to_array( $val );
|
||||
}
|
||||
} else {
|
||||
$new = $obj;
|
||||
}
|
||||
|
||||
return $new;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
/**
|
||||
* @package wpml-core
|
||||
* @subpackage wpml-core
|
||||
*/
|
||||
|
||||
if( class_exists( 'TranslationProxy_Api' ) ) {
|
||||
// Workaround for UnitTests.
|
||||
return;
|
||||
}
|
||||
|
||||
class TranslationProxy_Api {
|
||||
const API_VERSION = 1.1;
|
||||
|
||||
public static function proxy_request(
|
||||
$path,
|
||||
$params = array(),
|
||||
$method = 'GET',
|
||||
$multi_part = false,
|
||||
$has_return_value = true
|
||||
) {
|
||||
|
||||
return wpml_tm_load_tp_networking()->send_request(
|
||||
OTG_TRANSLATION_PROXY_URL . $path,
|
||||
$params,
|
||||
$method,
|
||||
$has_return_value
|
||||
);
|
||||
}
|
||||
|
||||
public static function proxy_download( $path, $params ) {
|
||||
|
||||
return wpml_tm_load_tp_networking()->send_request(
|
||||
OTG_TRANSLATION_PROXY_URL . $path,
|
||||
$params,
|
||||
'GET',
|
||||
true,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
public static function service_request(
|
||||
$url,
|
||||
$params = array(),
|
||||
$method = 'GET',
|
||||
$has_return_value = true,
|
||||
$json_response = false,
|
||||
$has_api_response = false
|
||||
) {
|
||||
|
||||
return wpml_tm_load_tp_networking()->send_request(
|
||||
$url,
|
||||
$params,
|
||||
$method,
|
||||
$has_return_value,
|
||||
$json_response,
|
||||
$has_api_response
|
||||
);
|
||||
}
|
||||
|
||||
public static function add_parameters_to_url( $url, $params ) {
|
||||
if ( preg_match_all( '/\{.+?\}/', $url, $symbs ) ) {
|
||||
foreach ( $symbs[0] as $symb ) {
|
||||
$without_braces = preg_replace( '/\{|\}/', '', $symb );
|
||||
if ( preg_match_all( '/\w+/', $without_braces, $indexes ) ) {
|
||||
foreach ( $indexes[0] as $index ) {
|
||||
if ( isset( $params[ $index ] ) ) {
|
||||
$value = $params[ $index ];
|
||||
$url = preg_replace( preg_quote( "/$symb/" ), $value, $url );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'gzdecode' ) ) {
|
||||
/**
|
||||
* Inflates a string enriched with gzip headers. Counterpart to gzencode().
|
||||
* Extracted from upgradephp
|
||||
* http://include-once.org/p/upgradephp/
|
||||
*
|
||||
* officially available by default in php @since 5.4.
|
||||
*/
|
||||
function gzdecode( $gzdata, $maxlen = null ) {
|
||||
|
||||
// -- decode header
|
||||
$len = strlen( $gzdata );
|
||||
if ( $len < 20 ) {
|
||||
return;
|
||||
}
|
||||
$head = substr( $gzdata, 0, 10 );
|
||||
$head = unpack( 'n1id/C1cm/C1flg/V1mtime/C1xfl/C1os', $head );
|
||||
list( $ID, $CM, $FLG, $MTIME, $XFL, $OS ) = array_values( $head );
|
||||
$FTEXT = 1 << 0;
|
||||
$FHCRC = 1 << 1;
|
||||
$FEXTRA = 1 << 2;
|
||||
$FNAME = 1 << 3;
|
||||
$FCOMMENT = 1 << 4;
|
||||
$head = unpack( 'V1crc/V1isize', substr( $gzdata, $len - 8, 8 ) );
|
||||
list( $CRC32, $ISIZE ) = array_values( $head );
|
||||
|
||||
// -- check gzip stream identifier
|
||||
if ( $ID != 0x1f8b ) {
|
||||
trigger_error( 'gzdecode: not in gzip format', E_USER_WARNING );
|
||||
|
||||
return;
|
||||
}
|
||||
// -- check for deflate algorithm
|
||||
if ( $CM != 8 ) {
|
||||
trigger_error( 'gzdecode: cannot decode anything but deflated streams', E_USER_WARNING );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// -- start of data, skip bonus fields
|
||||
$s = 10;
|
||||
if ( $FLG & $FEXTRA ) {
|
||||
$s += $XFL;
|
||||
}
|
||||
if ( $FLG & $FNAME ) {
|
||||
$s = strpos( $gzdata, "\000", $s ) + 1;
|
||||
}
|
||||
if ( $FLG & $FCOMMENT ) {
|
||||
$s = strpos( $gzdata, "\000", $s ) + 1;
|
||||
}
|
||||
if ( $FLG & $FHCRC ) {
|
||||
$s += 2; // cannot check
|
||||
}
|
||||
|
||||
// -- get data, uncompress
|
||||
$gzdata = substr( $gzdata, $s, $len - $s );
|
||||
if ( $maxlen ) {
|
||||
$gzdata = gzinflate( $gzdata, $maxlen );
|
||||
|
||||
return ( $gzdata ); // no checks(?!)
|
||||
} else {
|
||||
$gzdata = gzinflate( $gzdata );
|
||||
}
|
||||
|
||||
// -- check+fin
|
||||
$chk = crc32( $gzdata );
|
||||
if ( $CRC32 != $chk ) {
|
||||
trigger_error( "gzdecode: checksum failed (real$chk != comp$CRC32)", E_USER_WARNING );
|
||||
} elseif ( $ISIZE != strlen( $gzdata ) ) {
|
||||
trigger_error( 'gzdecode: stream size mismatch', E_USER_WARNING );
|
||||
} else {
|
||||
return ( $gzdata );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,927 @@
|
||||
<?php
|
||||
/**
|
||||
* @package wpml-core
|
||||
* @subpackage wpml-core
|
||||
*/
|
||||
|
||||
use WPML\TM\API\Jobs;
|
||||
|
||||
if ( ! class_exists( 'TranslationProxy_Basket' ) ) {
|
||||
/**
|
||||
* TranslationProxy_basket collects all static methods to operate on
|
||||
* translations basket (cart)
|
||||
*/
|
||||
class TranslationProxy_Basket {
|
||||
private static $messages;
|
||||
private static $dashboard_select;
|
||||
|
||||
private static $basket;
|
||||
|
||||
// The name of the option stored in wp_options table and that
|
||||
// stores all the basket items
|
||||
const ICL_TRANSLATION_JOBS_BASKET = 'icl_translation_jobs_basket';
|
||||
private static $posts_ids;
|
||||
private static $translate_from;
|
||||
private static $translation_action;
|
||||
|
||||
public static function add_message( $array ) {
|
||||
self::$messages[] = $array;
|
||||
}
|
||||
|
||||
public static function remove_message( $text ) {
|
||||
if ( is_array( self::$messages ) ) {
|
||||
foreach ( self::$messages as $key => $message ) {
|
||||
if ( array_key_exists( 'text', $message ) && $message['text'] === $text ) {
|
||||
unset( self::$messages[ $key ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function get_basket( $force = false ) {
|
||||
if ( ! isset( self::$basket ) || $force ) {
|
||||
self::$basket = get_option( self::ICL_TRANSLATION_JOBS_BASKET, [] );
|
||||
}
|
||||
|
||||
return self::$basket;
|
||||
}
|
||||
|
||||
public static function update_basket( $basket_portion = array() ) {
|
||||
if ( ! empty( $basket_portion ) ) {
|
||||
if ( ! self::$basket || self::get_basket_items_count() == 0 ) {
|
||||
self::$basket = $basket_portion;
|
||||
} else {
|
||||
self::$basket = self::merge_baskets( self::$basket, $basket_portion );
|
||||
}
|
||||
}
|
||||
if ( self::get_basket_items_count( true ) == 0 ) {
|
||||
self::$basket = [];
|
||||
}
|
||||
self::sync_target_languages();
|
||||
self::update_basket_option( self::$basket );
|
||||
self::update_basket_notifications();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $basket
|
||||
*/
|
||||
private static function update_basket_option( $basket ) {
|
||||
update_option( self::ICL_TRANSLATION_JOBS_BASKET, $basket, false );
|
||||
}
|
||||
|
||||
private static function merge_baskets( $from, $to ) {
|
||||
if ( function_exists( 'array_replace_recursive' ) ) {
|
||||
return array_replace_recursive( $from, $to );
|
||||
} else {
|
||||
return self::array_replace_recursive( $from, $to );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return number of items in translation basket by key
|
||||
*
|
||||
* @param string $type
|
||||
* @param bool $skip_cache
|
||||
*
|
||||
* @return int number of items in translation basket
|
||||
*/
|
||||
public static function get_basket_items_type_count( $type, $skip_cache = false ) {
|
||||
|
||||
$cache_key = $type;
|
||||
$cache_group = 'get_basket_items_type_count';
|
||||
$cache_found = false;
|
||||
|
||||
if ( ! $skip_cache ) {
|
||||
$basket_items_number = (int) wp_cache_get( $cache_key, $cache_group, false, $cache_found );
|
||||
} else {
|
||||
$basket_items_number = 0;
|
||||
}
|
||||
|
||||
if ( $cache_found ) {
|
||||
return $basket_items_number;
|
||||
}
|
||||
|
||||
self::get_basket();
|
||||
|
||||
if ( self::$basket ) {
|
||||
if ( isset( self::$basket[ $type ] ) ) {
|
||||
$posts = self::$basket[ $type ];
|
||||
$basket_items_number += count( $posts );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $skip_cache ) {
|
||||
wp_cache_set( $cache_key, $basket_items_number, $cache_group );
|
||||
}
|
||||
|
||||
return $basket_items_number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return number of items in translation basket
|
||||
*
|
||||
* @param bool $skip_cache
|
||||
*
|
||||
* @return int number of items in translation basket
|
||||
*/
|
||||
public static function get_basket_items_count( $skip_cache = false ) {
|
||||
|
||||
$basket_items_number = 0;
|
||||
|
||||
$basket_items_types = self::get_basket_items_types();
|
||||
foreach ( $basket_items_types as $item_type_name => $item_type ) {
|
||||
$basket_items_number += self::get_basket_items_type_count( $item_type_name, $skip_cache );
|
||||
}
|
||||
|
||||
return $basket_items_number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register notification with number of items in basket and link to basket
|
||||
*/
|
||||
public static function update_basket_notifications() {
|
||||
$positions = self::get_basket_notification_positions();
|
||||
$basket_link = 'admin.php?page=' . WPML_TM_FOLDER . '/menu/main.php&sm=basket';
|
||||
|
||||
foreach ( $positions as $position => $group ) {
|
||||
ICL_AdminNotifier::remove_message_group( $position );
|
||||
}
|
||||
|
||||
self::get_basket();
|
||||
$basket_items_count = self::get_basket_items_count( true );
|
||||
|
||||
$limit_to_page = array();
|
||||
if ( defined( 'WPML_ST_FOLDER' ) ) {
|
||||
$limit_to_page[] = WPML_ST_FOLDER . '/menu/string-translation.php';
|
||||
}
|
||||
|
||||
// if we have something in the basket
|
||||
if ( self::is_st_page() && $basket_items_count > 0 && ( ! isset( $_GET['clear_basket'] ) || $_GET['clear_basket'] != 1 ) && ( ! isset( $_GET['action'] ) || $_GET['action'] != 'delete' ) ) {
|
||||
|
||||
$text = __( 'The items you have selected are now in the translation basket –', 'wpml-translation-management' );
|
||||
$text .= ' ' . sprintf( __( '<a href="%s">Send to translation »</a>', 'wpml-translation-management' ), $basket_link );
|
||||
|
||||
// translation management pages
|
||||
$message_args = array(
|
||||
'id' => $positions['tm_dashboard_top'],
|
||||
'text' => $text,
|
||||
'classes' => 'small',
|
||||
'type' => 'information small',
|
||||
'group' => $positions['tm_dashboard_top'],
|
||||
'admin_notice' => false,
|
||||
'hide_per_user' => false,
|
||||
'dismiss_per_user' => false,
|
||||
'limit_to_page' => $limit_to_page,
|
||||
'capability' => 'manage_translations',
|
||||
);
|
||||
ICL_AdminNotifier::add_message( $message_args );
|
||||
|
||||
} else {
|
||||
ICL_AdminNotifier::remove_message( $positions['tm_dashboard_top'] );
|
||||
}
|
||||
|
||||
$admin_basket_message_id = $positions['admin_notice'];
|
||||
if ( ( self::$messages || $basket_items_count > 0 ) && self::is_st_page() ) {
|
||||
|
||||
$additional_messages = array();
|
||||
if ( isset( self::$messages ) && is_array( self::$messages ) ) {
|
||||
foreach ( self::$messages as $message ) {
|
||||
$additional_messages[] = $message['text'];
|
||||
}
|
||||
}
|
||||
$additional_messages_text = '';
|
||||
if ( count( $additional_messages ) > 0 ) {
|
||||
$additional_messages_text = '<ul><li>' . implode( '</li><li>', $additional_messages ) . '</li></ul>';
|
||||
}
|
||||
|
||||
$message_args = array(
|
||||
'id' => $admin_basket_message_id,
|
||||
'text' => $additional_messages_text,
|
||||
'classes' => 'small',
|
||||
'type' => 'information',
|
||||
'group' => $admin_basket_message_id,
|
||||
'admin_notice' => true,
|
||||
'hide_per_user' => false,
|
||||
'dismiss_per_user' => false,
|
||||
'limit_to_page' => $limit_to_page,
|
||||
'show_once' => true,
|
||||
);
|
||||
|
||||
if ( trim( $additional_messages_text ) != '' ) {
|
||||
ICL_AdminNotifier::add_message( $message_args );
|
||||
}
|
||||
} else {
|
||||
ICL_AdminNotifier::remove_message( $admin_basket_message_id );
|
||||
}
|
||||
}
|
||||
|
||||
private static function is_st_page() {
|
||||
return defined( 'WPML_ST_FOLDER' ) && array_key_exists( 'page', $_GET ) && false !== strpos( $_GET['page'], WPML_ST_FOLDER );
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays div with number of items in basket and link to basket
|
||||
* Removes notification if basket is empty
|
||||
*/
|
||||
public static function display_basket_items_notification() {
|
||||
ICL_AdminNotifier::display_messages( 'translation-basket-notification' );
|
||||
}
|
||||
|
||||
public static function is_in_basket( $post_id, $source_language, $target_language, $item_type = 'post' ) {
|
||||
self::get_basket();
|
||||
|
||||
if ( ! self::$basket || ! isset( self::$basket[ $item_type ][ $post_id ] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$basket_item = self::$basket[ $item_type ][ $post_id ];
|
||||
|
||||
return $basket_item['from_lang'] == $source_language && isset( $basket_item['to_langs'][ $target_language ] ) && $basket_item['to_langs'][ $target_language ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if post with ID $post_id is in the basket for any language
|
||||
*
|
||||
* @param int $post_id
|
||||
* @param string $element_type
|
||||
* @param array $check_in_languages
|
||||
* @param bool $original_language_code
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function anywhere_in_basket( $post_id, $element_type = 'post', $check_in_languages = array(), $original_language_code = false ) {
|
||||
$basket = self::get_basket();
|
||||
|
||||
if ( $post_id && isset( $basket[ $element_type ][ $post_id ] ) ) {
|
||||
if ( $check_in_languages ) {
|
||||
if ( ! $original_language_code ) {
|
||||
$original_language_code = $basket['source_language'];
|
||||
}
|
||||
foreach ( $check_in_languages as $language_code => $language_data ) {
|
||||
if ( $language_code != $original_language_code && isset( $basket[ $element_type ][ $post_id ]['to_langs'][ $language_code ] ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function is_string_in_basket_anywhere( $string_id ) {
|
||||
return self::anywhere_in_basket( $string_id, 'string' );
|
||||
}
|
||||
|
||||
public static function has_any_string() {
|
||||
return self::has_any_item_type( 'string' );
|
||||
}
|
||||
|
||||
public static function has_any_item_type( $item_type ) {
|
||||
self::get_basket();
|
||||
return isset( self::$basket[ $item_type ] ) && count( self::$basket[ $item_type ] );
|
||||
}
|
||||
|
||||
/**** adding items to basket ****/
|
||||
|
||||
/**
|
||||
* Serves Translation Dashboard form submission and adds posts to basket
|
||||
*
|
||||
* @param array $data data submitted from form
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function add_posts_to_basket( $data ) {
|
||||
self::get_basket();
|
||||
global $sitepress, $iclTranslationManagement;
|
||||
|
||||
$wpml_translation_job_factory = wpml_tm_load_job_factory();
|
||||
|
||||
extract( $data, EXTR_OVERWRITE );
|
||||
|
||||
ICL_AdminNotifier::remove_message( 'the_basket_items_notification' );
|
||||
|
||||
self::$translation_action = null;
|
||||
if ( isset( $data['tr_action'] ) ) { // adapt new format
|
||||
self::$translation_action = $data['tr_action'];
|
||||
}
|
||||
if ( ! isset( $data['tr_action'] ) && isset( $data['translate_to'] ) ) { // adapt new format
|
||||
$data['tr_action'] = $data['translate_to'];
|
||||
self::$translation_action = $data['tr_action'];
|
||||
unset( $data['translate_to'] );
|
||||
}
|
||||
|
||||
self::$posts_ids = self::get_elements_ids( $data, 'post' );
|
||||
|
||||
self::$translate_from = $data ['translate_from']; // language of the submitted posts transported by hidden field
|
||||
|
||||
$data_is_valid = self::validate_data( $data );
|
||||
|
||||
if ( ! $data_is_valid ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// check tr_action and do what user decided
|
||||
foreach ( self::$translation_action as $language_code => $status ) {
|
||||
|
||||
$language_name = $sitepress->get_display_language_name( $language_code );
|
||||
// if he decided duplicate or not to translate for this particular language,
|
||||
// try to remove it from wp_options
|
||||
|
||||
$basket_item_type = 'post';
|
||||
|
||||
if ( $status == 2 ) {
|
||||
// iterate posts ids, check if they are in wp_options
|
||||
// if they are set to translate for this particular language
|
||||
// end then remove it
|
||||
foreach ( self::$posts_ids as $id ) {
|
||||
if ( isset( self::$basket[ $basket_item_type ][ $id ]['to_langs'][ $language_code ] ) ) {
|
||||
unset( self::$basket[ $basket_item_type ][ $id ]['to_langs'][ $language_code ] );
|
||||
}
|
||||
// if user want to duplicate this post, lets do this
|
||||
if ( $status == 2 ) {
|
||||
$iclTranslationManagement->make_duplicate( $id, $language_code );
|
||||
}
|
||||
}
|
||||
} elseif ( $status == 1 ) {
|
||||
foreach ( self::$posts_ids as $id ) {
|
||||
|
||||
$send_to_basket = true;
|
||||
|
||||
$post = self::get_post( $id );
|
||||
|
||||
$post_type = $post->post_type;
|
||||
$messages = new \WPML\TM\Jobs\Dispatch\Messages();
|
||||
global $wpdb;
|
||||
$source_language_code = $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
" SELECT source_language_code
|
||||
FROM {$wpdb->prefix}icl_translations
|
||||
WHERE element_type LIKE 'post_%%'
|
||||
AND element_id = %d",
|
||||
$post->ID
|
||||
)
|
||||
);
|
||||
|
||||
if ( $source_language_code != $language_code ) {
|
||||
$job = Jobs::getPostJob( $id, $post_type, $language_code );
|
||||
if ( $job && ICL_TM_IN_PROGRESS === $job->status && ! $job->needs_update ) {
|
||||
self::$messages[] = array(
|
||||
'type' => 'update',
|
||||
'text' => $messages->ignoreInProgressPostMessage( $post, $language_name ),
|
||||
);
|
||||
$send_to_basket = false;
|
||||
}
|
||||
} else {
|
||||
self::$messages[] = array(
|
||||
'type' => 'update',
|
||||
'text' => $messages->ignoreOriginalPostMessage( $post, $language_name ),
|
||||
);
|
||||
$send_to_basket = false;
|
||||
}
|
||||
|
||||
if ( $send_to_basket ) {
|
||||
self::$basket[ $basket_item_type ][ $id ]['from_lang'] = self::$translate_from;
|
||||
self::$basket[ $basket_item_type ][ $id ]['to_langs'][ $language_code ] = 1;
|
||||
// set basket language if not already set
|
||||
if ( ! isset( self::$basket['source_language'] ) ) {
|
||||
self::$basket['source_language'] = self::$translate_from;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self::update_basket();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serves WPML > String translation form submission and adds strings to basket
|
||||
*
|
||||
* @param array $string_ids identifiers of strings
|
||||
* @param $source_language
|
||||
* @param array $target_languages selected target languages
|
||||
* @return bool
|
||||
* @todo: [WPML 3.3] move to ST and handle with hooks
|
||||
*/
|
||||
public static function add_strings_to_basket( $string_ids, $source_language, $target_languages ) {
|
||||
global $wpdb, $sitepress;
|
||||
|
||||
self::get_basket();
|
||||
ICL_AdminNotifier::remove_message( 'the_basket_items_notification' );
|
||||
|
||||
/*
|
||||
structure of cart in get_option:
|
||||
* [posts]
|
||||
* [element_id]
|
||||
* [to_langs]
|
||||
* [language_code] fr | pl | de ... with value 1
|
||||
* [strings]
|
||||
* [string_id]
|
||||
* [to_langs]
|
||||
* [language_code]
|
||||
*/
|
||||
|
||||
// no post selected ?
|
||||
if ( empty( $string_ids ) ) {
|
||||
self::$messages[] = array(
|
||||
'type' => 'error',
|
||||
'text' => __( 'Please select at least one document to translate.', 'wpml-translation-management' ),
|
||||
);
|
||||
self::update_basket();
|
||||
return false;
|
||||
}
|
||||
|
||||
// no language selected ?
|
||||
if ( empty( $target_languages ) ) {
|
||||
self::$messages[] = array(
|
||||
'type' => 'error',
|
||||
'text' => __( 'Please select at least one language to translate into.', 'wpml-translation-management' ),
|
||||
);
|
||||
self::update_basket();
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( self::get_basket() && self::get_source_language() ) {
|
||||
/*
|
||||
we do not add items that are not in the source language of the current basket
|
||||
we cannot yet set its source language though since update_basket would set the basket
|
||||
to false oso long as we do not have any elements in the basket*/
|
||||
if ( $source_language != self::get_source_language() ) {
|
||||
self::$messages[] = array(
|
||||
'type' => 'update',
|
||||
'text' => __(
|
||||
'You cannot add strings in this language to the basket since it already contains posts 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-translation-management'
|
||||
),
|
||||
);
|
||||
self::update_basket();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $target_languages as $target_language => $selected ) {
|
||||
if ( $target_language == $source_language ) {
|
||||
continue;
|
||||
}
|
||||
$target_language_name = $sitepress->get_display_language_name( $target_language );
|
||||
|
||||
foreach ( $string_ids as $id ) {
|
||||
|
||||
$send_to_basket = true;
|
||||
$query = " SELECT {$wpdb->prefix}icl_string_translations.status,
|
||||
{$wpdb->prefix}icl_strings.value
|
||||
FROM {$wpdb->prefix}icl_string_translations
|
||||
INNER JOIN {$wpdb->prefix}icl_strings
|
||||
ON {$wpdb->prefix}icl_string_translations.string_id = {$wpdb->prefix}icl_strings.id
|
||||
WHERE {$wpdb->prefix}icl_string_translations.string_id=%d
|
||||
AND {$wpdb->prefix}icl_string_translations.language=%s";
|
||||
|
||||
$string_translation = $wpdb->get_row( $wpdb->prepare( $query, $id, $target_language ) );
|
||||
|
||||
if ( ! is_null( $string_translation ) && $string_translation->status == ICL_TM_WAITING_FOR_TRANSLATOR ) {
|
||||
self::$messages[] = array(
|
||||
'type' => 'update',
|
||||
'text' => sprintf(
|
||||
__(
|
||||
'String "%1$s" will be ignored for %2$s, because translation is already waiting for translator.',
|
||||
'wpml-translation-management'
|
||||
),
|
||||
$string_translation->value,
|
||||
$target_language_name
|
||||
),
|
||||
);
|
||||
$send_to_basket = false;
|
||||
}
|
||||
|
||||
if ( $send_to_basket ) {
|
||||
self::$basket['string'][ $id ]['from_lang'] = $source_language;
|
||||
self::$basket['string'][ $id ]['to_langs'][ $target_language ] = 1;
|
||||
// set basket language if not already set
|
||||
if ( ! isset( self::$basket['source_language'] ) ) {
|
||||
self::$basket['source_language'] = $source_language;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self::update_basket();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serves deletion of items from basket, triggered from WPML TM > Translation
|
||||
* Jobs
|
||||
*
|
||||
* @param array $items Array of items ids, in two separate parts: ['post']
|
||||
* and ['string']
|
||||
*/
|
||||
public static function delete_items_from_basket( $items ) {
|
||||
self::get_basket();
|
||||
|
||||
$basket_items_types = self::get_basket_items_types();
|
||||
foreach ( $basket_items_types as $item_type_name => $item_type ) {
|
||||
if ( ! empty( $items[ $item_type_name ] ) ) {
|
||||
foreach ( $items[ $item_type_name ] as $id ) {
|
||||
self::delete_item_from_basket( $id, $item_type_name, false );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self::update_basket();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes one item from basket
|
||||
*
|
||||
* @param int $id Item ID
|
||||
* @param string $type Item type (strings | posts | ...)
|
||||
* @param bool $update_option do update_option('icl_translation_jobs_cart' ?
|
||||
*/
|
||||
public static function delete_item_from_basket( $id, $type = 'post', $update_option = true ) {
|
||||
self::get_basket();
|
||||
|
||||
if ( isset( self::$basket[ $type ][ $id ] ) ) {
|
||||
unset( self::$basket[ $type ][ $id ] );
|
||||
if ( count( self::$basket[ $type ] ) == 0 ) {
|
||||
unset( self::$basket[ $type ] );
|
||||
}
|
||||
}
|
||||
|
||||
if ( self::get_basket_items_count( true ) == 0 ) {
|
||||
self::$basket = array();
|
||||
}
|
||||
|
||||
if ( $update_option ) {
|
||||
self::update_basket( self::$basket );
|
||||
} else {
|
||||
self::update_basket_notifications();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: [WPML 3.3] implement this in the troubleshooting page
|
||||
public static function delete_all_items_from_basket() {
|
||||
self::$basket = [];
|
||||
delete_option( self::ICL_TRANSLATION_JOBS_BASKET );
|
||||
self::update_basket();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WPML_TP_Batch|null $batch
|
||||
*/
|
||||
public static function set_batch_data( $batch ) {
|
||||
self::get_basket();
|
||||
self::$basket['batch'] = $batch;
|
||||
self::update_basket();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return false|null|WPML_TP_Batch
|
||||
*/
|
||||
public static function get_batch_data() {
|
||||
self::get_basket();
|
||||
return isset( self::$basket['batch'] ) ? self::$basket['batch'] : false;
|
||||
}
|
||||
|
||||
public static function set_basket_name( $basket_name ) {
|
||||
self::get_basket();
|
||||
self::$basket['name'] = $basket_name;
|
||||
self::update_basket();
|
||||
}
|
||||
|
||||
public static function get_basket_name() {
|
||||
self::get_basket();
|
||||
|
||||
return isset( self::$basket['name'] ) ? self::$basket['name'] : false;
|
||||
}
|
||||
|
||||
public static function set_options( array $options ) {
|
||||
self::$basket['options'] = $options;
|
||||
}
|
||||
|
||||
/** @return array */
|
||||
public static function get_options() {
|
||||
return isset( self::$basket['options'] ) ? self::$basket['options'] : array();
|
||||
}
|
||||
|
||||
public static function get_basket_extra_fields() {
|
||||
if ( isset( $_REQUEST['extra_fields'] ) ) {
|
||||
$extra_fields_string = urldecode( $_REQUEST['extra_fields'] );
|
||||
if ( strlen( $extra_fields_string ) > 0 ) {
|
||||
$extra_fields_rows = explode( '|', $extra_fields_string );
|
||||
$result = array();
|
||||
foreach ( $extra_fields_rows as $row ) {
|
||||
$row_data = explode( ':', $row );
|
||||
if ( count( $row_data ) == 2 ) {
|
||||
$result[ $row_data[0] ] = $row_data[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( $result ) && count( $result ) > 0 ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static function array_replace_recursive( $array, $array1 ) {
|
||||
if ( function_exists( 'array_replace_recursive' ) ) {
|
||||
$array = array_replace_recursive( $array, $array1 );
|
||||
} else {
|
||||
// handle the arguments, merge one by one
|
||||
$args = func_get_args();
|
||||
$array = $args[0];
|
||||
if ( ! is_array( $array ) ) {
|
||||
return $array;
|
||||
}
|
||||
for ( $i = 1; $i < count( $args ); $i ++ ) {
|
||||
if ( is_array( $args[ $i ] ) ) {
|
||||
$array = self::recurse( $array, $args[ $i ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
|
||||
private static function recurse( $array, $array1 ) {
|
||||
foreach ( $array1 as $key => $value ) {
|
||||
// create new key in $array, if it is empty or not an array
|
||||
if ( ! isset( $array[ $key ] ) || ( isset( $array[ $key ] ) && ! is_array( $array[ $key ] ) ) ) {
|
||||
$array[ $key ] = array();
|
||||
}
|
||||
|
||||
// overwrite the value in the base array
|
||||
if ( is_array( $value ) ) {
|
||||
$value = self::recurse( $array[ $key ], $value );
|
||||
}
|
||||
$array[ $key ] = $value;
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
public static function get_basket_items_types() {
|
||||
return apply_filters(
|
||||
'wpml_tm_basket_items_types',
|
||||
[
|
||||
'string' => 'core',
|
||||
'post' => 'core',
|
||||
'package' => 'custom',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $post_id
|
||||
*
|
||||
* @return mixed|null|void|WP_Post
|
||||
*/
|
||||
private static function get_post( $post_id ) {
|
||||
if ( is_string( $post_id ) && strcmp( substr( $post_id, 0, strlen( 'external_' ) ), 'external_' ) === 0 ) {
|
||||
$item = apply_filters( 'wpml_get_translatable_item', null, $post_id );
|
||||
} else {
|
||||
$item = get_post( $post_id );
|
||||
}
|
||||
return $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $selected_elements
|
||||
*
|
||||
* @param bool|string $type
|
||||
* @return array[]|int[]
|
||||
*/
|
||||
public static function get_elements_ids( $selected_elements, $type = false ) {
|
||||
$element_ids = array();
|
||||
$legal_item_types = $type ? array( $type ) : array_keys( self::get_basket_items_types() );
|
||||
foreach ( $legal_item_types as $item_type ) {
|
||||
if ( ! isset( $selected_elements[ $item_type ] ) ) {
|
||||
continue;
|
||||
}
|
||||
$element_ids[ $item_type ] = isset( $element_ids[ $item_type ] ) ? $element_ids[ $item_type ] : array();
|
||||
$items = $selected_elements[ $item_type ];
|
||||
foreach ( $items as $element_id => $action_data ) {
|
||||
if ( isset( $action_data['checked'] ) && $action_data['checked'] ) {
|
||||
$element_ids[ $item_type ][] = $element_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $type && isset( $element_ids[ $type ] ) ? $element_ids[ $type ] : $element_ids;
|
||||
}
|
||||
|
||||
public static function get_source_language() {
|
||||
self::get_basket();
|
||||
return isset( self::$basket['source_language'] ) ? self::$basket['source_language'] : false;
|
||||
}
|
||||
|
||||
private static function sync_target_languages() {
|
||||
self::get_basket();
|
||||
if ( ! isset( self::$basket['target_languages'] ) ) {
|
||||
self::$basket['target_languages'] = array();
|
||||
}
|
||||
|
||||
$basket_items_types = self::get_basket_items_types();
|
||||
foreach ( $basket_items_types as $item_type_name => $item_type ) {
|
||||
if ( isset( self::$basket[ $item_type_name ] ) ) {
|
||||
$posts_in_basket = self::$basket[ $item_type_name ];
|
||||
foreach ( (array) $posts_in_basket as $post_in_basket ) {
|
||||
foreach ( (array) $post_in_basket['to_langs'] as $key => $target_language ) {
|
||||
if ( $target_language && ! in_array( $key, self::$basket['target_languages'] ) ) {
|
||||
self::$basket['target_languages'] [] = $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|array
|
||||
*/
|
||||
public static function get_target_languages() {
|
||||
self::get_basket();
|
||||
self::sync_target_languages();
|
||||
return isset( self::$basket['target_languages'] ) ? self::$basket['target_languages'] : false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets target languages for remote service
|
||||
*
|
||||
* @param $remote_target_languages
|
||||
*/
|
||||
public static function set_remote_target_languages( $remote_target_languages ) {
|
||||
self::get_basket();
|
||||
self::$basket['remote_target_languages'] = $remote_target_languages;
|
||||
self::update_basket();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get target languages for remote service
|
||||
*
|
||||
* @return array | false
|
||||
*/
|
||||
public static function get_remote_target_languages() {
|
||||
self::get_basket();
|
||||
if ( isset( self::$basket['remote_target_languages'] ) ) {
|
||||
return self::$basket['remote_target_languages'];
|
||||
} else {
|
||||
return self::get_target_languages();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function get_basket_notification_positions() {
|
||||
return array(
|
||||
'admin_notice' => 'basket_status_update',
|
||||
'tm_dashboard_top' => 'translation-basket-notification',
|
||||
'st_dashboard_top' => 'string-translation-top',
|
||||
'st_dashboard_bottom' => 'string-translation-under',
|
||||
);
|
||||
}
|
||||
|
||||
public static function get_basket_extra_fields_section() {
|
||||
$extra_fields = TranslationProxy::get_extra_fields_local();
|
||||
|
||||
$html = '';
|
||||
|
||||
if ( $extra_fields ) {
|
||||
|
||||
$html .= '<h3>3. ' . __( 'Select additional options', 'wpml-translation-management' ) . ' <a href="#" id="basket_extra_fields_refresh">(' . __( 'Refresh', 'wpml-translation-management' ) . ')</a></h3>';
|
||||
|
||||
$html .= '<div id="basket_extra_fields_list">';
|
||||
|
||||
$html .= self::get_basket_extra_fields_inputs( $extra_fields, false );
|
||||
|
||||
$html .= '</div>';
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
public static function get_basket_extra_fields_inputs( array $extra_fields = array(), $force_refresh = false ) {
|
||||
if ( ! $extra_fields ) {
|
||||
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
|
||||
$force_refresh = true;
|
||||
}
|
||||
$extra_fields = self::get_basket_extra_fields_array( $force_refresh );
|
||||
}
|
||||
|
||||
return self::extra_fields_build_inputs( $extra_fields );
|
||||
}
|
||||
|
||||
public static function get_basket_extra_fields_array( $force_refresh = false ) {
|
||||
if ( $force_refresh ) {
|
||||
$networking = wpml_tm_load_tp_networking();
|
||||
$project = TranslationProxy::get_current_project();
|
||||
$extra_fields = $networking->get_extra_fields_remote( $project );
|
||||
TranslationProxy::save_extra_fields( $extra_fields );
|
||||
} else {
|
||||
$extra_fields = TranslationProxy::get_extra_fields_local();
|
||||
}
|
||||
|
||||
return TranslationProxy::maybe_convert_extra_fields( $extra_fields );
|
||||
}
|
||||
|
||||
public static function extra_fields_build_inputs( array $extra_fields ) {
|
||||
if ( ! $extra_fields ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$rows = array();
|
||||
/** @var WPML_TP_Extra_Field $field */
|
||||
$field_diplay = new WPML_TP_Extra_Field_Display();
|
||||
foreach ( $extra_fields as $field ) {
|
||||
$rows[] = $field_diplay->render( $field );
|
||||
}
|
||||
|
||||
$rows = array_filter( $rows );
|
||||
|
||||
$html = '';
|
||||
if ( $rows ) {
|
||||
$html = '<table class="form-table">';
|
||||
$html .= '<tbody>';
|
||||
$html .= implode( PHP_EOL, $rows );
|
||||
$html .= '</tbody>';
|
||||
$html .= '</table>';
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private static function validate_data( $data ) {
|
||||
$data_is_valid = true;
|
||||
if ( self::get_basket() && self::get_source_language() ) {
|
||||
/*
|
||||
we do not add items that are not in the source language of the current basket
|
||||
we cannot yet set its source language though since update_basket would set the basket
|
||||
to false as long as we do not have any elements in the basket*/
|
||||
if ( self::$translate_from != self::get_source_language() ) {
|
||||
self::$messages[] = array(
|
||||
'type' => 'update',
|
||||
'text' => __(
|
||||
'You cannot add posts in this language to the basket since it already contains posts 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-translation-management'
|
||||
),
|
||||
);
|
||||
self::update_basket();
|
||||
|
||||
$data_is_valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
// no language selected ?
|
||||
if ( ! isset( self::$translation_action ) || empty( self::$translation_action ) ) {
|
||||
self::$messages[] = array(
|
||||
'type' => 'error',
|
||||
'text' => __( 'Please select at least one language to translate into.', 'wpml-translation-management' ),
|
||||
);
|
||||
self::$dashboard_select = $data; // pre fill dashboard
|
||||
$data_is_valid = false;
|
||||
}
|
||||
|
||||
if ( $data_is_valid ) {
|
||||
$data_is_valid = false;
|
||||
$basket_items_types = self::get_basket_items_types();
|
||||
// nothing selected ?
|
||||
foreach ( $basket_items_types as $basket_items_type => $basket_type ) {
|
||||
if ( isset( $data[ $basket_items_type ] ) && $data[ $basket_items_type ] ) {
|
||||
$data_is_valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $data_is_valid ) {
|
||||
self::$messages[] = array(
|
||||
'type' => 'error',
|
||||
'text' => __( 'Please select at least one document to translate.', 'wpml-translation-management' ),
|
||||
);
|
||||
self::$dashboard_select = $data; // pre-populate dashboard
|
||||
$data_is_valid = false;
|
||||
|
||||
return $data_is_valid;
|
||||
}
|
||||
|
||||
return $data_is_valid;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
use \WPML\Collect\Support\Traits\Macroable;
|
||||
use function \WPML\FP\curryN;
|
||||
use \WPML\LIB\WP\Cache;
|
||||
use \WPML\FP\Logic;
|
||||
|
||||
/**
|
||||
* Class TranslationProxy_Batch
|
||||
*
|
||||
* @method static callable|int getBatchId( ...$name ) :: string → int
|
||||
*/
|
||||
class TranslationProxy_Batch {
|
||||
|
||||
use Macroable;
|
||||
|
||||
public static function update_translation_batch(
|
||||
$batch_name = false,
|
||||
$tp_id = false
|
||||
) {
|
||||
$batch_name = $batch_name
|
||||
? $batch_name
|
||||
: ( ( (bool) $tp_id === false || $tp_id === 'local' )
|
||||
? self::get_generic_batch_name() : TranslationProxy_Basket::get_basket_name() );
|
||||
if ( ! $batch_name ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$getBatchId = function( $batch_name, $tp_id ) {
|
||||
$batch_id = self::getBatchId( $batch_name );
|
||||
|
||||
return $batch_id ? $batch_id : self::createBatchRecord( $batch_name, $tp_id );
|
||||
};
|
||||
|
||||
$cache = Cache::memorizeWithCheck( 'update_translation_batch', Logic::isNotNull(), $getBatchId );
|
||||
return $cache( $batch_name, $tp_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the name of a generic batch
|
||||
* name is built based on the current's date
|
||||
*
|
||||
* @param bool $isAuto
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_generic_batch_name( $isAuto = false ) {
|
||||
return ( $isAuto ? 'Automatic Translations from ' : 'Manual Translations from ' ) . date( 'F \t\h\e jS\, Y' );
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the id of a generic batch
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private static function create_generic_batch() {
|
||||
$batch_name = self::get_generic_batch_name();
|
||||
$batch_id = self::update_translation_batch( $batch_name );
|
||||
|
||||
return $batch_id;
|
||||
}
|
||||
|
||||
public static function maybe_assign_generic_batch( $data ) {
|
||||
global $wpdb;
|
||||
|
||||
$batch_id = $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
"SELECT batch_id
|
||||
FROM {$wpdb->prefix}icl_translation_status
|
||||
WHERE translation_id=%d",
|
||||
$data['translation_id']
|
||||
)
|
||||
);
|
||||
|
||||
// if the batch id is smaller than 1 we assign the translation to the generic manual translations batch for today if the translation_service is local
|
||||
if ( ( $batch_id < 1 ) && isset( $data ['translation_service'] ) && $data ['translation_service'] == 'local' ) {
|
||||
// first we retrieve the batch id for today's generic translation batch
|
||||
$batch_id = self::create_generic_batch();
|
||||
// then we update the entry in the icl_translation_status table accordingly
|
||||
$data_where = array( 'rid' => $data['rid'] );
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'icl_translation_status',
|
||||
array( 'batch_id' => $batch_id ),
|
||||
$data_where
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $batch_name
|
||||
* @param $tp_id
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private static function createBatchRecord( $batch_name, $tp_id ) {
|
||||
global $wpdb;
|
||||
|
||||
$data = [
|
||||
'batch_name' => $batch_name,
|
||||
'last_update' => date( 'Y-m-d H:i:s' ),
|
||||
];
|
||||
if ( $tp_id ) {
|
||||
$data['tp_id'] = $tp_id === 'local' ? 0 : $tp_id;
|
||||
}
|
||||
$wpdb->insert( $wpdb->prefix . 'icl_translation_batches', $data );
|
||||
|
||||
return $wpdb->insert_id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $batch_name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
TranslationProxy_Batch::macro(
|
||||
'getBatchId',
|
||||
curryN(
|
||||
1,
|
||||
function( $batch_name ) {
|
||||
global $wpdb;
|
||||
|
||||
$batch_id_sql = "SELECT id FROM {$wpdb->prefix}icl_translation_batches WHERE batch_name=%s";
|
||||
$batch_id_prepared = $wpdb->prepare( $batch_id_sql, $batch_name );
|
||||
return $wpdb->get_var( $batch_id_prepared );
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
class TranslationProxy_Popup {
|
||||
|
||||
public static function display() {
|
||||
include_once WPML_TM_PATH . '/inc/translation-proxy/translationproxy-popup.php';
|
||||
exit;
|
||||
}
|
||||
|
||||
public static function get_link( $link, $args = array(), $just_url = false ) {
|
||||
|
||||
$defaults = array(
|
||||
'title' => null,
|
||||
'class' => '',
|
||||
'id' => '',
|
||||
'ar' => 0, // auto_resize
|
||||
'unload_cb' => false, // onunload callback
|
||||
);
|
||||
|
||||
$args = array_merge($defaults, $args);
|
||||
|
||||
/**
|
||||
* @var title string
|
||||
*/
|
||||
$title = $args['title'];
|
||||
/**
|
||||
* @var $class string
|
||||
*/
|
||||
$class = $args['class'];
|
||||
/**
|
||||
* @var $id int
|
||||
*/
|
||||
$id = $args['id'];
|
||||
/**
|
||||
* @var $ar int
|
||||
*/
|
||||
$ar = $args['ar'];
|
||||
/**
|
||||
* @var $unload_cb bool
|
||||
*/
|
||||
$unload_cb = $args['unload_cb'];
|
||||
|
||||
if ( !empty( $ar ) ) {
|
||||
$auto_resize = '&auto_resize=1';
|
||||
} else {
|
||||
$auto_resize = '';
|
||||
}
|
||||
|
||||
$unload_cb = isset( $unload_cb ) ? '&unload_cb=' . $unload_cb : '';
|
||||
|
||||
$url_glue = false !== strpos( $link, '?' ) ? '&' : '?';
|
||||
$link .= $url_glue . 'compact=1';
|
||||
|
||||
$nonce_snippet = '&_icl_nonce=' . wp_create_nonce( 'reminder_popup_nonce' );
|
||||
$action_and_nonce = 'admin.php?page=' . ICL_PLUGIN_FOLDER
|
||||
. "/menu/languages.php&icl_action=reminder_popup{$nonce_snippet}{$auto_resize}{$unload_cb}"
|
||||
. "&target=" . urlencode( $link );
|
||||
if ( ! empty( $id ) ) {
|
||||
$id = ' id="' . $id . '"';
|
||||
}
|
||||
if ( ! $just_url ) {
|
||||
return '<a class="icl_thickbox ' . $class . '" title="' . $title . '" href="' . $action_and_nonce . '"' . $id . '>';
|
||||
} else {
|
||||
if ( ! $just_url ) {
|
||||
return '<a class="icl_thickbox ' . $class . '" href="' . $action_and_nonce . '"' . $id . '>';
|
||||
} else {
|
||||
return $action_and_nonce;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
define( 'ICL_LANGUAGE_NOT_SUPPORTED', 3 );
|
||||
global $wpdb, $sitepress;
|
||||
|
||||
$target = filter_input( INPUT_GET, 'target', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
|
||||
$auto_resize = filter_input( INPUT_GET, 'auto_resize', FILTER_VALIDATE_BOOLEAN | FILTER_NULL_ON_FAILURE );
|
||||
$unload_cb = filter_input( INPUT_GET, 'unload_cb', FILTER_SANITIZE_FULL_SPECIAL_CHARS | FILTER_NULL_ON_FAILURE );
|
||||
|
||||
// Adding a translator
|
||||
if ( preg_match( '|^@select-translators;([^;]+);([^;]+)@|', $target, $matches ) ) {
|
||||
$source_language = $matches[1];
|
||||
$target_language = $matches[2];
|
||||
$project = TranslationProxy::get_current_project();
|
||||
try {
|
||||
$lp_setting_index = 'language_pairs';
|
||||
$language_pairs = $sitepress->get_setting( $lp_setting_index, array() );
|
||||
if ( ! isset( $language_pairs[ $source_language ][ $target_language ] ) || $language_pairs[ $source_language ][ $target_language ] == 0 ) {
|
||||
$language_pairs[ $source_language ][ $target_language ] = 1;
|
||||
TranslationProxy_Translator::update_language_pairs( $project, $language_pairs );
|
||||
$sitepress->set_setting( $lp_setting_index, $language_pairs, true );
|
||||
}
|
||||
$target = $project->select_translator_iframe_url( $source_language, $target_language );
|
||||
} catch ( Exception $e ) {
|
||||
if ( $e->getCode() == ICL_LANGUAGE_NOT_SUPPORTED ) {
|
||||
printf( __( '<p>Requested languages are not supported by the translation service (%s). Please <a%s>contact us</a> for support. </p>', 'wpml-translation-management' ), $e->getMessage(), ' target="_blank" href="http://wpml.org/?page_id=5255"' );
|
||||
} else {
|
||||
printf( __( '<p>Could not add the requested languages. Please <a%s>contact us</a> for support. </p><p>Show <a%s>debug information</a>.</p>', 'wpml-translation-management' ), ' target="_blank" href="http://wpml.org/?page_id=5255"',
|
||||
' a href="admin.php?page=' .
|
||||
ICL_PLUGIN_FOLDER .
|
||||
'/menu/troubleshooting.php&icl_action=icl-connection-test' .
|
||||
'#icl-connection-test"' );
|
||||
}
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
$target .= ( strpos( $target, '?' ) === false ) ? '?' : '&';
|
||||
$target .= "lc=" . $sitepress->get_admin_language();
|
||||
?>
|
||||
|
||||
<iframe src="<?php echo $target; ?>" style="width:100%; height:92%" onload=" var TB_window = jQuery('#TB_window');
|
||||
<?php if ( $auto_resize ): ?>
|
||||
TB_window.css('width','90%').css('margin-left', '-45%');
|
||||
<?php endif; ?>
|
||||
<?php if ( $unload_cb ){
|
||||
$unload_cb = esc_js($unload_cb);
|
||||
?>
|
||||
TB_window.unbind('unload').bind('tb_unload', function(){<?php echo $unload_cb; ?>});
|
||||
<?php } ?>
|
||||
">
|
||||
@@ -0,0 +1,513 @@
|
||||
<?php
|
||||
/**
|
||||
* @package wpml-core
|
||||
* @subpackage wpml-core
|
||||
*/
|
||||
|
||||
if( class_exists( 'TranslationProxy_Project' ) ) {
|
||||
// Workaround for UnitTests.
|
||||
return;
|
||||
}
|
||||
|
||||
require_once dirname( __FILE__ ) . '/translationproxy-api.class.php';
|
||||
require_once dirname( __FILE__ ) . '/translationproxy-service.class.php';
|
||||
require_once dirname( __FILE__ ) . '/translationproxy-batch.class.php';
|
||||
|
||||
/**
|
||||
* Class TranslationProxy_Project
|
||||
*/
|
||||
class TranslationProxy_Project {
|
||||
|
||||
public $id;
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* `access_key` used when sending **any request** to TP
|
||||
*/
|
||||
public $access_key;
|
||||
/**
|
||||
* @var int
|
||||
*
|
||||
* `ts_id` (aka `website_id`) is used **exclusively** when sending request directly to ICL
|
||||
*/
|
||||
public $ts_id;
|
||||
/**
|
||||
* @var string
|
||||
*
|
||||
* `ts_access_key` is used **exclusively** when sending request directly to ICL
|
||||
*/
|
||||
public $ts_access_key;
|
||||
|
||||
/**
|
||||
* @var object
|
||||
*/
|
||||
public $service;
|
||||
|
||||
/** @var WPML_TP_Client $tp_client */
|
||||
public $tp_client;
|
||||
|
||||
public $errors = array();
|
||||
|
||||
/**
|
||||
* @param TranslationProxy_Service $service
|
||||
* @param string $delivery
|
||||
* @param WPML_TP_Client $tp_client
|
||||
*/
|
||||
public function __construct( $service, $delivery, WPML_TP_Client $tp_client ) {
|
||||
$this->service = $service;
|
||||
$this->tp_client = $tp_client;
|
||||
|
||||
$icl_translation_projects = TranslationProxy::get_translation_projects();
|
||||
$project_index = self::generate_service_index( $service );
|
||||
|
||||
if ( $project_index && $icl_translation_projects && isset( $icl_translation_projects [ $project_index ] ) ) {
|
||||
$project = $icl_translation_projects[ $project_index ];
|
||||
$this->id = $project['id'];
|
||||
$this->access_key = $project['access_key'];
|
||||
$this->ts_id = $project['ts_id'];
|
||||
$this->ts_access_key = $project['ts_access_key'];
|
||||
|
||||
$this->service->delivery_method = $delivery;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return TranslationProxy_Service
|
||||
*/
|
||||
public function service() {
|
||||
|
||||
return $this->service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index by which a translation service can be found in the array returned by
|
||||
* \TranslationProxy::get_translation_projects
|
||||
*
|
||||
* @param $service object
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public static function generate_service_index( $service ) {
|
||||
$index = false;
|
||||
if ( $service ) {
|
||||
$service->custom_fields_data = isset( $service->custom_fields_data ) ? $service->custom_fields_data : array();
|
||||
if ( isset( $service->id ) ) {
|
||||
$index = md5( $service->id . serialize( $service->custom_fields_data ) );
|
||||
}
|
||||
}
|
||||
|
||||
return $index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert WPML language code to service language
|
||||
*
|
||||
* @param $language string
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
private function service_language( $language ) {
|
||||
return TranslationProxy_Service::get_language( $this->service, $language );
|
||||
}
|
||||
|
||||
/*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Get information about the project (Translation Service)
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
public function custom_text( $location, $locale = 'en' ) {
|
||||
$response = '';
|
||||
if ( ! $this->ts_id || ! $this->ts_access_key ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Sending Translation Service (ts_) id and access_key, as we are talking directly to the Translation Service
|
||||
// Todo: use project->id and project->access_key once this call is moved to TP
|
||||
$params = array(
|
||||
'project_id' => $this->ts_id,
|
||||
'accesskey' => $this->ts_access_key,
|
||||
'location' => $location,
|
||||
'lc' => $locale,
|
||||
);
|
||||
|
||||
if ( $this->service->custom_text_url ) {
|
||||
try {
|
||||
$response = TranslationProxy_Api::service_request(
|
||||
$this->service->custom_text_url,
|
||||
$params,
|
||||
'GET',
|
||||
true,
|
||||
true,
|
||||
true
|
||||
);
|
||||
} catch ( Exception $e ) {
|
||||
throw new RuntimeException(
|
||||
'error getting custom text from Translation Service: ' . serialize( $params ) . ' url: ' . $this->service->custom_text_url,
|
||||
0,
|
||||
$e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
function current_service_name() {
|
||||
|
||||
return TranslationProxy::get_current_service_name();
|
||||
}
|
||||
|
||||
function current_service() {
|
||||
return TranslationProxy::get_current_service();
|
||||
}
|
||||
|
||||
/*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* IFrames to display project info (Translation Service)
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
public function select_translator_iframe_url( $source_language, $target_language ) {
|
||||
// Sending Translation Service (ts_) id and access_key, as we are talking directly to the Translation Service
|
||||
$params['project_id'] = $this->ts_id;
|
||||
$params['accesskey'] = $this->ts_access_key;
|
||||
$params['source_language'] = $this->service_language( $source_language );
|
||||
$params['target_language'] = $this->service_language( $target_language );
|
||||
$params['compact'] = 1;
|
||||
|
||||
return $this->_create_iframe_url( $this->service->select_translator_iframe_url, $params );
|
||||
}
|
||||
|
||||
public function translator_contact_iframe_url( $translator_id ) {
|
||||
// Sending Translation Service (ts_) id and access_key, as we are talking directly to the Translation Service
|
||||
$params['project_id'] = $this->ts_id;
|
||||
$params['accesskey'] = $this->ts_access_key;
|
||||
$params['translator_id'] = $translator_id;
|
||||
$params['compact'] = 1;
|
||||
if ( $this->service->translator_contact_iframe_url ) {
|
||||
return $this->_create_iframe_url( $this->service->translator_contact_iframe_url, $params );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function _create_iframe_url( $url, $params ) {
|
||||
if ( $params ) {
|
||||
$url = TranslationProxy_Api::add_parameters_to_url( $url, $params );
|
||||
$url .= '?' . http_build_query( $params );
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Jobs handling (Translation Proxy)
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
/**
|
||||
* @throws WPML_TP_Batch_Exception
|
||||
*
|
||||
* @param bool $source_language
|
||||
* @param bool $target_languages
|
||||
*
|
||||
* @internal param bool $name
|
||||
* @return false|WPML_TP_Batch
|
||||
*/
|
||||
function get_batch_job(
|
||||
$source_language = false,
|
||||
$target_languages = false
|
||||
) {
|
||||
$batch_data = TranslationProxy_Basket::get_batch_data();
|
||||
|
||||
if ( ! $batch_data ) {
|
||||
if ( ! $source_language ) {
|
||||
$source_language = TranslationProxy_Basket::get_source_language();
|
||||
}
|
||||
if ( ! $target_languages ) {
|
||||
$target_languages = TranslationProxy_Basket::get_remote_target_languages();
|
||||
}
|
||||
|
||||
if ( ! $source_language || ! $target_languages ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$batch_data = $this->create_batch_job( $source_language, $target_languages );
|
||||
|
||||
if ( $batch_data ) {
|
||||
TranslationProxy_Basket::set_batch_data( $batch_data );
|
||||
}
|
||||
}
|
||||
|
||||
return $batch_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws WPML_TP_Batch_Exception
|
||||
*
|
||||
* @return false|int
|
||||
*/
|
||||
function get_batch_job_id() {
|
||||
$ret = false;
|
||||
$batch_data = $this->get_batch_job();
|
||||
|
||||
if ( $batch_data ) {
|
||||
$ret = $batch_data->get_id();
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws WPML_TP_Batch_Exception
|
||||
*
|
||||
* @param bool $source_language
|
||||
* @param $target_languages
|
||||
*
|
||||
* @internal param bool $name
|
||||
* @return false|WPML_TP_Batch
|
||||
*/
|
||||
public function create_batch_job( $source_language, $target_languages ) {
|
||||
$batch_name = TranslationProxy_Basket::get_basket_name();
|
||||
$batch_options = TranslationProxy_Basket::get_options();
|
||||
$extra_fields = TranslationProxy_Basket::get_basket_extra_fields();
|
||||
|
||||
$batch_data = array(
|
||||
'source_language' => $source_language,
|
||||
'target_languages' => $target_languages,
|
||||
'name' => $batch_name,
|
||||
);
|
||||
|
||||
if ( ! $batch_data['source_language'] ) {
|
||||
$batch_data['source_language'] = TranslationProxy_Basket::get_source_language();
|
||||
}
|
||||
|
||||
if ( ! $batch_data['target_languages'] ) {
|
||||
$batch_data['target_languages'] = TranslationProxy_Basket::get_remote_target_languages();
|
||||
}
|
||||
|
||||
if ( ! $batch_data['source_language'] || ! $batch_data['target_languages'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! $batch_data['name'] ) {
|
||||
$batch_data['name'] = sprintf(
|
||||
__(
|
||||
'%s: WPML Translation Jobs',
|
||||
'wpml-translation-management'
|
||||
),
|
||||
get_option( 'blogname' )
|
||||
);
|
||||
}
|
||||
|
||||
TranslationProxy_Basket::set_basket_name( $batch_data['name'] );
|
||||
|
||||
if ( isset( $batch_options['deadline_date'] ) ) {
|
||||
$batch_data['deadline'] = strtotime( $batch_options['deadline_date'] );
|
||||
}
|
||||
|
||||
return $this->tp_client->batches()->create( $batch_data, $extra_fields );
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Add Files Batch Job
|
||||
*
|
||||
* @throws WPML_TP_Batch_Exception
|
||||
*
|
||||
* @param string $file
|
||||
* @param string $title
|
||||
* @param string $cms_id
|
||||
* @param string $url
|
||||
* @param string $source_language
|
||||
* @param string $target_language
|
||||
* @param int $word_count
|
||||
* @param int $translator_id
|
||||
* @param string $note
|
||||
*
|
||||
* @return bool|int
|
||||
*/
|
||||
public function send_to_translation_batch_mode(
|
||||
$file,
|
||||
$title,
|
||||
$cms_id,
|
||||
$url,
|
||||
$source_language,
|
||||
$target_language,
|
||||
$word_count,
|
||||
$translator_id = 0,
|
||||
$note = '',
|
||||
$uuid = null
|
||||
) {
|
||||
|
||||
$batch_id = $this->get_batch_job_id();
|
||||
|
||||
if ( ! $batch_id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$job_data = array(
|
||||
'file' => $file,
|
||||
'word_count' => $word_count,
|
||||
'title' => $title,
|
||||
'cms_id' => $cms_id,
|
||||
'udid' => $uuid,
|
||||
'url' => $url,
|
||||
'translator_id' => $translator_id,
|
||||
'note' => $note,
|
||||
'source_language' => $source_language,
|
||||
'target_language' => $target_language,
|
||||
);
|
||||
|
||||
$tp_job = $this->tp_client->batches()->add_job( $batch_id, $job_data );
|
||||
|
||||
return $tp_job ? $tp_job->get_id() : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool|int $tp_batch_id
|
||||
*
|
||||
* @link http://git.icanlocalize.com/onthego/translation_proxy/wikis/commit_batch_job
|
||||
*
|
||||
* @return array|bool|mixed|null|stdClass|string
|
||||
*/
|
||||
function commit_batch_job( $tp_batch_id = false ) {
|
||||
$tp_batch_id = $tp_batch_id ? $tp_batch_id : $this->get_batch_job_id();
|
||||
|
||||
if ( ! $tp_batch_id ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$params = array(
|
||||
'api_version' => TranslationProxy_Api::API_VERSION,
|
||||
'project_id' => $this->id,
|
||||
'accesskey' => $this->access_key,
|
||||
'batch_id' => $tp_batch_id,
|
||||
);
|
||||
|
||||
$response = TranslationProxy_Api::proxy_request( '/batches/{batch_id}/commit.json', $params, 'PUT', false );
|
||||
$basket_name = TranslationProxy_Basket::get_basket_name();
|
||||
if ( $basket_name ) {
|
||||
global $wpdb;
|
||||
|
||||
$batch_id_sql = "SELECT id FROM {$wpdb->prefix}icl_translation_batches WHERE batch_name=%s";
|
||||
$batch_id_prepared = $wpdb->prepare(
|
||||
$batch_id_sql,
|
||||
array( $basket_name )
|
||||
);
|
||||
$batch_id = $wpdb->get_var( $batch_id_prepared );
|
||||
|
||||
$batch_data = array(
|
||||
'batch_name' => $basket_name,
|
||||
'tp_id' => $tp_batch_id,
|
||||
'last_update' => date( 'Y-m-d H:i:s' ),
|
||||
);
|
||||
if ( isset( $response ) && $response ) {
|
||||
$batch_data['ts_url'] = serialize( $response );
|
||||
}
|
||||
|
||||
if ( ! $batch_id ) {
|
||||
$wpdb->insert(
|
||||
$wpdb->prefix . 'icl_translation_batches',
|
||||
$batch_data
|
||||
);
|
||||
} else {
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'icl_translation_batches',
|
||||
$batch_data,
|
||||
array( 'id' => $batch_id )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return isset( $response ) ? $response : false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return object[]
|
||||
*/
|
||||
public function jobs() {
|
||||
|
||||
return $this->get_jobs( 'any' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return object[]
|
||||
*/
|
||||
public function finished_jobs() {
|
||||
|
||||
return $this->get_jobs( 'translation_ready' );
|
||||
}
|
||||
|
||||
public function set_delivery_method( $method ) {
|
||||
$params = array(
|
||||
'project_id' => $this->id,
|
||||
'accesskey' => $this->access_key,
|
||||
'project' => array( 'delivery_method' => $method ),
|
||||
);
|
||||
TranslationProxy_Api::proxy_request( '/projects.json', $params, 'put' );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function fetch_translation( $job_id ) {
|
||||
$params = array(
|
||||
'project_id' => $this->id,
|
||||
'accesskey' => $this->access_key,
|
||||
'job_id' => $job_id,
|
||||
);
|
||||
|
||||
return TranslationProxy_Api::proxy_download(
|
||||
'/jobs/{job_id}/xliff.json',
|
||||
$params
|
||||
);
|
||||
}
|
||||
|
||||
public function update_job( $job_id, $url = null, $state = 'delivered' ) {
|
||||
$params = array(
|
||||
'job_id' => $job_id,
|
||||
'project_id' => $this->id,
|
||||
'accesskey' => $this->access_key,
|
||||
'job' => array(
|
||||
'state' => $state,
|
||||
),
|
||||
);
|
||||
if ( $url ) {
|
||||
$params['job']['url'] = $url;
|
||||
}
|
||||
|
||||
TranslationProxy_Api::proxy_request(
|
||||
'/jobs/{job_id}.json',
|
||||
$params,
|
||||
'PUT'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $state
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function get_jobs( $state = 'any' ) {
|
||||
$batch = TranslationProxy_Basket::get_batch_data();
|
||||
|
||||
$params = array(
|
||||
'project_id' => $this->id,
|
||||
'accesskey' => $this->access_key,
|
||||
'state' => $state,
|
||||
);
|
||||
|
||||
if ( $batch ) {
|
||||
$params['batch_id'] = $batch ? $batch->get_id() : false;
|
||||
|
||||
return TranslationProxy_Api::proxy_request(
|
||||
'/batches/{batch_id}/jobs.json',
|
||||
$params
|
||||
);
|
||||
} else {
|
||||
// FIXME: remove this once TP will accept the TP Project ID: https://icanlocalize.basecamphq.com/projects/11113143-translation-proxy/todo_items/182251206/comments
|
||||
$params['project_id'] = $this->id;
|
||||
}
|
||||
|
||||
return TranslationProxy_Api::proxy_request( '/jobs.json', $params );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
/**
|
||||
* @package wpml-core
|
||||
* @subpackage wpml-core
|
||||
*/
|
||||
|
||||
require_once dirname( __FILE__ ) . '/translationproxy-api.class.php';
|
||||
|
||||
class TranslationProxy_Service {
|
||||
|
||||
public $id;
|
||||
public $name;
|
||||
public $description;
|
||||
public $default_service;
|
||||
public $has_translator_selection = true; // Todo: read this from service properties
|
||||
public $delivery_method;
|
||||
public $project_details_url;
|
||||
public $custom_text_url;
|
||||
public $has_language_pairs;
|
||||
public $languages_map;
|
||||
public $url;
|
||||
public $logo_url;
|
||||
public $create_project_url;
|
||||
public $add_language_pair_url;
|
||||
public $new_job_url;
|
||||
public $custom_fields;
|
||||
public $custom_fields_data;
|
||||
public $select_translator_iframe_url;
|
||||
public $translator_contact_iframe_url;
|
||||
public $quote_iframe_url;
|
||||
public $batch_name_max_length;
|
||||
|
||||
public static function is_authenticated( $service ) {
|
||||
|
||||
// for services that do not require authentication return true by default
|
||||
if ( ! TranslationProxy::service_requires_authentication( $service ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return isset( $service->custom_fields_data ) && $service->custom_fields_data ? true : false;
|
||||
}
|
||||
|
||||
public static function list_services() {
|
||||
return TranslationProxy_Api::proxy_request( '/services.json' );
|
||||
}
|
||||
|
||||
public static function get_service( $service_id ) {
|
||||
$service = TranslationProxy_Api::proxy_request( "/services/$service_id.json" );
|
||||
$service->languages_map = self::languages_map( $service );
|
||||
|
||||
return $service;
|
||||
}
|
||||
|
||||
public static function get_service_by_suid( $suid ) {
|
||||
$service = TranslationProxy_Api::proxy_request( "/services/$suid.json" );
|
||||
$service->languages_map = self::languages_map( $service );
|
||||
|
||||
return $service;
|
||||
}
|
||||
|
||||
public static function languages_map( $service ) {
|
||||
$languages_map = array();
|
||||
$languages = TranslationProxy_Api::proxy_request( "/services/{$service->id}/language_identifiers.json" );
|
||||
foreach ( $languages as $language ) {
|
||||
$languages_map[ $language->iso_code ] = $language->value;
|
||||
}
|
||||
|
||||
return $languages_map;
|
||||
}
|
||||
|
||||
public static function get_language( $service, $language ) {
|
||||
if ( ! empty( $service->languages_map ) and array_key_exists( $language, $service->languages_map ) ) {
|
||||
$language = $service->languages_map[ $language ];
|
||||
}
|
||||
|
||||
return $language;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a WPML readable string that allows to tell translation service and translator id
|
||||
* (typically used for translators dropdowns)
|
||||
*
|
||||
* @param int|bool $translation_service_id
|
||||
* @param int|bool $translator_id
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_wpml_translator_id( $translation_service_id = false, $translator_id = false ) {
|
||||
if ( $translation_service_id === false ) {
|
||||
$translation_service_id = TranslationProxy::get_current_service_id();
|
||||
}
|
||||
$result = 'ts-' . $translation_service_id;
|
||||
if ( $translator_id !== false ) {
|
||||
$result .= '-' . $translator_id;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $translator_id
|
||||
*
|
||||
* @return array Returns a two elements array, respectively containing translation_service and translator_id
|
||||
*/
|
||||
public static function get_translator_data_from_wpml( $translator_id ) {
|
||||
$result = array();
|
||||
if ( is_numeric( $translator_id ) ) {
|
||||
$result['translation_service'] = 'local';
|
||||
$result['translator_id'] = $translator_id;
|
||||
} else {
|
||||
$translator_data = explode( '-', $translator_id );
|
||||
$result = array();
|
||||
$result['translation_service'] = $translator_data[1];
|
||||
$result['translator_id'] = isset( $translator_data[2] ) ? $translator_data[2] : 0;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
<?php
|
||||
|
||||
class TranslationProxy_Translator {
|
||||
/**
|
||||
* Get information about translators from current project. Works only for ICL as a Translation Service
|
||||
*
|
||||
* @param bool $force
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
public static function get_icl_translator_status( $force = false ) {
|
||||
/** @var SitePress $sitepress */
|
||||
/** @var WPML_Pro_Translation $ICL_Pro_Translation */
|
||||
global $sitepress, $ICL_Pro_Translation;
|
||||
|
||||
if ( ! $ICL_Pro_Translation ) {
|
||||
$job_factory = wpml_tm_load_job_factory();
|
||||
$ICL_Pro_Translation = new WPML_Pro_Translation( $job_factory );
|
||||
}
|
||||
|
||||
if ( ! TranslationProxy::translator_selection_available() ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$project = TranslationProxy::get_current_project();
|
||||
|
||||
if ( ! $project ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$cache_key = md5( serialize( $project ) );
|
||||
$cache_group = 'get_icl_translator_status';
|
||||
|
||||
$found = false;
|
||||
$result = wp_cache_get( $cache_key, $cache_group, false, $found );
|
||||
|
||||
if ( $found ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$translator_status = array();
|
||||
$website_details = self::get_website_details(
|
||||
new TranslationProxy_Project( TranslationProxy::get_current_service(), 'xmlrpc', TranslationProxy::get_tp_client() ),
|
||||
$force
|
||||
);
|
||||
|
||||
if ( false === (bool) $website_details ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$language_pairs = array();
|
||||
if ( isset( $website_details['translation_languages']['translation_language'] ) ) {
|
||||
|
||||
$translation_languages = $website_details['translation_languages']['translation_language'];
|
||||
if ( ! isset( $translation_languages[0] ) ) {
|
||||
$buf = $translation_languages;
|
||||
$translation_languages = array( 0 => $buf );
|
||||
}
|
||||
|
||||
foreach ( $translation_languages as $lang ) {
|
||||
$translators = $_tr = array();
|
||||
$max_rate = false;
|
||||
if ( isset( $lang['translators'], $lang['translators']['translator'] ) && ! empty( $lang['translators'] ) ) {
|
||||
if ( ! isset( $lang['translators']['translator'][0] ) ) {
|
||||
$_tr[0] = $lang['translators']['translator'];
|
||||
} else {
|
||||
$_tr = $lang['translators']['translator'];
|
||||
}
|
||||
foreach ( $_tr as $t ) {
|
||||
if ( false === $max_rate || $t['attr']['amount'] > $max_rate ) {
|
||||
$max_rate = $t['attr']['amount'];
|
||||
}
|
||||
$translators[] = array(
|
||||
'id' => $t['attr']['id'],
|
||||
'nickname' => $t['attr']['nickname'],
|
||||
'contract_id' => $t['attr']['contract_id'],
|
||||
);
|
||||
}
|
||||
}
|
||||
$language_pairs[] = array(
|
||||
'from' => $sitepress->get_language_code( $ICL_Pro_Translation->server_languages_map( $lang['attr']['from_language_name'], true ) ),
|
||||
'to' => $sitepress->get_language_code( $ICL_Pro_Translation->server_languages_map( $lang['attr']['to_language_name'], true ) ),
|
||||
'have_translators' => $lang['attr']['have_translators'],
|
||||
'available_translators' => $lang['attr']['available_translators'],
|
||||
'applications' => $lang['attr']['applications'],
|
||||
'contract_id' => $lang['attr']['contract_id'],
|
||||
'id' => $lang['attr']['id'],
|
||||
'translators' => $translators,
|
||||
'max_rate' => $max_rate,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$translator_status['icl_lang_status'] = $language_pairs;
|
||||
|
||||
$translator_status['icl_support_ticket_id'] = null;
|
||||
|
||||
wp_cache_set( $cache_key, $translator_status, $cache_group );
|
||||
|
||||
return $translator_status;
|
||||
}
|
||||
|
||||
private static function get_popup_link( $matches ) {
|
||||
global $sitepress;
|
||||
|
||||
return TranslationProxy_Popup::get_link( $matches[2] );
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Get information about language pairs (including translators). Works only for ICL as a Translation Service
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_language_pairs() {
|
||||
global $sitepress;
|
||||
|
||||
$icl_lang_status = $sitepress->get_setting( 'icl_lang_status', array() );
|
||||
if ( ! empty( $icl_lang_status ) ) {
|
||||
$missing_translators = false;
|
||||
foreach ( $icl_lang_status as $lang ) {
|
||||
if ( empty( $lang['translators'] ) ) {
|
||||
$missing_translators = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( ! $missing_translators ) {
|
||||
$icl_lang_sub_status = $icl_lang_status;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! isset( $icl_lang_sub_status ) ) {
|
||||
$translator_status = self::get_icl_translator_status();
|
||||
$icl_lang_sub_status = isset( $translator_status['icl_lang_status'] )
|
||||
? $translator_status['icl_lang_status'] : array();
|
||||
}
|
||||
foreach ( $icl_lang_sub_status as $key => $status ) {
|
||||
if ( ! isset( $status['from'] ) ) {
|
||||
unset( $icl_lang_sub_status[ $key ] );
|
||||
}
|
||||
}
|
||||
array_filter( $icl_lang_sub_status );
|
||||
|
||||
return $icl_lang_sub_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends request to ICL to get website details (including language pairs)
|
||||
*
|
||||
* @param TranslationProxy_Project $project
|
||||
* @param bool $force
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function get_website_details( $project, $force = false ) {
|
||||
|
||||
require_once ICL_PLUGIN_PATH . '/inc/utilities/xml2array.php';
|
||||
require_once ICL_PLUGIN_PATH . '/lib/icl_api.php';
|
||||
|
||||
$site_id = $project->ts_id;
|
||||
$access_key = $project->ts_access_key;
|
||||
|
||||
$default = array();
|
||||
|
||||
if ( ! $site_id ) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
$icl_query = new ICanLocalizeQuery( $site_id, $access_key );
|
||||
|
||||
return $icl_query->get_website_details( $force );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $translator_id
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public static function get_translator_name( $translator_id ) {
|
||||
if ( TranslationProxy::translator_selection_available() ) {
|
||||
$lang_status = self::get_language_pairs();
|
||||
if ( $lang_status ) {
|
||||
foreach ( $lang_status as $lp ) {
|
||||
$lp_trans = ! empty( $lp['translators'] ) ? $lp['translators'] : array();
|
||||
foreach ( $lp_trans as $tr ) {
|
||||
$translators[ $tr['id'] ] = $tr['nickname'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return isset( $translators[ $translator_id ] ) ? $translators[ $translator_id ] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronizes language pairs with ICL
|
||||
*
|
||||
* @global object $sitepress
|
||||
*
|
||||
* @param $project
|
||||
* @param $language_pairs
|
||||
*/
|
||||
public static function update_language_pairs( $project, $language_pairs ) {
|
||||
/** @var WPML_Pro_Translation $ICL_Pro_Translation */
|
||||
global $sitepress, $ICL_Pro_Translation;
|
||||
|
||||
$params = array(
|
||||
'site_id' => $project->ts_id,
|
||||
'accesskey' => $project->ts_access_key,
|
||||
'create_account' => 0,
|
||||
);
|
||||
|
||||
$lang_server = array();
|
||||
foreach ( $sitepress->get_active_languages() as $lang ) {
|
||||
$lang_server[ $lang['code'] ] = $ICL_Pro_Translation->server_languages_map( $lang['english_name'] );
|
||||
}
|
||||
|
||||
// update account - add language pair
|
||||
$incr = 0;
|
||||
foreach ( $language_pairs as $k => $v ) {
|
||||
if ( ! array_key_exists( $k, $lang_server ) ) {
|
||||
unset( $language_pairs[ $k ] );
|
||||
continue;
|
||||
}
|
||||
foreach ( $v as $k2 => $v2 ) {
|
||||
if ( ! array_key_exists( $k2, $lang_server ) ) {
|
||||
unset( $language_pairs[ $k ][ $k2 ] );
|
||||
if ( (bool) $language_pairs[ $k ] === false ) {
|
||||
unset( $language_pairs[ $k ] );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
$incr ++;
|
||||
$params[ 'from_language' . $incr ] = $lang_server[ $k ];
|
||||
$params[ 'to_language' . $incr ] = $lang_server[ $k2 ];
|
||||
}
|
||||
}
|
||||
|
||||
require_once ICL_PLUGIN_PATH . '/inc/utilities/xml2array.php';
|
||||
require_once ICL_PLUGIN_PATH . '/lib/icl_api.php';
|
||||
$icl_query = new ICanLocalizeQuery();
|
||||
$icl_query->updateAccount( $params );
|
||||
}
|
||||
|
||||
public static function flush_website_details_cache() {
|
||||
delete_transient( WEBSITE_DETAILS_TRANSIENT_KEY );
|
||||
}
|
||||
|
||||
public static function flush_website_details_cache_action() {
|
||||
$nonce = array_key_exists( 'nonce', $_POST ) ? $_POST['nonce'] : null;
|
||||
$action = array_key_exists( 'action', $_POST ) ? $_POST['action'] : null;
|
||||
$nonce_is_valid = wp_verify_nonce( $nonce, $action );
|
||||
|
||||
if ( $nonce_is_valid ) {
|
||||
self::flush_website_details_cache();
|
||||
$query_args = array(
|
||||
'page' => urlencode( WPML_TM_FOLDER . '/menu/main.php' ),
|
||||
'sm' => urlencode( 'translators' ),
|
||||
);
|
||||
$link_url = add_query_arg( $query_args, get_admin_url( null, 'admin.php' ) );
|
||||
wp_send_json_success( array( 'redirectTo' => $link_url ) );
|
||||
} else {
|
||||
wp_send_json_error( 'Nonce is not valid.' );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,671 @@
|
||||
<?php
|
||||
/**
|
||||
* @package wpml-core
|
||||
* @subpackage wpml-core
|
||||
*/
|
||||
|
||||
use WPML\TM\TranslationProxy\Services\AuthorizationFactory;
|
||||
use WPML\FP\Obj;
|
||||
|
||||
require_once WPML_TM_PATH . '/inc/translation-proxy/functions.php';
|
||||
require_once WPML_TM_PATH . '/inc/translation-proxy/translationproxy-basket.class.php';
|
||||
require_once WPML_TM_PATH . '/inc/translation-proxy/translationproxy-api.class.php';
|
||||
require_once WPML_TM_PATH . '/inc/translation-proxy/translationproxy-project.class.php';
|
||||
require_once WPML_TM_PATH . '/inc/translation-proxy/translationproxy-service.class.php';
|
||||
require_once WPML_TM_PATH . '/inc/translation-proxy/translationproxy-popup.class.php';
|
||||
require_once WPML_TM_PATH . '/inc/translation-proxy/translationproxy-translator.class.php';
|
||||
|
||||
define( 'CUSTOM_TEXT_MAX_LENGTH', 1000 );
|
||||
|
||||
class TranslationProxy {
|
||||
private static $tp_client;
|
||||
|
||||
/**
|
||||
* @param bool $reload
|
||||
*
|
||||
* @return WPML_TP_Service[]
|
||||
*/
|
||||
public static function services( $reload = true ) {
|
||||
return self::get_tp_client()->services()->get_all( $reload );
|
||||
}
|
||||
|
||||
public static function get_tp_default_suid() {
|
||||
if ( defined( 'WPML_TP_DEFAULT_SUID' ) ) {
|
||||
return WPML_TP_DEFAULT_SUID;
|
||||
}
|
||||
|
||||
return self::get_preferred_translation_service() ?: false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $suid
|
||||
* @return 'wpml_list'|'config'|'account'
|
||||
*/
|
||||
public static function get_service_linked_by_suid( $suid ) {
|
||||
if ( defined( 'WPML_TP_DEFAULT_SUID' ) && WPML_TP_DEFAULT_SUID === $suid ) {
|
||||
return 'config';
|
||||
}
|
||||
if ( self::get_preferred_translation_service() === $suid ) {
|
||||
return 'account';
|
||||
}
|
||||
return 'wpml_list';
|
||||
}
|
||||
|
||||
public static function has_preferred_translation_service() {
|
||||
return self::get_tp_default_suid() !== false;
|
||||
}
|
||||
|
||||
public static function clear_preferred_translation_service() {
|
||||
WP_Installer_API::set_preferred_ts( 'clear' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $service_id
|
||||
*
|
||||
* @return stdClass
|
||||
*/
|
||||
public static function get_service( $service_id ) {
|
||||
// @todo: implement usage of WPML_TP_Service for the active service
|
||||
return (object) (array) self::get_tp_client()->services()->get_service( $service_id, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $service_id
|
||||
*
|
||||
* @return TranslationProxy_Project|WP_Error
|
||||
* @throws \WPMLTranslationProxyApiException
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public static function select_service( $service_id, $credentials = null ) {
|
||||
global $sitepress;
|
||||
|
||||
$service_selected = false;
|
||||
$error = false;
|
||||
|
||||
/** @var TranslationProxy_Service $service */
|
||||
$service = self::get_service( $service_id );
|
||||
|
||||
if ( $service ) {
|
||||
self::deselect_active_service();
|
||||
|
||||
$service = self::build_and_store_active_translation_service( $service, $credentials );
|
||||
$result = $service;
|
||||
$service_selected = true;
|
||||
|
||||
// Force authentication if no user input is needed
|
||||
if ( ! self::service_requires_authentication( $service ) ) {
|
||||
( new AuthorizationFactory() )->create()->authorize( new \stdClass() );
|
||||
}
|
||||
} else {
|
||||
$result = new WP_Error(
|
||||
'0',
|
||||
'No service selected',
|
||||
array( 'service_id' => $service_id )
|
||||
);
|
||||
}
|
||||
|
||||
// Do not store selected service if this operation failed;
|
||||
if ( $error || ! $service_selected ) {
|
||||
$sitepress->set_setting( 'translation_service', false, true );
|
||||
}
|
||||
$sitepress->save_settings();
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public static function deselect_active_service() {
|
||||
global $sitepress;
|
||||
|
||||
$sitepress->set_setting( 'translation_service', false );
|
||||
$sitepress->set_setting( 'translator_choice', false );
|
||||
$sitepress->set_setting( 'icl_lang_status', false );
|
||||
$sitepress->set_setting( 'icl_html_status', false );
|
||||
$sitepress->set_setting( 'icl_current_session', false );
|
||||
$sitepress->set_setting( 'last_icl_reminder_fetch', false );
|
||||
$sitepress->set_setting( 'translators_management_info', false );
|
||||
$sitepress->set_setting( 'language_pairs', false );
|
||||
$sitepress->save_settings();
|
||||
|
||||
do_action( 'wpml_tp_service_dectivated', self::get_current_service() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $service
|
||||
* @param bool $custom_fields_data
|
||||
*
|
||||
* @return mixed
|
||||
* @throws \WPMLTranslationProxyApiException
|
||||
*/
|
||||
public static function build_and_store_active_translation_service( $service, $custom_fields_data = false ) {
|
||||
global $sitepress;
|
||||
|
||||
// set language map
|
||||
$service->languages_map = self::languages_map( $service );
|
||||
|
||||
// set information about custom fields
|
||||
$service->custom_fields = self::get_custom_fields( $service->id, true );
|
||||
$service->custom_fields_data = $custom_fields_data;
|
||||
|
||||
$service->last_refresh = time();
|
||||
|
||||
$sitepress->set_setting( 'translation_service', $service, true );
|
||||
|
||||
return $service;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|TranslationProxy_Project
|
||||
*/
|
||||
public static function get_current_project() {
|
||||
$translation_service = self::get_current_service();
|
||||
|
||||
if ( $translation_service ) {
|
||||
return new TranslationProxy_Project( $translation_service, 'xmlrpc', self::get_tp_client() );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function get_current_service_info( array $info = array() ) {
|
||||
global $sitepress;
|
||||
if ( ! $sitepress->get_setting( 'translation_service' ) ) {
|
||||
$sitepress->set_setting( 'translation_service', false, true );
|
||||
}
|
||||
$service = self::get_current_service();
|
||||
if ( $service ) {
|
||||
$service_info = array();
|
||||
if ( icl_do_not_promote() ) {
|
||||
$service_info['name'] = __( 'Translation Service', 'wpml-translation-management' );
|
||||
$service_info['logo'] = false;
|
||||
$service_info['header'] = __( 'Translation Service', 'wpml-translation-management' );
|
||||
$service_info['description'] = false;
|
||||
$service_info['contact_url'] = false;
|
||||
} else {
|
||||
$service_info['name'] = $service->name;
|
||||
$service_info['logo'] = $service->logo_url;
|
||||
$service_info['header'] = $service->name;
|
||||
$service_info['description'] = $service->description;
|
||||
$service_info['contact_url'] = $service->url;
|
||||
}
|
||||
$service_info['setup_url'] = TranslationProxy_Popup::get_link( '@select-translators;from_replace;to_replace@', array( 'ar' => 1 ), true );
|
||||
$service_info['has_quote'] = $service->quote_iframe_url !== '';
|
||||
$service_info['has_translator_selection'] = $service->has_translator_selection;
|
||||
|
||||
$info[ $service->id ] = $service_info;
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
public static function get_service_promo() {
|
||||
global $sitepress;
|
||||
|
||||
if ( icl_do_not_promote() ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$cache_key = 'get_service_promo';
|
||||
$cache_found = false;
|
||||
|
||||
$output = wp_cache_get( $cache_key, '', false, $cache_found );
|
||||
|
||||
if ( $cache_found ) {
|
||||
return $output;
|
||||
}
|
||||
|
||||
$icl_translation_services = apply_filters( 'icl_translation_services', array() );
|
||||
$icl_translation_services = array_merge( $icl_translation_services, self::get_current_service_info() );
|
||||
|
||||
$output = '';
|
||||
|
||||
if ( ! empty( $icl_translation_services ) ) {
|
||||
|
||||
$sitepress_settings = $sitepress->get_settings();
|
||||
$icl_dashboard_settings = isset( $sitepress_settings['dashboard'] ) ? $sitepress_settings['dashboard'] : array();
|
||||
|
||||
if ( empty( $icl_dashboard_settings['hide_icl_promo'] ) ) {
|
||||
$exp_hidden = '';
|
||||
$col_hidden = ' hidden';
|
||||
} else {
|
||||
$exp_hidden = ' hidden';
|
||||
$col_hidden = '';
|
||||
}
|
||||
|
||||
$output .= '<div class="icl-translation-services' . $exp_hidden . '">';
|
||||
foreach ( $icl_translation_services as $service ) {
|
||||
$output .= '<div class="icl-translation-services-inner">';
|
||||
$output .= '<p class="icl-translation-services-logo"><span><img src="' . $service['logo'] . '" alt="' . $service['name'] . '" /></span></p>';
|
||||
$output .= '<h3 class="icl-translation-services-header"> ' . $service['header'] . '</h3>';
|
||||
$output .= '<div class="icl-translation-desc"> ' . $service['description'] . '</div>';
|
||||
$output .= '</div>';
|
||||
$output .= '<p class="icl-translation-links">';
|
||||
$output .= '<a class="icl-mail-ico" href="' . $service['contact_url'] . '" target="_blank">' . __( 'Contact', 'wpml-translation-management' ) . " {$service['name']}</a>";
|
||||
$output .= '<a id="icl_hide_promo" href="#">' . __( 'Hide this', 'wpml-translation-management' ) . '</a>';
|
||||
$output .= '</p>';
|
||||
}
|
||||
$output .= '</div>';
|
||||
|
||||
$output .= '<a class="' . $col_hidden . '" id="icl_show_promo" href="#">' . __( 'Need translators?', 'wpml-translation-management' ) . '</a>';
|
||||
}
|
||||
|
||||
wp_cache_set( $cache_key, $output );
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
public static function get_service_dashboard_info() {
|
||||
global $sitepress;
|
||||
|
||||
return self::get_custom_html(
|
||||
'dashboard',
|
||||
$sitepress->get_current_language(),
|
||||
array(
|
||||
'TranslationProxy_Popup',
|
||||
'get_link',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static function get_service_translators_info() {
|
||||
global $sitepress;
|
||||
|
||||
return self::get_custom_html(
|
||||
'translators',
|
||||
$sitepress->get_current_language(),
|
||||
array(
|
||||
'TranslationProxy_Popup',
|
||||
'get_link',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $location
|
||||
* @param string $locale
|
||||
* @param callable $popup_link_callback
|
||||
* @param int $max_count
|
||||
* @param bool $paragraph
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_custom_html(
|
||||
$location,
|
||||
$locale,
|
||||
$popup_link_callback,
|
||||
$max_count = 1000,
|
||||
$paragraph = true
|
||||
) {
|
||||
/** @var $project TranslationProxy_Project */
|
||||
$project = self::get_current_project();
|
||||
|
||||
if ( ! $project ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$cache_key = $project->id . ':' . md5(
|
||||
serialize(
|
||||
array(
|
||||
$location,
|
||||
$locale,
|
||||
serialize( $popup_link_callback ),
|
||||
$max_count,
|
||||
$paragraph,
|
||||
)
|
||||
)
|
||||
);
|
||||
$cache_group = 'get_custom_html';
|
||||
$cache_found = false;
|
||||
|
||||
$output = wp_cache_get( $cache_key, $cache_group, false, $cache_found );
|
||||
|
||||
if ( $cache_found ) {
|
||||
return $output;
|
||||
}
|
||||
|
||||
try {
|
||||
$text = $project->custom_text( $location, $locale );
|
||||
} catch ( Exception $e ) {
|
||||
|
||||
return 'Error getting custom text from Translation Service: ' . $e->getMessage();
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
if ( $text ) {
|
||||
foreach ( $text as $string ) {
|
||||
$format_string = self::sanitize_custom_text( $string->format_string );
|
||||
|
||||
if ( $paragraph ) {
|
||||
$format = '<p>' . $format_string . '</p>';
|
||||
} else {
|
||||
$format = '<div>' . $format_string . '</div>';
|
||||
}
|
||||
$links = array();
|
||||
/** @var array $string_links */
|
||||
$string_links = $string->links;
|
||||
foreach ( $string_links as $link ) {
|
||||
$url = self::sanitize_custom_text( $link->url );
|
||||
$text = self::sanitize_custom_text( $link->text );
|
||||
if ( isset( $link->dismiss ) && (int) $link->dismiss === 1 ) {
|
||||
$links[] = '<a href="' . $url . '" class="wpml_tp_custom_dismiss_able">' . $text . '</a>';
|
||||
} else {
|
||||
$links[] = call_user_func(
|
||||
$popup_link_callback,
|
||||
$url
|
||||
) . $text . '</a>';
|
||||
}
|
||||
}
|
||||
|
||||
$output .= vsprintf( $format, $links );
|
||||
|
||||
$count ++;
|
||||
if ( $count >= $max_count ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
public static function get_current_service_name() {
|
||||
|
||||
if ( icl_do_not_promote() ) {
|
||||
return __( 'Translation Service', 'wpml-translation-management' );
|
||||
}
|
||||
|
||||
$translation_service = self::get_current_service();
|
||||
|
||||
if ( $translation_service ) {
|
||||
return $translation_service->name;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function get_current_service_id() {
|
||||
|
||||
$translation_service = self::get_current_service();
|
||||
|
||||
if ( $translation_service ) {
|
||||
return $translation_service->id;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function get_current_service_batch_name_max_length() {
|
||||
$translation_service = self::get_current_service();
|
||||
|
||||
if ( $translation_service && isset( $translation_service->batch_name_max_length )
|
||||
&& null
|
||||
!== $translation_service->batch_name_max_length ) {
|
||||
return $translation_service->batch_name_max_length;
|
||||
}
|
||||
|
||||
return 40;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool|TranslationProxy_Service|WP_Error $service
|
||||
*
|
||||
* @return bool
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws \WPMLTranslationProxyApiException
|
||||
*/
|
||||
public static function service_requires_authentication( $service = false ) {
|
||||
if ( ! $service ) {
|
||||
$service = self::get_current_service();
|
||||
}
|
||||
|
||||
$custom_fields = false;
|
||||
if ( false !== (bool) $service ) {
|
||||
$custom_fields = self::get_custom_fields( $service->id );
|
||||
}
|
||||
|
||||
return $custom_fields && isset( $custom_fields->custom_fields ) && count( $custom_fields->custom_fields ) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if $service has been successfully authenticated
|
||||
* Services that do not require authentication are by default authenticated
|
||||
*
|
||||
* @param bool|WP_Error|TranslationProxy_Service $service
|
||||
*
|
||||
* @return bool
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public static function is_service_authenticated( $service = false ) {
|
||||
if ( ! $service ) {
|
||||
$service = self::get_current_service();
|
||||
}
|
||||
|
||||
if ( ! $service ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! self::service_requires_authentication( $service ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$has_custom_fields = self::has_custom_fields();
|
||||
$custom_fields_data = self::get_custom_fields_data();
|
||||
|
||||
return $has_custom_fields && $custom_fields_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|TranslationProxy_Service|WP_Error
|
||||
*/
|
||||
public static function get_current_service() {
|
||||
global $sitepress;
|
||||
|
||||
/** @var TranslationProxy_Service $ts */
|
||||
$ts = $sitepress->get_setting( 'translation_service' );
|
||||
|
||||
if ( is_array( $ts ) ) {
|
||||
return new WP_Error( 'translation-proxy-service-misconfiguration', 'translation_service is stored as array!', $ts );
|
||||
}
|
||||
|
||||
return $ts;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return bool
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public static function is_current_service_active_and_authenticated() {
|
||||
$active_service = self::get_current_service();
|
||||
|
||||
return $active_service && TranslationProxy_Service::is_authenticated( $active_service );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get_translation_projects() {
|
||||
global $sitepress;
|
||||
|
||||
return $sitepress->get_setting( 'icl_translation_projects', null );
|
||||
}
|
||||
|
||||
public static function get_service_name( $service_id = false ) {
|
||||
if ( $service_id ) {
|
||||
$name = false;
|
||||
$services = self::services( false );
|
||||
|
||||
foreach ( $services as $service ) {
|
||||
if ( $service->id === $service_id ) {
|
||||
$name = $service->name;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$name = self::get_current_service_name();
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
public static function has_custom_fields( $service_id = false ) {
|
||||
$custom_fields = self::get_custom_fields( $service_id );
|
||||
|
||||
if ( $custom_fields ) {
|
||||
return isset( $custom_fields->custom_fields ) && is_array( $custom_fields->custom_fields ) && count( $custom_fields->custom_fields );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|bool $service_id If not given, will use the current service ID (if any)
|
||||
* @param bool $force_reload Force reload custom fields from Translation Service
|
||||
*
|
||||
* @throws WPMLTranslationProxyApiException
|
||||
* @throws InvalidArgumentException
|
||||
* @return array|mixed|null|string
|
||||
*/
|
||||
public static function get_custom_fields( $service_id = false, $force_reload = false ) {
|
||||
|
||||
if ( ! $service_id ) {
|
||||
$service_id = self::get_current_service_id();
|
||||
}
|
||||
if ( ! $service_id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$translation_service = self::get_current_service();
|
||||
if ( $translation_service && ! $force_reload ) {
|
||||
return $translation_service->custom_fields ?: false;
|
||||
}
|
||||
|
||||
return self::get_tp_client()->services()->get_custom_fields( $service_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function get_extra_fields_local() {
|
||||
global $sitepress;
|
||||
$service = self::get_current_service();
|
||||
$icl_translation_projects = $sitepress->get_setting( 'icl_translation_projects' );
|
||||
|
||||
if ( isset( $icl_translation_projects[ TranslationProxy_Project::generate_service_index( $service ) ]['extra_fields'] ) && ! empty( $icl_translation_projects[ TranslationProxy_Project::generate_service_index( $service ) ]['extra_fields'] ) ) {
|
||||
return $icl_translation_projects[ TranslationProxy_Project::generate_service_index( $service ) ]['extra_fields'];
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $extra_fields
|
||||
*/
|
||||
public static function save_extra_fields( $extra_fields ) {
|
||||
global $sitepress;
|
||||
$service = self::get_current_service();
|
||||
$icl_translation_projects = $sitepress->get_setting( 'icl_translation_projects' );
|
||||
$icl_translation_project_id = TranslationProxy_Project::generate_service_index( $service );
|
||||
|
||||
if ( is_array( Obj::prop( $icl_translation_project_id, $icl_translation_projects ) ) ) {
|
||||
$icl_translation_projects[ $icl_translation_project_id ]['extra_fields'] = $extra_fields;
|
||||
$sitepress->set_setting( 'icl_translation_projects', $icl_translation_projects );
|
||||
$sitepress->save_settings();
|
||||
}
|
||||
}
|
||||
|
||||
public static function maybe_convert_extra_fields( $extra_fields ) {
|
||||
$extra_fields_typed = array();
|
||||
|
||||
if ( $extra_fields && is_array( $extra_fields ) ) {
|
||||
/** @var array $extra_fields */
|
||||
/** @var stdClass $extra_field */
|
||||
foreach ( $extra_fields as $extra_field ) {
|
||||
if ( $extra_field instanceof WPML_TP_Extra_Field ) {
|
||||
$extra_field_typed = $extra_field;
|
||||
} else {
|
||||
$extra_field_typed = new WPML_TP_Extra_Field();
|
||||
if ( isset( $extra_field->type ) ) {
|
||||
$extra_field_typed->type = $extra_field->type;
|
||||
}
|
||||
if ( isset( $extra_field->label ) ) {
|
||||
$extra_field_typed->label = $extra_field->label;
|
||||
}
|
||||
if ( isset( $extra_field->name ) ) {
|
||||
$extra_field_typed->name = $extra_field->name;
|
||||
}
|
||||
if ( isset( $extra_field->items ) ) {
|
||||
$extra_field_typed->items = $extra_field->items;
|
||||
}
|
||||
}
|
||||
$extra_fields_typed[] = $extra_field_typed;
|
||||
}
|
||||
}
|
||||
|
||||
return $extra_fields_typed;
|
||||
}
|
||||
|
||||
public static function get_custom_fields_data() {
|
||||
$service = self::get_current_service();
|
||||
|
||||
return null !== $service->custom_fields_data ? $service->custom_fields_data : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool true if the current translation service allows selection of specific translators
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public static function translator_selection_available() {
|
||||
$res = false;
|
||||
|
||||
$translation_service = self::get_current_service();
|
||||
if ( $translation_service && $translation_service->has_translator_selection && self::is_service_authenticated() ) {
|
||||
$res = true;
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
private static function sanitize_custom_text( $text ) {
|
||||
$text = substr( $text, 0, CUSTOM_TEXT_MAX_LENGTH );
|
||||
$text = esc_html( $text );
|
||||
|
||||
// Service sends html tags as [tag]
|
||||
$text = str_replace( array( '[', ']' ), array( '<', '>' ), $text );
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
private static function languages_map( $service ) {
|
||||
$languages_map = array();
|
||||
$languages = self::get_tp_client()->services()->get_languages_map( $service->id );
|
||||
if ( ! empty( $languages ) ) {
|
||||
foreach ( $languages as $language ) {
|
||||
$languages_map[ $language->iso_code ] = $language->value;
|
||||
}
|
||||
}
|
||||
|
||||
return $languages_map;
|
||||
}
|
||||
|
||||
private static function get_preferred_translation_service() {
|
||||
$tp_default_suid = false;
|
||||
$preferred_translation_service_from_installer = self::get_preferred_translation_service_from_installer();
|
||||
if ( 'clear' !== $preferred_translation_service_from_installer ) {
|
||||
$tp_default_suid = $preferred_translation_service_from_installer;
|
||||
}
|
||||
|
||||
return $tp_default_suid;
|
||||
}
|
||||
|
||||
private static function get_preferred_translation_service_from_installer() {
|
||||
|
||||
return WP_Installer_API::get_preferred_ts();
|
||||
}
|
||||
|
||||
public static function get_tp_client() {
|
||||
if ( ! self::$tp_client ) {
|
||||
$tp_api_factory = new WPML_TP_Client_Factory();
|
||||
self::$tp_client = $tp_api_factory->create();
|
||||
}
|
||||
|
||||
return self::$tp_client;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,611 @@
|
||||
<?php
|
||||
/**
|
||||
* @package wpml-core
|
||||
* @package wpml-core-pro-translation
|
||||
*/
|
||||
|
||||
use WPML\FP\Fns;
|
||||
use WPML\FP\Lst;
|
||||
use WPML\FP\Str;
|
||||
use function WPML\Container\make;
|
||||
use function WPML\FP\pipe;
|
||||
|
||||
/**
|
||||
* Class WPML_Pro_Translation
|
||||
*/
|
||||
class WPML_Pro_Translation extends WPML_TM_Job_Factory_User {
|
||||
|
||||
public $errors = array();
|
||||
/** @var TranslationManagement $tmg */
|
||||
private $tmg;
|
||||
|
||||
/** @var WPML_TM_CMS_ID $cms_id_helper */
|
||||
private $cms_id_helper;
|
||||
|
||||
/** @var WPML_TM_Xliff_Reader_Factory $xliff_reader_factory */
|
||||
private $xliff_reader_factory;
|
||||
|
||||
|
||||
private $sitepress;
|
||||
|
||||
private $update_pm;
|
||||
|
||||
/**
|
||||
* WPML_Pro_Translation constructor.
|
||||
*
|
||||
* @param WPML_Translation_Job_Factory $job_factory
|
||||
*/
|
||||
function __construct( &$job_factory ) {
|
||||
parent::__construct( $job_factory );
|
||||
global $iclTranslationManagement, $wpdb, $sitepress, $wpml_post_translations, $wpml_term_translations;
|
||||
|
||||
$this->tmg =& $iclTranslationManagement;
|
||||
$this->xliff_reader_factory = new WPML_TM_Xliff_Reader_Factory( $this->job_factory );
|
||||
$wpml_tm_records = new WPML_TM_Records( $wpdb, $wpml_post_translations, $wpml_term_translations );
|
||||
$this->cms_id_helper = new WPML_TM_CMS_ID( $wpml_tm_records, $job_factory );
|
||||
$this->sitepress = $sitepress;
|
||||
|
||||
add_filter( 'xmlrpc_methods', array( $this, 'custom_xmlrpc_methods' ) );
|
||||
add_action(
|
||||
'post_submitbox_start',
|
||||
array(
|
||||
$this,
|
||||
'post_submitbox_start',
|
||||
)
|
||||
);
|
||||
add_action(
|
||||
'icl_ajx_custom_call',
|
||||
array(
|
||||
$this,
|
||||
'ajax_calls',
|
||||
),
|
||||
10,
|
||||
2
|
||||
);
|
||||
|
||||
add_action( 'wpml_minor_edit_for_gutenberg', array( $this, 'gutenberg_minor_edit' ), 10, 0 );
|
||||
|
||||
$this->update_pm = new WPML_Update_PickUp_Method( $this->sitepress );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_TM_CMS_ID
|
||||
*/
|
||||
public function &get_cms_id_helper() {
|
||||
return $this->cms_id_helper;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $call
|
||||
* @param array $data
|
||||
*/
|
||||
function ajax_calls( $call, $data ) {
|
||||
switch ( $call ) {
|
||||
case 'set_pickup_mode':
|
||||
$response = $this->update_pm->update_pickup_method( $data, $this->get_current_project() );
|
||||
if ( 'no-ts' === $response ) {
|
||||
wp_send_json_error( array( 'message' => __( 'Please activate translation service first.', 'wpml-translation-management' ) ) );
|
||||
}
|
||||
if ( 'cant-update' === $response ) {
|
||||
wp_send_json_error( array( 'message' => __( 'Could not update the translation pickup mode.', 'wpml-translation-management' ) ) );
|
||||
}
|
||||
|
||||
wp_send_json_success( array( 'message' => __( 'Ok', 'wpml-translation-management' ) ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public function get_current_project() {
|
||||
return TranslationProxy::get_current_project();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_Post|WPML_Package $post
|
||||
* @param array $target_languages
|
||||
* @param int $translator_id
|
||||
* @param int $job_id
|
||||
*
|
||||
* @return bool|int
|
||||
*/
|
||||
function send_post( $post, $target_languages, $translator_id, $job_id ) {
|
||||
/** @var TranslationManagement $iclTranslationManagement */
|
||||
global $sitepress, $iclTranslationManagement;
|
||||
|
||||
$this->maybe_init_translation_management( $iclTranslationManagement );
|
||||
|
||||
if ( is_numeric( $post ) ) {
|
||||
$post = get_post( $post );
|
||||
}
|
||||
if ( ! $post ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$post_id = $post->ID;
|
||||
$post_type = $post->post_type;
|
||||
$element_type_prefix = $iclTranslationManagement->get_element_type_prefix_from_job_id( $job_id );
|
||||
$element_type = $element_type_prefix . '_' . $post_type;
|
||||
|
||||
$note = WPML_TM_Translator_Note::get( $post_id );
|
||||
if ( ! $note ) {
|
||||
$note = null;
|
||||
}
|
||||
$err = false;
|
||||
$tp_job_id = false;
|
||||
$source_language = $sitepress->get_language_for_element( $post_id, $element_type );
|
||||
$target_language = is_array( $target_languages ) ? end( $target_languages ) : $target_languages;
|
||||
if ( empty( $target_language ) || $target_language === $source_language ) {
|
||||
return false;
|
||||
}
|
||||
$translation = $this->tmg->get_element_translation( $post_id, $target_language, $element_type );
|
||||
if ( ! $translation ) { // translated the first time
|
||||
$err = true;
|
||||
}
|
||||
if ( ! $err && ( $translation->needs_update || $translation->status == ICL_TM_NOT_TRANSLATED || $translation->status == ICL_TM_WAITING_FOR_TRANSLATOR ) ) {
|
||||
$project = TranslationProxy::get_current_project();
|
||||
|
||||
if ( $iclTranslationManagement->is_external_type( $element_type_prefix ) ) {
|
||||
$job_object = new WPML_External_Translation_Job( $job_id );
|
||||
} else {
|
||||
$job_object = new WPML_Post_Translation_Job( $job_id );
|
||||
$job_object->load_terms_from_post_into_job();
|
||||
}
|
||||
|
||||
list( $err, $project, $tp_job_id ) = $job_object->send_to_tp( $project, $translator_id, $this->cms_id_helper, $this->tmg, $note );
|
||||
if ( $err ) {
|
||||
$this->enqueue_project_errors( $project );
|
||||
}
|
||||
}
|
||||
|
||||
return $err ? false : $tp_job_id; // last $ret
|
||||
}
|
||||
|
||||
function server_languages_map( $language_name, $server2plugin = false ) {
|
||||
if ( is_array( $language_name ) ) {
|
||||
return array_map( array( $this, 'server_languages_map' ), $language_name );
|
||||
}
|
||||
$map = array(
|
||||
'Norwegian Bokmål' => 'Norwegian',
|
||||
'Portuguese, Brazil' => 'Portuguese',
|
||||
'Portuguese, Portugal' => 'Portugal Portuguese',
|
||||
);
|
||||
|
||||
$map = $server2plugin ? array_flip( $map ) : $map;
|
||||
|
||||
return isset( $map[ $language_name ] ) ? $map[ $language_name ] : $language_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $methods
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function custom_xmlrpc_methods( $methods ) {
|
||||
$icl_methods['translationproxy.test_xmlrpc'] = '__return_true';
|
||||
$icl_methods['translationproxy.updated_job_status'] = array(
|
||||
$this,
|
||||
'xmlrpc_updated_job_status',
|
||||
);
|
||||
|
||||
$methods = array_merge( $methods, $icl_methods );
|
||||
if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST && preg_match( '#<methodName>([^<]+)</methodName>#i', $this->sitepress->get_wp_api()->get_raw_post_data(), $matches ) ) {
|
||||
$method = $matches[1];
|
||||
if ( array_key_exists( $method, $icl_methods ) ) {
|
||||
set_error_handler( array( $this, 'translation_error_handler' ), E_ERROR | E_USER_ERROR );
|
||||
}
|
||||
}
|
||||
|
||||
return $methods;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $args
|
||||
*
|
||||
* @return int|IXR_Error
|
||||
*/
|
||||
public function xmlrpc_updated_job_status( $args ) {
|
||||
global $wpdb;
|
||||
|
||||
$tp_id = isset( $args[0] ) ? $args[0] : 0;
|
||||
$cms_id = isset( $args[1] ) ? $args[1] : 0;
|
||||
$status = isset( $args[2] ) ? $args[2] : '';
|
||||
$signature = isset( $args[3] ) ? $args[3] : '';
|
||||
|
||||
if ( ! $this->authenticate_request( $tp_id, $cms_id, $status, $signature ) ) {
|
||||
return new IXR_Error( 401, 'Wrong signature' );
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
/** @var WPML_TM_Jobs_Repository $jobs_repository */
|
||||
$jobs_repository = wpml_tm_get_jobs_repository();
|
||||
|
||||
$job_match = $jobs_repository->get(
|
||||
new WPML_TM_Jobs_Search_Params(
|
||||
array(
|
||||
'scope' => 'remote',
|
||||
'tp_id' => $tp_id,
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if ( $job_match ) {
|
||||
$jobs_array = $job_match->toArray();
|
||||
$job = $jobs_array[0];
|
||||
$job->set_status( WPML_TP_Job_States::map_tp_state_to_local( $status ) );
|
||||
|
||||
$tp_sync_updated_job = new WPML_TP_Sync_Update_Job( $wpdb, $this->sitepress );
|
||||
$job_updated = $tp_sync_updated_job->update_state( $job );
|
||||
|
||||
if ( $job_updated && WPML_TP_Job_States::CANCELLED !== $status ) {
|
||||
$apply_tp_translation = new WPML_TP_Apply_Single_Job(
|
||||
wpml_tm_get_tp_translations_repository(),
|
||||
new WPML_TP_Apply_Translation_Strategies( $wpdb )
|
||||
);
|
||||
$apply_tp_translation->apply( $job );
|
||||
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
} catch ( Exception $e ) {
|
||||
return new IXR_Error( $e->getCode(), $e->getMessage() );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function authenticate_request( $tp_id, $cms_id, $status, $signature ) {
|
||||
$project = TranslationProxy::get_current_project();
|
||||
|
||||
return sha1( $project->id . $project->access_key . $tp_id . $cms_id . $status ) === $signature;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_WP_API
|
||||
*/
|
||||
function get_wpml_wp_api() {
|
||||
return $this->sitepress->get_wp_api();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Cancel translation for given cms_id
|
||||
*
|
||||
* @param $rid
|
||||
* @param $cms_id
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function cancel_translation( $rid, $cms_id ) {
|
||||
/**
|
||||
* @var WPML_String_Translation|null $WPML_String_Translation
|
||||
* @var TranslationManagement $iclTranslationManagement
|
||||
*/
|
||||
global $WPML_String_Translation, $iclTranslationManagement;
|
||||
|
||||
$res = false;
|
||||
if ( empty( $cms_id ) ) { // it's a string
|
||||
if ( $WPML_String_Translation ) {
|
||||
$res = $WPML_String_Translation->cancel_remote_translation( $rid );
|
||||
}
|
||||
} else {
|
||||
$translation_id = $this->cms_id_helper->get_translation_id( $cms_id );
|
||||
|
||||
if ( $translation_id ) {
|
||||
$iclTranslationManagement->cancel_translation_request( $translation_id );
|
||||
$res = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Downloads translation from TP and updates its document
|
||||
*
|
||||
* @param $translation_proxy_job_id
|
||||
* @param $cms_id
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
function download_and_process_translation( $translation_proxy_job_id, $cms_id ) {
|
||||
global $wpdb;
|
||||
|
||||
if ( empty( $cms_id ) ) { // it's a string
|
||||
// TODO: [WPML 3.3] this should be handled as any other element type in 3.3
|
||||
$target = $wpdb->get_var( $wpdb->prepare( "SELECT target FROM {$wpdb->prefix}icl_core_status WHERE rid=%d", $translation_proxy_job_id ) );
|
||||
|
||||
return $this->process_translated_string( $translation_proxy_job_id, $target );
|
||||
} else {
|
||||
$translation_id = $this->cms_id_helper->get_translation_id( $cms_id, TranslationProxy::get_current_service() );
|
||||
|
||||
return ! empty( $translation_id ) && $this->add_translated_document( $translation_id, $translation_proxy_job_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $translation_id
|
||||
* @param int $translation_proxy_job_id
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function add_translated_document( $translation_id, $translation_proxy_job_id ) {
|
||||
global $wpdb, $sitepress;
|
||||
$project = TranslationProxy::get_current_project();
|
||||
|
||||
$translation_info = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}icl_translations WHERE translation_id=%d", $translation_id ) );
|
||||
$translation = $project->fetch_translation( $translation_proxy_job_id );
|
||||
if ( ! $translation ) {
|
||||
$this->errors = array_merge( $this->errors, $project->errors );
|
||||
} else {
|
||||
$translation = apply_filters( 'icl_data_from_pro_translation', $translation );
|
||||
}
|
||||
$ret = true;
|
||||
|
||||
if ( ! empty( $translation ) && strpos( $translation, 'xliff' ) !== false ) {
|
||||
try {
|
||||
/** @var $job_xliff_translation WP_Error|array */
|
||||
$job_xliff_translation = $this->xliff_reader_factory
|
||||
->general_xliff_import()->import( $translation, $translation_id );
|
||||
if ( is_wp_error( $job_xliff_translation ) ) {
|
||||
$this->add_error( $job_xliff_translation->get_error_message() );
|
||||
|
||||
return false;
|
||||
}
|
||||
kses_remove_filters();
|
||||
wpml_tm_save_data( $job_xliff_translation );
|
||||
kses_init();
|
||||
|
||||
$translations = $sitepress->get_element_translations( $translation_info->trid, $translation_info->element_type, false, true, true );
|
||||
if ( isset( $translations[ $translation_info->language_code ] ) ) {
|
||||
$translation = $translations[ $translation_info->language_code ];
|
||||
if ( isset( $translation->element_id ) && $translation->element_id ) {
|
||||
$translation_post_type_prepared = $wpdb->prepare( "SELECT post_type FROM $wpdb->posts WHERE ID=%d", array( $translation->element_id ) );
|
||||
$translation_post_type = $wpdb->get_var( $translation_post_type_prepared );
|
||||
} else {
|
||||
$translation_post_type = implode( '_', array_slice( explode( '_', $translation_info->element_type ), 1 ) );
|
||||
}
|
||||
if ( $translation_post_type == 'page' ) {
|
||||
$url = get_option( 'home' ) . '?page_id=' . $translation->element_id;
|
||||
} else {
|
||||
$url = get_option( 'home' ) . '?p=' . $translation->element_id;
|
||||
}
|
||||
$project->update_job( $translation_proxy_job_id, $url );
|
||||
} else {
|
||||
$project->update_job( $translation_proxy_job_id );
|
||||
}
|
||||
} catch ( Exception $e ) {
|
||||
$ret = false;
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
private static function content_get_link_paths( $body ) {
|
||||
|
||||
$regexp_links = array(
|
||||
"/<a[^>]*href\s*=\s*([\"\']??)([^\"^>]+)[\"\']??([^>]*)>/i",
|
||||
);
|
||||
|
||||
$links = array();
|
||||
|
||||
foreach ( $regexp_links as $regexp ) {
|
||||
if ( preg_match_all( $regexp, $body, $matches, PREG_SET_ORDER ) ) {
|
||||
foreach ( $matches as $match ) {
|
||||
$links[] = $match;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
public function fix_links_to_translated_content( $element_id, $target_lang_code, $element_type = 'post' ) {
|
||||
global $wpdb, $sitepress;
|
||||
|
||||
$sitepress->switch_lang( $target_lang_code );
|
||||
|
||||
$wpml_element_type = $element_type;
|
||||
$body = false;
|
||||
$string_type = null;
|
||||
if ( strpos( $element_type, 'post' ) === 0 ) {
|
||||
$post_prepared = $wpdb->prepare( "SELECT * FROM {$wpdb->posts} WHERE ID=%d", array( $element_id ) );
|
||||
$post = $wpdb->get_row( $post_prepared );
|
||||
$body = $post->post_content;
|
||||
$wpml_element_type = 'post_' . $post->post_type;
|
||||
} elseif ( $element_type == 'string' ) {
|
||||
$string_prepared = $wpdb->prepare( "SELECT string_id, value FROM {$wpdb->prefix}icl_string_translations WHERE id=%d", array( $element_id ) );
|
||||
$data = $wpdb->get_row( $string_prepared );
|
||||
$body = $data->value;
|
||||
$original_string_id = $data->string_id;
|
||||
$string_type = $wpdb->get_var( $wpdb->prepare( "SELECT type FROM {$wpdb->prefix}icl_strings WHERE id=%d", $original_string_id ) );
|
||||
if ( 'LINK' === $string_type ) {
|
||||
$body = '<a href="' . $body . '">removeit</a>';
|
||||
}
|
||||
}
|
||||
|
||||
$translate_link_targets = make( 'WPML_Translate_Link_Targets' );
|
||||
$absolute_links = make( 'AbsoluteLinks' );
|
||||
|
||||
$getTranslatedLink = function ( $link ) use ( $translate_link_targets, $absolute_links, $element_type, $target_lang_code ) {
|
||||
if ( $absolute_links->is_home( $link[2] ) ) {
|
||||
$translatedLink = $absolute_links->convert_url( $link[2], $target_lang_code );
|
||||
$translatedLink = Str::replace( $link[2], $translatedLink, $link[0] );
|
||||
} else {
|
||||
add_filter( 'wpml_force_translated_permalink', '__return_true' );
|
||||
$translatedLink = $translate_link_targets->convert_text( $link[0] );
|
||||
remove_filter( 'wpml_force_translated_permalink', '__return_true' );
|
||||
if ( self::should_links_be_converted_back_to_sticky( $element_type ) ) {
|
||||
$translatedLink = $absolute_links->convert_text( $translatedLink );
|
||||
}
|
||||
}
|
||||
|
||||
return $translatedLink !== $link[0]
|
||||
? [
|
||||
'from' => $link[0],
|
||||
'to' => $translatedLink,
|
||||
]
|
||||
: null;
|
||||
};
|
||||
|
||||
$getTranslatedLinks = pipe(
|
||||
Fns::map( $getTranslatedLink ),
|
||||
Fns::filter( Fns::identity() )
|
||||
);
|
||||
|
||||
$links = self::content_get_link_paths( $body );
|
||||
|
||||
$translatedLinks = $getTranslatedLinks( $links );
|
||||
|
||||
$replaceLink = function ( $body, $link ) {
|
||||
return str_replace( $link['from'], $link['to'], $body );
|
||||
};
|
||||
|
||||
$new_body = Fns::reduce( $replaceLink, $body, $translatedLinks );
|
||||
|
||||
if ( $new_body != $body ) {
|
||||
if ( strpos( $element_type, 'post' ) === 0 ) {
|
||||
$wpdb->update( $wpdb->posts, array( 'post_content' => $new_body ), array( 'ID' => $element_id ) );
|
||||
} elseif ( $element_type == 'string' ) {
|
||||
if ( 'LINK' === $string_type ) {
|
||||
$new_body = str_replace( array( '<a href="', '">removeit</a>' ), array( '', '' ), $new_body );
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'icl_string_translations',
|
||||
array(
|
||||
'value' => $new_body,
|
||||
'status' => ICL_TM_COMPLETE,
|
||||
),
|
||||
array( 'id' => $element_id )
|
||||
);
|
||||
do_action( 'icl_st_add_string_translation', $element_id );
|
||||
} else {
|
||||
$wpdb->update( $wpdb->prefix . 'icl_string_translations', array( 'value' => $new_body ), array( 'id' => $element_id ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$links_fixed_status_factory = new WPML_Links_Fixed_Status_Factory( $wpdb, new WPML_WP_API() );
|
||||
$links_fixed_status = $links_fixed_status_factory->create( $element_id, $wpml_element_type );
|
||||
$links_fixed_status->set( Lst::length( $links ) === Lst::length( $translatedLinks ) );
|
||||
|
||||
$sitepress->switch_lang();
|
||||
|
||||
return sizeof( $translatedLinks );
|
||||
|
||||
}
|
||||
|
||||
function translation_error_handler( $error_number, $error_string, $error_file, $error_line ) {
|
||||
switch ( $error_number ) {
|
||||
case E_ERROR:
|
||||
case E_USER_ERROR:
|
||||
throw new Exception( $error_string . ' [code:e' . $error_number . '] in ' . $error_file . ':' . $error_line );
|
||||
case E_WARNING:
|
||||
case E_USER_WARNING:
|
||||
return true;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static function should_links_be_converted_back_to_sticky( $element_type ) {
|
||||
return 'string' !== $element_type && ! empty( $GLOBALS['WPML_Sticky_Links'] );
|
||||
}
|
||||
|
||||
function post_submitbox_start() {
|
||||
$show_box_style = $this->get_show_minor_edit_style();
|
||||
if ( false !== $show_box_style ) {
|
||||
?>
|
||||
<p id="icl_minor_change_box" style="float:left;padding:0;margin:3px;<?php echo $show_box_style; ?>">
|
||||
<label><input type="checkbox" name="icl_minor_edit" value="1" style="min-width:15px;"/>
|
||||
<?php esc_html_e( 'Minor edit - don\'t update translation', 'wpml-translation-management' ); ?>
|
||||
</label>
|
||||
<br clear="all"/>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
public function gutenberg_minor_edit() {
|
||||
$show_box_style = $this->get_show_minor_edit_style();
|
||||
if ( false !== $show_box_style ) {
|
||||
?>
|
||||
<div id="icl_minor_change_box" style="<?php echo $show_box_style; ?>" class="icl_box_paragraph">
|
||||
<p>
|
||||
<strong><?php esc_html_e( 'Minor edit', 'wpml-translation-management' ); ?></strong>
|
||||
</p>
|
||||
<label><input type="checkbox" name="icl_minor_edit" value="1" style="min-width:15px;"/>
|
||||
<?php esc_html_e( "Don't update translation", 'wpml-translation-management' ); ?>
|
||||
</label>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
private function get_show_minor_edit_style() {
|
||||
global $post, $iclTranslationManagement;
|
||||
if ( empty( $post ) || ! $post->ID ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$translations = $iclTranslationManagement->get_element_translations( $post->ID, 'post_' . $post->post_type );
|
||||
$show_box_style = 'display:none';
|
||||
foreach ( $translations as $t ) {
|
||||
if ( $t->element_id == $post->ID ) {
|
||||
return false;
|
||||
}
|
||||
if ( $t->status == ICL_TM_COMPLETE && ! $t->needs_update ) {
|
||||
$show_box_style = '';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $show_box_style;
|
||||
}
|
||||
|
||||
private function process_translated_string( $translation_proxy_job_id, $language ) {
|
||||
$project = TranslationProxy::get_current_project();
|
||||
$translation = $project->fetch_translation( $translation_proxy_job_id );
|
||||
$translation = apply_filters( 'icl_data_from_pro_translation', $translation );
|
||||
$ret = false;
|
||||
$translation = $this->xliff_reader_factory->string_xliff_reader()->get_data( $translation );
|
||||
if ( $translation ) {
|
||||
$ret = icl_translation_add_string_translation( $translation_proxy_job_id, $translation, $language );
|
||||
if ( $ret ) {
|
||||
$project->update_job( $translation_proxy_job_id );
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
private function add_error( $project_error ) {
|
||||
$this->errors[] = $project_error;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $project TranslationProxy_Project
|
||||
*/
|
||||
function enqueue_project_errors( $project ) {
|
||||
if ( isset( $project ) && isset( $project->errors ) && $project->errors ) {
|
||||
foreach ( $project->errors as $project_error ) {
|
||||
$this->add_error( $project_error );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param TranslationManagement $iclTranslationManagement
|
||||
*/
|
||||
private function maybe_init_translation_management( $iclTranslationManagement ) {
|
||||
if ( empty( $this->tmg->settings ) ) {
|
||||
$iclTranslationManagement->init();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
<?php
|
||||
|
||||
use WPML\LIB\WP\Cache;
|
||||
use \WPML\Collect\Support\Traits\Macroable;
|
||||
use WPML\FP\Str;
|
||||
use function \WPML\FP\System\sanitizeString;
|
||||
use function \WPML\FP\pipe;
|
||||
use function \WPML\FP\curryN;
|
||||
|
||||
/**
|
||||
* @method static int get_batch_id_from_name( string $basket_name )
|
||||
*/
|
||||
class WPML_Translation_Basket {
|
||||
|
||||
use Macroable;
|
||||
|
||||
/** @var wpdb $wpdb */
|
||||
private $wpdb;
|
||||
|
||||
public function __construct( \wpdb $wpdb ) {
|
||||
$this->wpdb = $wpdb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array representation of the current translation basket
|
||||
*
|
||||
* @param bool|false $force if true reloads the baskets contents from the database
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function get_basket( $force = false ) {
|
||||
$basket = TranslationProxy_Basket::get_basket( $force );
|
||||
$basket = $basket ? $basket : array();
|
||||
|
||||
return $basket;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|TranslationProxy_Project
|
||||
*/
|
||||
public function get_project() {
|
||||
|
||||
return TranslationProxy::get_current_project();
|
||||
}
|
||||
|
||||
function get_item_types() {
|
||||
|
||||
return TranslationProxy_Basket::get_basket_items_types();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a batch instance by basket- or batch-name
|
||||
*
|
||||
* @param string $basket_name
|
||||
*
|
||||
* @return WPML_Translation_Batch
|
||||
*/
|
||||
function get_basket_batch( $basket_name ) {
|
||||
|
||||
return new WPML_Translation_Batch( $this->wpdb, self::get_batch_id_from_name( $basket_name ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the remote target languages before committing the basket to a translation service.
|
||||
*
|
||||
* @param array $remote_languages
|
||||
*/
|
||||
function set_remote_target_languages( $remote_languages ) {
|
||||
|
||||
TranslationProxy_Basket::set_remote_target_languages( $remote_languages );
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all items from the current translation basket.
|
||||
*/
|
||||
function delete_all_items() {
|
||||
|
||||
TranslationProxy_Basket::delete_all_items_from_basket();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the current translation basket.
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
function get_name() {
|
||||
|
||||
return TranslationProxy_Basket::get_basket_name();
|
||||
}
|
||||
|
||||
function set_name( $basket_name ) {
|
||||
|
||||
TranslationProxy_Basket::set_basket_name( $basket_name );
|
||||
}
|
||||
|
||||
function set_options( array $batch_options ) {
|
||||
TranslationProxy_Basket::set_options( $batch_options );
|
||||
}
|
||||
|
||||
/** @return array */
|
||||
function get_options() {
|
||||
return TranslationProxy_Basket::get_options();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $basket_name
|
||||
* @param int $basket_name_max_length
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function check_basket_name( $basket_name, $basket_name_max_length ) {
|
||||
|
||||
$result = array(
|
||||
'modified' => false,
|
||||
'valid' => true,
|
||||
'message' => '',
|
||||
'new_value' => '',
|
||||
);
|
||||
$old_value = $basket_name;
|
||||
$basket_name = strip_tags( $basket_name );
|
||||
|
||||
if ( mb_strlen( $basket_name ) > $basket_name_max_length ) {
|
||||
$result['valid'] = true;
|
||||
$result['message'] = sprintf(
|
||||
__( 'The length of the batch name exceeds the maximum length of %s', 'wpml-translation-management' ),
|
||||
$basket_name_max_length
|
||||
);
|
||||
$result['new_value'] = $this->get_unique_basket_name( $basket_name, $basket_name_max_length );
|
||||
} elseif ( self::get_batch_id_from_name( $basket_name ) ) {
|
||||
$result['valid'] = true;
|
||||
$result['new_value'] = $this->get_unique_basket_name( $basket_name, $basket_name_max_length );
|
||||
$result['message'] = __(
|
||||
'This batch name already exists and was modified to ensure unique naming',
|
||||
'wpml-translation-management'
|
||||
);
|
||||
} elseif ( count( $basket_name_array = explode( '|', $basket_name ) ) === 1 ) {
|
||||
$result['valid'] = true;
|
||||
$result['new_value'] = $this->get_unique_basket_name( $basket_name, $basket_name_max_length );
|
||||
$result['message'] = __(
|
||||
'The batch name was appended with the source language of its elements.',
|
||||
'wpml-translation-management'
|
||||
);
|
||||
}
|
||||
$result['modified'] = $result['new_value'] !== '' && $result['new_value'] !== $old_value;
|
||||
$result['message'] = $result['modified'] || ! $result['valid'] ? $result['message'] : '';
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unique name derived from an input name for a Translation Proxy Basket
|
||||
*
|
||||
* @param bool $name
|
||||
* @param bool|int $max_length
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
function get_unique_basket_name( $name, $max_length ) {
|
||||
$basket_name_array = explode( '|', $name );
|
||||
$name = count( $basket_name_array ) === 1
|
||||
|| ( ! is_numeric( $basket_name_array[ count( $basket_name_array ) - 1 ] )
|
||||
&& $basket_name_array[ count( $basket_name_array ) - 1 ] !== $this->get_source_language() )
|
||||
|| ( is_numeric( $basket_name_array[ count( $basket_name_array ) - 1 ] )
|
||||
&& $basket_name_array[ count( $basket_name_array ) - 2 ] !== $this->get_source_language() )
|
||||
? $name . '|' . $this->get_source_language() : $name;
|
||||
|
||||
$name = mb_strlen( $name ) > $max_length
|
||||
? $this->sanitize_basket_name( $name, $max_length ) : $name;
|
||||
|
||||
if ( self::get_batch_id_from_name( $name ) ) {
|
||||
$suffix = 2;
|
||||
$name = $this->sanitize_basket_name( $name, $max_length - mb_strlen( (string) $suffix ) - 1 );
|
||||
while ( self::get_batch_id_from_name( $name . '|' . $suffix ) ) {
|
||||
$suffix ++;
|
||||
$name = $this->sanitize_basket_name( $name, $max_length - mb_strlen( (string) $suffix ) - 1 );
|
||||
}
|
||||
$name .= '|' . $suffix;
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_source_language() {
|
||||
|
||||
return TranslationProxy_Basket::get_source_language();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $package_id
|
||||
*/
|
||||
public function remove_package( $package_id ) {
|
||||
TranslationProxy_Basket::delete_item_from_basket( $package_id, 'package' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param string $kind
|
||||
*/
|
||||
public function remove_item( $id, $kind ) {
|
||||
TranslationProxy_Basket::delete_item_from_basket( $id, $kind );
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the basket portion with the saved basket
|
||||
*
|
||||
* @param array $basket_portion
|
||||
*/
|
||||
public function update_basket( $basket_portion = array() ) {
|
||||
TranslationProxy_Basket::update_basket( $basket_portion );
|
||||
}
|
||||
|
||||
private function sanitize_basket_name( $basket_name, $max_length ) {
|
||||
// input basket name is separated by pipes so we explode it
|
||||
$to_trim = mb_strlen( $basket_name ) - $max_length;
|
||||
if ( $to_trim <= 0 ) {
|
||||
return $basket_name;
|
||||
}
|
||||
$basket_name_array = explode( '|', $basket_name );
|
||||
$wpml_flag = count( $basket_name_array ) < 3;
|
||||
|
||||
if ( $wpml_flag === false && count( $basket_name_array ) < 2 ) {
|
||||
|
||||
return mb_substr( $basket_name, $max_length - 1 );
|
||||
}
|
||||
|
||||
// first we trim the middle part holding the "WPML"
|
||||
if ( $wpml_flag ) {
|
||||
list( $basket_name_array, $to_trim ) = $this->shorten_basket_name( $basket_name_array, 1, $to_trim );
|
||||
}
|
||||
// then trim the site name first, if that's not enough move the array index and also trim the language
|
||||
for ( $i = 0; $i <= 1; $i ++ ) {
|
||||
if ( $to_trim > 0 ) {
|
||||
list( $basket_name_array, $to_trim ) = $this->shorten_basket_name( $basket_name_array, 0, $to_trim );
|
||||
$basket_name_array = array_filter( $basket_name_array );
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$basket_name_array = array_filter( $basket_name_array );
|
||||
|
||||
return implode( '|', $basket_name_array );
|
||||
}
|
||||
|
||||
private function shorten_basket_name( $name_array, $index, $to_trim ) {
|
||||
if ( mb_strlen( $name_array [ $index ] ) > $to_trim ) {
|
||||
$name_array[ $index ] = mb_substr( $name_array[ $index ], 0, mb_strlen( $name_array [ $index ] ) - $to_trim - 1 );
|
||||
$name_array = array_filter( $name_array );
|
||||
$to_trim = 0;
|
||||
} else {
|
||||
$to_trim = $to_trim - mb_strlen( $name_array [ $index ] ) - 1; // subtract one here since we lose a downstroke
|
||||
unset( $name_array [ $index ] );
|
||||
}
|
||||
|
||||
return array( $name_array, $to_trim );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the batch id for a given basket or batch name
|
||||
*
|
||||
* @param string $basket_name
|
||||
*
|
||||
* @return int|bool
|
||||
*/
|
||||
WPML_Translation_Basket::macro(
|
||||
'get_batch_id_from_name',
|
||||
curryN(
|
||||
1,
|
||||
Cache::memorize(
|
||||
'get_batch_id_from_name',
|
||||
pipe(
|
||||
Str::replace( '"', '\\"' ),
|
||||
sanitizeString(),
|
||||
TranslationProxy_Batch::getBatchId()
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Translation_Proxy_Basket_Networking
|
||||
*/
|
||||
class WPML_Translation_Proxy_Basket_Networking {
|
||||
|
||||
/** @var WPML_Translation_Basket $basket */
|
||||
private $basket;
|
||||
|
||||
/** @var TranslationManagement $tm_instance */
|
||||
private $tm_instance;
|
||||
|
||||
/**
|
||||
* @param WPML_Translation_Basket $basket
|
||||
* @param TranslationManagement $tm_instance
|
||||
*/
|
||||
function __construct( $basket, &$tm_instance ) {
|
||||
$this->basket = $basket;
|
||||
$this->tm_instance = $tm_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WPML_TM_Translation_Batch $batch
|
||||
*
|
||||
* @uses \WPML_Translation_Basket::get_basket Gets the array representation of the translation basket
|
||||
* @uses \WPML_Translation_Proxy_Basket_Networking::generate_batch generates the batch in case no chunk was given for the commit from the basket
|
||||
* @uses \WPML_Translation_Proxy_Basket_Networking::get_batch_name
|
||||
* @uses \WPML_Translation_Proxy_Basket_Networking::send_all_jobs
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function commit_basket_chunk( WPML_TM_Translation_Batch $batch ) {
|
||||
$result = $this->send_all_jobs( $batch );
|
||||
$error_messages = $this->tm_instance->messages_by_type( 'error' );
|
||||
if ( ( $has_error = (bool) $error_messages ) === true ) {
|
||||
\WPML\TM\API\Batch::rollback( $batch->get_basket_name() );
|
||||
$result['message'] = '';
|
||||
$result['additional_messages'] = $error_messages;
|
||||
}
|
||||
|
||||
return array( $has_error, $result, $error_messages );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an array of translators has any remote translators in it.
|
||||
*
|
||||
* @param array $translators
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function contains_remote_translators( array $translators ) {
|
||||
|
||||
return count( array_filter( $translators, 'is_numeric' ) ) < count( $translators );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends all jobs from basket in batch mode to translation proxy
|
||||
*
|
||||
* @param WPML_TM_Translation_Batch $batch
|
||||
* @param array $translators
|
||||
* @param array $batch_options
|
||||
*
|
||||
* @return bool false in case of errors (read from TranslationManagement::get_messages('error') to get errors details)
|
||||
*/
|
||||
private function send_all_jobs( WPML_TM_Translation_Batch $batch ) {
|
||||
$this->basket->set_options( $batch->get_batch_options() );
|
||||
$this->basket->set_name( $batch->get_basket_name() );
|
||||
|
||||
$this->basket->set_remote_target_languages( $batch->get_remote_target_languages() );
|
||||
$basket_items_types = $this->basket->get_item_types();
|
||||
foreach ( $basket_items_types as $item_type_name => $item_type ) {
|
||||
do_action(
|
||||
'wpml_tm_send_' . $item_type_name . '_jobs',
|
||||
$batch,
|
||||
$item_type_name,
|
||||
\WPML\TM\API\Jobs::SENT_VIA_BASKET
|
||||
);
|
||||
}
|
||||
|
||||
// check if there were no errors
|
||||
return ! $this->tm_instance->messages_by_type( 'error' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the batch array for posts in the basket.
|
||||
*
|
||||
* @param array $basket
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function generate_batch( array $basket ) {
|
||||
$batch = array();
|
||||
|
||||
$posts = isset( $basket['post'] ) ? $basket['post'] : array();
|
||||
foreach ( $posts as $post_id => $post ) {
|
||||
$batch[] = array(
|
||||
'type' => 'post',
|
||||
'post_id' => $post_id,
|
||||
);
|
||||
}
|
||||
|
||||
return $batch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the batch that contains the given post_id.
|
||||
*
|
||||
* @param int $post_id
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
private function get_batch_name( $post_id ) {
|
||||
global $wpdb;
|
||||
|
||||
$name = $wpdb->get_var(
|
||||
$wpdb->prepare(
|
||||
" SELECT b.batch_name
|
||||
FROM {$wpdb->prefix}icl_translation_batches b
|
||||
JOIN {$wpdb->prefix}icl_translation_status s
|
||||
ON s.batch_id = b.id
|
||||
JOIN {$wpdb->prefix}icl_translations t
|
||||
ON t.translation_id = s.translation_id
|
||||
JOIN {$wpdb->prefix}icl_translations o
|
||||
ON o.trid = t.trid
|
||||
AND o.language_code = t.source_language_code
|
||||
JOIN {$wpdb->posts} p
|
||||
ON o.element_id = p.ID
|
||||
AND o.element_type = CONCAT('post_', p.post_type)
|
||||
WHERE o.element_id = %d
|
||||
ORDER BY b.id
|
||||
LIMIT 1",
|
||||
$post_id
|
||||
)
|
||||
);
|
||||
$this->basket->set_name( $name );
|
||||
|
||||
return $name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
|
||||
jQuery(function () {
|
||||
jQuery('#icl-migrate-start').one('click', function () {
|
||||
iclStepper(jQuery(this).attr('href'), '&init=1', true);
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
function iclStepper(href, addUrl, init) {
|
||||
init = typeof(init) != 'undefined' ? true : false;
|
||||
jQuery.ajax({
|
||||
type: "POST",
|
||||
url: href+addUrl,
|
||||
cache: false,
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
if (data.stop == true) {
|
||||
jQuery('#icl-migrate-progress .message').html('stopped');
|
||||
} else if (data.error == false) {
|
||||
if (init == true) {
|
||||
jQuery('#icl-migrate-start').fadeOut(function(){
|
||||
jQuery('#icl-migrate-progress').fadeIn().html(data.output).children('.message').html(data.message);
|
||||
iclStepper(href, '&step='+data.step);
|
||||
});
|
||||
// jQuery('#icl-migrate-progress').html(data.output).children('.message').html(data.message);
|
||||
} else {
|
||||
jQuery('#icl-migrate-progress .message').html(data.message);
|
||||
jQuery('#icl-migrate-progress .progress').animate({
|
||||
width : data.barWidth+'%'
|
||||
}, 100);
|
||||
if (data.completed == true) {
|
||||
jQuery('#icl-migrate').delay(3000).fadeOut();
|
||||
} else {
|
||||
iclStepper(href, '&step='+data.step);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
alert('error');
|
||||
jQuery('#icl-migrate-progress .message').html(data.error);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
class Icl_Stepper {
|
||||
|
||||
|
||||
/**
|
||||
* Added dummy element to match number of elements and to cover init action
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_steps = array( null );
|
||||
/**
|
||||
* Current step
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $_step;
|
||||
/**
|
||||
* Next step can be forced with Icl_Stepper::setNextStep()
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $_nextStep = null;
|
||||
|
||||
/**
|
||||
* Provide current step here
|
||||
*
|
||||
* @param int $step
|
||||
*/
|
||||
function __construct( $step = 0 ) {
|
||||
if ( empty( $step ) ) {
|
||||
$step = 0;
|
||||
}
|
||||
$this->_step = intval( $step );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register steps (function names)
|
||||
*/
|
||||
public function registerSteps() {
|
||||
$args = func_get_args();
|
||||
$this->_steps = array_merge( $this->_steps, $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current step
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getStep() {
|
||||
return $this->_step;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns next step
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getNextStep() {
|
||||
return ! is_null( $this->_nextStep ) ? $this->_nextStep : $this->_step += 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets current step
|
||||
*
|
||||
* @param int $num
|
||||
*/
|
||||
public function setStep( $num ) {
|
||||
$this->_step = intval( $num );
|
||||
}
|
||||
|
||||
/**
|
||||
* Forcing next step
|
||||
*
|
||||
* @param int $num
|
||||
*/
|
||||
public function setNextStep( $num ) {
|
||||
$this->_nextStep = intval( $num );
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates bar width
|
||||
*
|
||||
* @return int Should be used as percentage width (%)
|
||||
*/
|
||||
public function barWidth() {
|
||||
return round( ( $this->_step * 100 ) / count( $this->_steps ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls current step's function
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function init() {
|
||||
if ( $this->_step !== 0 && isset( $this->_steps[ $this->_step ] )
|
||||
&& is_callable( $this->_steps[ $this->_step ] ) ) {
|
||||
return call_user_func_array( $this->_steps[ $this->_step ], array( $this->_step, $this ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns initial HTML formatted screen
|
||||
*
|
||||
* @param string $message Message to be displayed
|
||||
* @return string
|
||||
*/
|
||||
public function render( $message = '' ) {
|
||||
$output = '<div class="progress-bar" style="width: 100%; height: 15px; background-color: #FFFFFFF; border: 1px solid #e6db55;">
|
||||
<div class="progress" style="height: 100%; background-color: Yellow; width: ' . $this->barWidth() . '%;"></div>
|
||||
</div>
|
||||
<div class="message" style="clear:both;">' . $message . '</div>';
|
||||
return $output;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
function update_string_statuses() {
|
||||
global $wpdb;
|
||||
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'icl_string_translations',
|
||||
array(
|
||||
'status' => ICL_TM_COMPLETE,
|
||||
'batch_id' => 0,
|
||||
),
|
||||
array(
|
||||
'batch_id' => -1,
|
||||
'status' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'icl_string_translations',
|
||||
array(
|
||||
'status' => ICL_TM_NEEDS_UPDATE,
|
||||
'batch_id' => 0,
|
||||
),
|
||||
array(
|
||||
'batch_id' => -1,
|
||||
'status' => 2,
|
||||
)
|
||||
);
|
||||
|
||||
$wpdb->update(
|
||||
$wpdb->prefix . 'icl_string_translations',
|
||||
array(
|
||||
'status' => ICL_TM_WAITING_FOR_TRANSLATOR,
|
||||
'batch_id' => 0,
|
||||
),
|
||||
array(
|
||||
'batch_id' => -1,
|
||||
'status' => 11,
|
||||
)
|
||||
);
|
||||
$sql = "ALTER TABLE `{$wpdb->prefix}icl_string_translations` CHANGE batch_id batch_id int DEFAULT 0 NOT NULL;";
|
||||
$wpdb->query( $sql );
|
||||
|
||||
}
|
||||
|
||||
function fix_icl_string_status() {
|
||||
global $wpdb;
|
||||
|
||||
$wpdb->query(
|
||||
$wpdb->prepare(
|
||||
"UPDATE {$wpdb->prefix}icl_strings s
|
||||
SET s.status = %d
|
||||
WHERE EXISTS ( SELECT 1
|
||||
FROM {$wpdb->prefix}icl_string_translations st
|
||||
WHERE string_id = s.id AND st.status = %d )",
|
||||
ICL_TM_NEEDS_UPDATE,
|
||||
ICL_TM_NEEDS_UPDATE
|
||||
)
|
||||
);
|
||||
|
||||
$wpdb->query(
|
||||
$wpdb->prepare(
|
||||
"UPDATE {$wpdb->prefix}icl_strings s
|
||||
SET s.status = %d
|
||||
WHERE ( SELECT COUNT(string_id)
|
||||
FROM {$wpdb->prefix}icl_string_translations st
|
||||
WHERE st.string_id = s.id AND st.status = %d ) = (( SELECT COUNT(*)
|
||||
FROM {$wpdb->prefix}icl_languages
|
||||
WHERE active = 1) - 1)",
|
||||
ICL_TM_COMPLETE,
|
||||
ICL_TM_COMPLETE
|
||||
)
|
||||
);
|
||||
|
||||
$wpdb->query(
|
||||
$wpdb->prepare(
|
||||
"UPDATE {$wpdb->prefix}icl_strings s
|
||||
SET s.status = %d
|
||||
WHERE ( SELECT COUNT(string_id)
|
||||
FROM {$wpdb->prefix}icl_string_translations st
|
||||
WHERE st.string_id = s.id AND st.status = %d ) < (( SELECT COUNT(*)
|
||||
FROM {$wpdb->prefix}icl_languages
|
||||
WHERE active = 1) - 1)
|
||||
AND ( SELECT COUNT(string_id)
|
||||
FROM {$wpdb->prefix}icl_string_translations st2
|
||||
WHERE st2.string_id = s.id AND st2.status = %d ) > 0 ",
|
||||
2,
|
||||
ICL_TM_COMPLETE,
|
||||
ICL_TM_COMPLETE
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,319 @@
|
||||
<?php
|
||||
function icl_upgrade_2_0_0_steps( $step, $stepper ) {
|
||||
global $wpdb, $sitepress, $wp_post_types, $sitepress_settings;
|
||||
|
||||
if ( ! isset( $sitepress ) ) {
|
||||
$sitepress = new SitePress();
|
||||
}
|
||||
$TranslationManagement = new TranslationManagement();
|
||||
|
||||
$default_language = $sitepress->get_default_language();
|
||||
|
||||
define( 'ICL_TM_DISABLE_ALL_NOTIFICATIONS', true ); // make sure no notifications are being sent
|
||||
ini_set( 'max_execution_time', 300 );
|
||||
|
||||
$post_types = array_keys( $wp_post_types );
|
||||
foreach ( $post_types as $pt ) {
|
||||
$types[] = 'post_' . $pt;
|
||||
}
|
||||
|
||||
$temp_upgrade_data = get_option(
|
||||
'icl_temp_upgrade_data',
|
||||
array(
|
||||
'step' => 0,
|
||||
'offset' => 0,
|
||||
)
|
||||
);
|
||||
|
||||
switch ( $step ) {
|
||||
|
||||
case 1:
|
||||
// if the tables are missing, call the plugin activation routine
|
||||
$table_name = $wpdb->prefix . 'icl_translation_status';
|
||||
if ( $wpdb->get_var( "SHOW TABLES LIKE '{$table_name}'" ) != $table_name ) {
|
||||
icl_sitepress_activate();
|
||||
}
|
||||
|
||||
$wpdb->query( "ALTER TABLE `{$wpdb->prefix}icl_translations` CHANGE `element_type` `element_type` VARCHAR( 32 ) NOT NULL DEFAULT 'post_post'" );
|
||||
$wpdb->query( "ALTER TABLE `{$wpdb->prefix}icl_translations` CHANGE `element_id` `element_id` BIGINT( 20 ) NULL DEFAULT NULL " );
|
||||
|
||||
// fix source_language_code
|
||||
// all source documents must have null
|
||||
if ( isset( $types ) ) {
|
||||
$wpdb->query(
|
||||
$wpdb->prepare(
|
||||
"UPDATE {$wpdb->prefix}icl_translations SET source_language_code = NULL
|
||||
WHERE element_type IN('" . join( "','", $types ) . "') AND source_language_code = '' AND language_code=%s",
|
||||
$default_language
|
||||
)
|
||||
);
|
||||
// get translated documents with missing source language
|
||||
$res = $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
"
|
||||
SELECT translation_id, trid, language_code
|
||||
FROM {$wpdb->prefix}icl_translations
|
||||
WHERE (source_language_code = '' OR source_language_code IS NULL)
|
||||
AND element_type IN('" . join( "','", $types ) . "')
|
||||
AND language_code <> %s
|
||||
",
|
||||
$default_language
|
||||
)
|
||||
);
|
||||
foreach ( $res as $row ) {
|
||||
$wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->prefix}icl_translations SET source_language_code = %s WHERE translation_id=%d", $default_language, $row->translation_id ) );
|
||||
}
|
||||
}
|
||||
|
||||
$temp_upgrade_data['step'] = 2;
|
||||
update_option( 'icl_temp_upgrade_data', $temp_upgrade_data );
|
||||
|
||||
return array( 'message' => __( 'Processing translations...', 'sitepress' ) );
|
||||
break;
|
||||
|
||||
case 2:
|
||||
$limit = 100;
|
||||
$offset = $temp_upgrade_data['offset'];
|
||||
$processing = false;
|
||||
|
||||
// loop existing translations
|
||||
if ( isset( $types ) ) {
|
||||
$res = $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
"SELECT * FROM {$wpdb->prefix}icl_translations
|
||||
WHERE element_type IN(" . wpml_prepare_in( $types ) . ' )
|
||||
AND source_language_code IS NULL LIMIT %d OFFSET %d',
|
||||
array( $limit, $offset )
|
||||
)
|
||||
);
|
||||
foreach ( $res as $row ) {
|
||||
$processing = true;
|
||||
// grab translations
|
||||
$translations = $sitepress->get_element_translations( $row->trid, $row->element_type );
|
||||
|
||||
$md5 = 0;
|
||||
$table_name = $wpdb->prefix . 'icl_node';
|
||||
if ( $wpdb->get_var( "SHOW TABLES LIKE '{$table_name}'" ) == $table_name ) {
|
||||
list($md5, $links_fixed) = $wpdb->get_row(
|
||||
$wpdb->prepare(
|
||||
"
|
||||
SELECT md5, links_fixed FROM {$wpdb->prefix}icl_node
|
||||
WHERE nid = %d
|
||||
",
|
||||
$row->element_id
|
||||
),
|
||||
ARRAY_N
|
||||
);
|
||||
}
|
||||
if ( ! $md5 ) {
|
||||
$md5 = $TranslationManagement->post_md5( $row->element_id );
|
||||
}
|
||||
|
||||
$translation_package = $TranslationManagement->create_translation_package( $row->element_id );
|
||||
|
||||
foreach ( $translations as $lang => $t ) {
|
||||
if ( ! $t->original ) {
|
||||
|
||||
// determine service and status
|
||||
$service = 'local';
|
||||
$needs_update = 0;
|
||||
|
||||
list($rid, $status, $current_md5) = $wpdb->get_row(
|
||||
$wpdb->prepare(
|
||||
"
|
||||
SELECT c.rid, n.status , c.md5
|
||||
FROM {$wpdb->prefix}icl_content_status c
|
||||
JOIN {$wpdb->prefix}icl_core_status n ON c.rid = n.rid
|
||||
WHERE c.nid = %d AND target = %s
|
||||
ORDER BY rid DESC
|
||||
LIMIT 1
|
||||
",
|
||||
$row->element_id,
|
||||
$lang
|
||||
),
|
||||
ARRAY_N
|
||||
);
|
||||
|
||||
$translator_id = false;
|
||||
if ( $rid ) {
|
||||
if ( $current_md5 != $md5 ) {
|
||||
$needs_update = 1;
|
||||
}
|
||||
if ( $status == 3 ) {
|
||||
$status = 10;
|
||||
} else {
|
||||
$status = 2;
|
||||
}
|
||||
$service = 'icanlocalize';
|
||||
|
||||
foreach ( $sitepress_settings['icl_lang_status'] as $lpair ) {
|
||||
if ( $lpair['from'] == $row->language_code && $lpair['to'] == $lang && isset( $lpair['translators'][0]['id'] ) ) {
|
||||
$translator_id = $lpair['translators'][0]['id'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$status = 10;
|
||||
$translator_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_author FROM {$wpdb->posts} WHERE ID=%d", $t->element_id ) );
|
||||
$tlp = get_user_meta( $translator_id, $wpdb->prefix . 'language_pairs', true );
|
||||
$tlp[ $row->language_code ][ $lang ] = 1;
|
||||
if ( method_exists( $TranslationManagement, 'edit_translator' ) ) {
|
||||
$TranslationManagement->edit_translator( $translator_id, $tlp );
|
||||
}
|
||||
}
|
||||
|
||||
// add translation_status record
|
||||
list($newrid) = $TranslationManagement->update_translation_status(
|
||||
array(
|
||||
'translation_id' => $t->translation_id,
|
||||
'status' => $status,
|
||||
'translator_id' => $translator_id,
|
||||
'needs_update' => $needs_update,
|
||||
'md5' => $md5,
|
||||
'translation_service' => $service,
|
||||
'translation_package' => serialize( $translation_package ),
|
||||
'links_fixed' => intval( isset( $links_fixed ) ? $links_fixed : 0 ),
|
||||
)
|
||||
);
|
||||
|
||||
$job_id = $TranslationManagement->add_translation_job( $newrid, $translator_id, $translation_package );
|
||||
if ( $job_id && $status == 10 ) {
|
||||
do_action( 'wpml_save_job_fields_from_post', $job_id );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( $processing ) {
|
||||
update_option(
|
||||
'icl_temp_upgrade_data',
|
||||
array(
|
||||
'step' => 2,
|
||||
'offset' => intval( $offset + 100 ),
|
||||
)
|
||||
);
|
||||
$stepper->setNextStep( 2 );
|
||||
} else {
|
||||
update_option(
|
||||
'icl_temp_upgrade_data',
|
||||
array(
|
||||
'step' => 3,
|
||||
'offset' => 99999999999999999999,
|
||||
)
|
||||
);
|
||||
}
|
||||
$message = $processing ? __( 'Processing translations...', 'sitepress' ) : __( 'Finalizing upgrade...', 'sitepress' );
|
||||
return array( 'message' => $message );
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// removing the plugins text table; importing data into a SitePress setting
|
||||
$results = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}icl_plugins_texts" );
|
||||
if ( ! empty( $results ) ) {
|
||||
foreach ( $results as $row ) {
|
||||
$cft[ $row->attribute_name ] = $row->translate + 1;
|
||||
}
|
||||
if ( isset( $cft ) ) {
|
||||
$iclsettings['translation-management']['custom_fields_translation'] = $cft;
|
||||
$sitepress->save_settings( $iclsettings );
|
||||
}
|
||||
|
||||
$wpdb->query( "DROP TABLE {$wpdb->prefix}icl_plugins_texts" );
|
||||
}
|
||||
|
||||
$iclsettings['language_selector_initialized'] = 1;
|
||||
|
||||
if ( get_option( '_force_mp_post_http' ) ) {
|
||||
$iclsettings['troubleshooting_options']['http_communication'] = intval( get_option( '_force_mp_post_http' ) );
|
||||
delete_option( '_force_mp_post_http' );
|
||||
}
|
||||
|
||||
$sitepress->save_settings( $iclsettings );
|
||||
|
||||
$iclsettings['migrated_2_0_0'] = 1;
|
||||
$sitepress->save_settings( $iclsettings );
|
||||
delete_option( 'icl_temp_upgrade_data' );
|
||||
return array(
|
||||
'message' => __( 'Done', 'sitepress' ),
|
||||
'completed' => 1,
|
||||
);
|
||||
break;
|
||||
|
||||
default:
|
||||
return array(
|
||||
'error' => __( 'Missing step', 'sitepress' ),
|
||||
'stop' => 1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// $iclsettings defined in upgrade.php
|
||||
if ( empty( $iclsettings['migrated_2_0_0'] ) ) {
|
||||
wp_enqueue_script( 'icl-stepper', ICL_PLUGIN_URL . '/inc/upgrade-functions/2.0.0/stepper.js', array( 'jquery' ) );
|
||||
add_filter( 'admin_notices', 'icl_migrate_2_0_0' );
|
||||
add_action( 'icl_ajx_custom_call', 'icl_ajx_upgrade_2_0_0', 1, 2 );
|
||||
}
|
||||
|
||||
|
||||
function icl_migrate_2_0_0() {
|
||||
$ajax_action = 'wpml_upgrade_2_0_0';
|
||||
$ajax_action_none = wp_create_nonce( $ajax_action );
|
||||
$link = 'index.php?icl_ajx_action=' . $ajax_action . '&nonce=' . $ajax_action_none;
|
||||
$txt = get_option( 'icl_temp_upgrade_data', false ) ? __( 'Resume Upgrade Process', 'sitepress' ) : __( 'Run Upgrade Process', 'sitepress' );
|
||||
echo '<div class="message error" id="icl-migrate"><p><strong>' . __( 'WPML requires database upgrade', 'sitepress' ) . '</strong></p>'
|
||||
. '<p>' . __( 'This normally takes a few seconds, but may last up to several minutes of very large databases.', 'sitepress' ) . '</p>'
|
||||
. '<p><a href="' . $link . '" style="" id="icl-migrate-start">' . $txt . '</a></p>'
|
||||
. '<div id="icl-migrate-progress" style="display:none; margin: 10px 0 20px 0;">'
|
||||
. '</div></div>';
|
||||
}
|
||||
|
||||
function icl_ajx_upgrade_2_0_0( $call, $request ) {
|
||||
if ( $call == 'wpml_upgrade_2_0_0' ) {
|
||||
$error = 0;
|
||||
$completed = 0;
|
||||
$stop = 0;
|
||||
$message = __( 'Starting the upgrade process...', 'sitepress' );
|
||||
include_once WPML_PLUGIN_PATH . '/inc/upgrade-functions/2.0.0/stepper.php';
|
||||
include_once WPML_PLUGIN_PATH . '/inc/upgrade-functions/upgrade-2.0.0.php';
|
||||
$temp_upgrade_data = get_option(
|
||||
'icl_temp_upgrade_data',
|
||||
array(
|
||||
'step' => 0,
|
||||
'offset' => 0,
|
||||
)
|
||||
);
|
||||
$step = isset( $request['step'] ) ? $request['step'] : $temp_upgrade_data['step'];
|
||||
$migration = new Icl_Stepper( $step );
|
||||
$migration->registerSteps(
|
||||
'icl_upgrade_2_0_0_steps',
|
||||
'icl_upgrade_2_0_0_steps',
|
||||
'icl_upgrade_2_0_0_steps'
|
||||
);
|
||||
if ( isset( $request['init'] ) ) {
|
||||
echo json_encode(
|
||||
array(
|
||||
'error' => $error,
|
||||
'output' => $migration->render(),
|
||||
'step' => $migration->getNextStep(),
|
||||
'message' => __( 'Creating new tables...', 'sitepress' ),
|
||||
'stop' => $stop,
|
||||
)
|
||||
);
|
||||
exit;
|
||||
}
|
||||
$data = $migration->init();
|
||||
@extract( $data, EXTR_OVERWRITE );
|
||||
echo json_encode(
|
||||
array(
|
||||
'error' => $error,
|
||||
'completed' => $completed,
|
||||
'message' => $message,
|
||||
'step' => $migration->getNextStep(),
|
||||
'barWidth' => $migration->barWidth(),
|
||||
'stop' => $stop,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user