PageRenderTime 97ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/htdocs/wp-content/plugins/sitepress-multilingual-cms/inc/translation-management/translation-management.class.php

https://bitbucket.org/dkrzos/phc
PHP | 3758 lines | 2883 code | 573 blank | 302 comment | 611 complexity | 6562e9287eb76105f6468d7ba157806a MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. define ( 'ICL_TM_NOT_TRANSLATED', 0);
  3. define ( 'ICL_TM_WAITING_FOR_TRANSLATOR', 1);
  4. define ( 'ICL_TM_IN_PROGRESS', 2);
  5. define ( 'ICL_TM_NEEDS_UPDATE', 3); //virt. status code (based on needs_update)
  6. define ( 'ICL_TM_DUPLICATE', 9);
  7. define ( 'ICL_TM_COMPLETE', 10);
  8. define('ICL_TM_NOTIFICATION_NONE', 0);
  9. define('ICL_TM_NOTIFICATION_IMMEDIATELY', 1);
  10. define('ICL_TM_NOTIFICATION_DAILY', 2);
  11. define('ICL_TM_TMETHOD_MANUAL', 0);
  12. define('ICL_TM_TMETHOD_EDITOR', 1);
  13. define('ICL_TM_TMETHOD_PRO', 2);
  14. define('ICL_TM_DOCS_PER_PAGE', 20);
  15. $asian_languages = array('ja', 'ko', 'zh-hans', 'zh-hant', 'mn', 'ne', 'hi', 'pa', 'ta', 'th');
  16. class TranslationManagement{
  17. private $selected_translator = array('ID'=>0);
  18. private $current_translator = array('ID'=>0);
  19. public $messages = array();
  20. public $dashboard_select = array();
  21. public $settings;
  22. public $admin_texts_to_translate = array();
  23. function __construct(){
  24. add_action('init', array($this, 'init'), 15);
  25. if(isset($_GET['icl_tm_message'])){
  26. $this->messages[] = array(
  27. 'type' => isset($_GET['icl_tm_message_type']) ? $_GET['icl_tm_message_type'] : 'updated',
  28. 'text' => $_GET['icl_tm_message']
  29. );
  30. }
  31. add_action('save_post', array($this, 'save_post_actions'), 11, 2); // calling *after* the Sitepress actions
  32. add_action('delete_post', array($this, 'delete_post_actions'), 1, 1); // calling *before* the Sitepress actions
  33. add_action('icl_ajx_custom_call', array($this, 'ajax_calls'), 10, 2);
  34. add_action('wp_ajax_show_post_content', array($this, '_show_post_content'));
  35. if(isset($_GET['sm']) && ($_GET['sm'] == 'dashboard' || $_GET['sm'] == 'jobs')){@session_start();}
  36. elseif(isset($_GET['page']) && preg_match('@/menu/translations-queue\.php$@', $_GET['page'])){@session_start();}
  37. add_filter('icl_additional_translators', array($this, 'icl_additional_translators'), 99, 3);
  38. add_filter('icl_translators_list', array($this, 'icanlocalize_translators_list'));
  39. add_action('user_register', array($this, 'clear_cache'));
  40. add_action('profile_update', array($this, 'clear_cache'));
  41. add_action('delete_user', array($this, 'clear_cache'));
  42. add_action('added_existing_user', array($this, 'clear_cache'));
  43. add_action('remove_user_from_blog', array($this, 'clear_cache'));
  44. add_action('admin_print_scripts', array($this, '_inline_js_scripts'));
  45. add_action('wp_ajax_icl_tm_user_search', array($this, '_user_search'));
  46. }
  47. function save_settings(){
  48. global $sitepress;
  49. $iclsettings['translation-management'] = $this->settings;
  50. $sitepress->save_settings($iclsettings);
  51. }
  52. function init(){
  53. global $wpdb, $current_user, $sitepress_settings, $sitepress, $pagenow;
  54. $this->settings =& $sitepress_settings['translation-management'];
  55. //logic for syncing comments
  56. if($sitepress->get_option('sync_comments_on_duplicates')){
  57. add_action('delete_comment', array($this, 'duplication_delete_comment'));
  58. add_action('edit_comment', array($this, 'duplication_edit_comment'));
  59. add_action('wp_set_comment_status', array($this, 'duplication_status_comment'), 10, 2);
  60. add_action('wp_insert_comment', array($this, 'duplication_insert_comment'), 100);
  61. }
  62. $this->initial_custom_field_translate_states();
  63. // defaults
  64. if(!isset($this->settings['notification']['new-job'])) $this->settings['notification']['new-job'] = ICL_TM_NOTIFICATION_IMMEDIATELY;
  65. if(!isset($this->settings['notification']['completed'])) $this->settings['notification']['completed'] = ICL_TM_NOTIFICATION_IMMEDIATELY;
  66. if(!isset($this->settings['notification']['resigned'])) $this->settings['notification']['resigned'] = ICL_TM_NOTIFICATION_IMMEDIATELY;
  67. if(!isset($this->settings['notification']['dashboard'])) $this->settings['notification']['dashboard'] = true;
  68. if(!isset($this->settings['notification']['purge-old'])) $this->settings['notification']['purge-old'] = 7;
  69. if(!isset($this->settings['custom_fields_translation'])) $this->settings['custom_fields_translation'] = array();
  70. if(!isset($this->settings['doc_translation_method'])) $this->settings['doc_translation_method'] = ICL_TM_TMETHOD_MANUAL;
  71. get_currentuserinfo();
  72. if(isset($current_user->ID)){
  73. $user = new WP_User($current_user->ID);
  74. }
  75. if(empty($user->data)) return;
  76. $ct['translator_id'] = $current_user->ID;
  77. $ct['display_name'] = isset($user->data->display_name) ? $user->data->display_name : $user->data->user_login;
  78. $ct['user_login'] = $user->data->user_login;
  79. $ct['language_pairs'] = get_user_meta($current_user->ID, $wpdb->prefix.'language_pairs', true);
  80. if(empty($ct['language_pairs'])) $ct['language_pairs'] = array();
  81. $this->current_translator = (object)$ct;
  82. $this->load_config_pre_process();
  83. $this->load_plugins_wpml_config();
  84. $this->load_theme_wpml_config();
  85. $this->load_config_post_process();
  86. if(isset($_POST['icl_tm_action'])){
  87. $this->process_request($_POST['icl_tm_action'], $_POST);
  88. }elseif(isset($_GET['icl_tm_action'])){
  89. $this->process_request($_GET['icl_tm_action'], $_GET);
  90. }
  91. //$this->load_plugins_wpml_config();
  92. //$this->load_theme_wpml_config();
  93. if($GLOBALS['pagenow']=='edit.php'){ // use standard WP admin notices
  94. add_action('admin_notices', array($this, 'show_messages'));
  95. }else{ // use custom WP admin notices
  96. add_action('icl_tm_messages', array($this, 'show_messages'));
  97. }
  98. if(isset($_GET['page']) && basename($_GET['page']) == 'translations-queue.php' && isset($_GET['job_id'])){
  99. add_filter('admin_head',array($this, '_show_tinyMCE'));
  100. }
  101. //if(!isset($this->settings['doc_translation_method'])){
  102. if(isset($this->settings['doc_translation_method']) && $this->settings['doc_translation_method'] < 0 ){
  103. if(isset($_GET['sm']) && $_GET['sm']=='mcsetup' && isset($_GET['src']) && $_GET['src']=='notice'){
  104. $this->settings['doc_translation_method'] = ICL_TM_TMETHOD_MANUAL;
  105. $this->save_settings();
  106. }else{
  107. add_action('admin_notices', array($this, '_translation_method_notice'));
  108. }
  109. }
  110. if(defined('WPML_TM_VERSION') && isset($_GET['page']) && $_GET['page'] == WPML_TM_FOLDER. '/menu/main.php' && isset($_GET['sm']) && $_GET['sm'] == 'translators'){
  111. $iclsettings =& $sitepress_settings;
  112. $sitepress->get_icl_translator_status($iclsettings);
  113. $sitepress->save_settings($iclsettings);
  114. }
  115. // default settings
  116. if(empty($this->settings['doc_translation_method']) || !defined('WPML_TM_VERSION')){
  117. $this->settings['doc_translation_method'] = ICL_TM_TMETHOD_MANUAL;
  118. }
  119. }
  120. function initial_custom_field_translate_states() {
  121. global $wpdb;
  122. $cf_keys_limit = 1000; // jic
  123. $custom_keys = $wpdb->get_col( "
  124. SELECT meta_key
  125. FROM $wpdb->postmeta
  126. GROUP BY meta_key
  127. ORDER BY meta_key
  128. LIMIT $cf_keys_limit" );
  129. $changed = false;
  130. foreach($custom_keys as $cfield) {
  131. if(empty($this->settings['custom_fields_translation'][$cfield]) || $this->settings['custom_fields_translation'][$cfield] == 0) {
  132. // see if a plugin handles this field
  133. $override = apply_filters('icl_cf_translate_state', 'nothing', $cfield);
  134. switch($override) {
  135. case 'nothing':
  136. break;
  137. case 'ignore':
  138. $changed = true;
  139. $this->settings['custom_fields_translation'][$cfield] = 3;
  140. break;
  141. case 'translate':
  142. $changed = true;
  143. $this->settings['custom_fields_translation'][$cfield] = 2;
  144. break;
  145. case 'copy':
  146. $changed = true;
  147. $this->settings['custom_fields_translation'][$cfield] = 1;
  148. break;
  149. }
  150. }
  151. }
  152. if ($changed) {
  153. $this->save_settings();
  154. }
  155. }
  156. function _translation_method_notice(){
  157. echo '<div class="error fade"><p id="icl_side_by_site">'.sprintf(__('New - side-by-site translation editor: <a href="%s">try it</a> | <a href="#cancel">no thanks</a>.', 'sitepress'),
  158. admin_url('admin.php?page='.WPML_TM_FOLDER.'/menu/main.php&sm=mcsetup&src=notice')) . '</p></div>';
  159. }
  160. function _show_tinyMCE() {
  161. wp_print_scripts('editor');
  162. //add_filter('the_editor', array($this, 'editor_directionality'), 9999);
  163. add_filter('tiny_mce_before_init', array($this, '_mce_set_direction'), 9999);
  164. add_filter('mce_buttons', array($this, '_mce_remove_fullscreen'), 9999);
  165. if (version_compare($GLOBALS['wp_version'], '3.1.4', '<=') && function_exists('wp_tiny_mce'))
  166. try{
  167. @wp_tiny_mce();
  168. } catch(Exception $e) { /*don't do anything with this */ }
  169. }
  170. function _mce_remove_fullscreen($options){
  171. foreach($options as $k=>$v) if($v == 'fullscreen') unset($options[$k]);
  172. return $options;
  173. }
  174. function _inline_js_scripts(){
  175. // remove fullscreen mode
  176. if(defined('WPML_TM_FOLDER') && isset($_GET['page']) && $_GET['page'] == WPML_TM_FOLDER . '/menu/translations-queue.php' && isset($_GET['job_id'])){
  177. ?>
  178. <script type="text/javascript">addLoadEvent(function(){jQuery('#ed_fullscreen').remove();});</script>
  179. <?php
  180. }
  181. }
  182. function _mce_set_direction($settings) {
  183. $job = $this->get_translation_job((int)$_GET['job_id'], false, true);
  184. if (!empty($job)) {
  185. $rtl_translation = in_array($job->language_code, array('ar','he','fa'));
  186. if ($rtl_translation) {
  187. $settings['directionality'] = 'rtl';
  188. } else {
  189. $settings['directionality'] = 'ltr';
  190. }
  191. }
  192. return $settings;
  193. }
  194. /*
  195. function editor_directionality($tag) {
  196. $job = $this->get_translation_job((int)$_GET['job_id'], false, true);
  197. $rtl_translation = in_array($job->language_code, array('ar','he','fa'));
  198. if ($rtl_translation) {
  199. $dir = 'dir="rtl"';
  200. } else {
  201. $dir = 'dir="ltr"';
  202. }
  203. return str_replace('<textarea', '<textarea ' . $dir, $tag);
  204. }
  205. */
  206. function process_request($action, $data){
  207. $data = stripslashes_deep($data);
  208. switch($action){
  209. case 'add_translator':
  210. if(wp_create_nonce('add_translator') == $data['add_translator_nonce']){
  211. // Initial adding
  212. if (isset($data['from_lang']) && isset($data['to_lang'])) {
  213. $data['lang_pairs'] = array();
  214. $data['lang_pairs'][$data['from_lang']] = array($data['to_lang'] => 1);
  215. }
  216. $this->add_translator($data['user_id'], $data['lang_pairs']);
  217. $_user = new WP_User($data['user_id']);
  218. wp_redirect('admin.php?page='.WPML_TM_FOLDER.'/menu/main.php&sm=translators&icl_tm_message='.urlencode(sprintf(__('%s has been added as a translator for this site.','sitepress'),$_user->data->display_name)).'&icl_tm_message_type=updated');
  219. }
  220. break;
  221. case 'edit_translator':
  222. if(wp_create_nonce('edit_translator') == $data['edit_translator_nonce']){
  223. $this->edit_translator($data['user_id'], $data['lang_pairs']);
  224. $_user = new WP_User($data['user_id']);
  225. wp_redirect('admin.php?page='.WPML_TM_FOLDER.'/menu/main.php&sm=translators&icl_tm_message='.urlencode(sprintf(__('Language pairs for %s have been edited.','sitepress'),$_user->data->display_name)).'&icl_tm_message_type=updated');
  226. }
  227. break;
  228. case 'remove_translator':
  229. if(wp_create_nonce('remove_translator') == $data['remove_translator_nonce']){
  230. $this->remove_translator($data['user_id']);
  231. $_user = new WP_User($data['user_id']);
  232. wp_redirect('admin.php?page='.WPML_TM_FOLDER.'/menu/main.php&sm=translators&icl_tm_message='.urlencode(sprintf(__('%s has been removed as a translator for this site.','sitepress'),$_user->data->display_name)).'&icl_tm_message_type=updated');
  233. }
  234. break;
  235. case 'edit':
  236. $this->selected_translator['ID'] = intval($data['user_id']);
  237. break;
  238. case 'dashboard_filter':
  239. $_SESSION['translation_dashboard_filter'] = $data['filter'];
  240. wp_redirect('admin.php?page='.WPML_TM_FOLDER . '/menu/main.php&sm=dashboard');
  241. break;
  242. case 'sort':
  243. if(isset($data['sort_by'])) $_SESSION['translation_dashboard_filter']['sort_by'] = $data['sort_by'];
  244. if(isset($data['sort_order'])) $_SESSION['translation_dashboard_filter']['sort_order'] = $data['sort_order'];
  245. break;
  246. case 'reset_filters':
  247. unset($_SESSION['translation_dashboard_filter']);
  248. break;
  249. case 'send_jobs':
  250. if(isset($data['iclnonce']) && wp_verify_nonce($data['iclnonce'], 'pro-translation-icl')){
  251. $this->send_jobs($data);
  252. }
  253. break;
  254. case 'jobs_filter':
  255. $_SESSION['translation_jobs_filter'] = $data['filter'];
  256. wp_redirect('admin.php?page='.WPML_TM_FOLDER . '/menu/main.php&sm=jobs');
  257. break;
  258. case 'ujobs_filter':
  259. $_SESSION['translation_ujobs_filter'] = $data['filter'];
  260. wp_redirect('admin.php?page='.WPML_TM_FOLDER . '/menu/translations-queue.php');
  261. break;
  262. case 'save_translation':
  263. if(!empty($data['resign'])){
  264. $this->resign_translator($data['job_id']);
  265. wp_redirect(admin_url('admin.php?page='.WPML_TM_FOLDER.'/menu/translations-queue.php&resigned='.$data['job_id']));
  266. exit;
  267. }else{
  268. $this->save_translation($data);
  269. }
  270. break;
  271. case 'save_notification_settings':
  272. $this->settings['notification'] = $data['notification'];
  273. $this->save_settings();
  274. $this->messages[] = array(
  275. 'type'=>'updated',
  276. 'text' => __('Preferences saved.', 'sitepress')
  277. );
  278. break;
  279. case 'create_job':
  280. global $current_user;
  281. if(!isset($this->current_translator->ID) && isset($current_user->ID)){
  282. $this->current_translator->ID = $current_user->ID;
  283. }
  284. $data['translator'] = $this->current_translator->ID;
  285. $job_ids = $this->send_jobs($data);
  286. wp_redirect('admin.php?page='.WPML_TM_FOLDER . '/menu/translations-queue.php&job_id=' . array_pop($job_ids));
  287. break;
  288. case 'cancel_jobs':
  289. $ret = $this->cancel_translation_request($data['icl_translation_id']);
  290. $this->messages[] = array(
  291. 'type'=>'updated',
  292. 'text' => __('Translation requests cancelled.', 'sitepress')
  293. );
  294. break;
  295. }
  296. }
  297. function ajax_calls($call, $data){
  298. global $wpdb, $sitepress, $sitepress_settings;
  299. switch($call){
  300. /*
  301. case 'save_dashboard_setting':
  302. $iclsettings['dashboard'] = $sitepress_settings['dashboard'];
  303. if(isset($data['setting']) && isset($data['value'])){
  304. $iclsettings['dashboard'][$data['setting']] = $data['value'];
  305. $sitepress->save_settings($iclsettings);
  306. }
  307. break;
  308. */
  309. case 'assign_translator':
  310. $_exp = explode('-', $data['translator_id']);
  311. $service = isset($_exp[1]) ? $_exp[1] : 'local';
  312. $translator_id = $_exp[0];
  313. if($this->assign_translation_job($data['job_id'], $translator_id, $service)){
  314. if($service == 'icanlocalize'){
  315. $job = $this->get_translation_job($data['job_id']);
  316. global $ICL_Pro_Translation;
  317. $ICL_Pro_Translation->send_post($job->original_doc_id, array($job->language_code), $translator_id);
  318. foreach($sitepress_settings['icl_lang_status'] as $lp){
  319. if($lp['from'] == $job->source_language_code && $lp['to'] == $job->language_code){
  320. $contract_id = $lp['contract_id'];
  321. $lang_tr_id = $lp['id'];
  322. break;
  323. }
  324. }
  325. $translator_edit_link = $sitepress->create_icl_popup_link(ICL_API_ENDPOINT . '/websites/' . $sitepress_settings['site_id']
  326. . '/website_translation_offers/' . $lang_tr_id . '/website_translation_contracts/'
  327. . $contract_id, array('title' => __('Chat with translator', 'sitepress'), 'unload_cb' => 'icl_thickbox_refresh'))
  328. . esc_html(ICL_Pro_Translation::get_translator_name($translator_id)) . '</a> (ICanLocalize)';
  329. }else{
  330. $translator_edit_link = '<a href="'.$this->get_translator_edit_url($data['translator_id']).'">' .
  331. esc_html($wpdb->get_var($wpdb->prepare("SELECT display_name FROM {$wpdb->users} WHERE ID=%d",$data['translator_id']))) . '</a>';
  332. }
  333. echo json_encode(array('error'=>0, 'message'=>$translator_edit_link, 'status'=>$this->status2text(ICL_TM_WAITING_FOR_TRANSLATOR), 'service'=>$service));
  334. }else{
  335. echo json_encode(array('error'=>1));
  336. }
  337. break;
  338. case 'icl_cf_translation':
  339. if(!empty($data['cf'])){
  340. foreach($data['cf'] as $k=>$v){
  341. $cft[base64_decode($k)] = $v;
  342. }
  343. $this->settings['custom_fields_translation'] = $cft;
  344. $this->save_settings();
  345. }
  346. echo '1|';
  347. break;
  348. case 'icl_doc_translation_method':
  349. $this->settings['doc_translation_method'] = intval($data['t_method']);
  350. $this->save_settings();
  351. echo '1|';
  352. break;
  353. case 'reset_duplication':
  354. $this->reset_duplicate_flag($_POST['post_id']);
  355. break;
  356. case 'set_duplication':
  357. $this->set_duplicate($_POST['post_id']);
  358. break;
  359. case 'make_duplicates':
  360. $mdata['iclpost'] = array($data['post_id']);
  361. $langs = explode(',', $data['langs']);
  362. foreach($langs as $lang){
  363. $mdata['duplicate_to'][$lang] = 1;
  364. }
  365. $this->make_duplicates($mdata);
  366. break;
  367. }
  368. }
  369. function show_messages(){
  370. if(!empty($this->messages)){
  371. foreach($this->messages as $m){
  372. echo '<div class="'.$m['type'].' below-h2"><p>' . $m['text'] . '</p></div>';
  373. }
  374. }
  375. }
  376. /* TRANSLATORS */
  377. /* ******************************************************************************************** */
  378. function add_translator($user_id, $language_pairs){
  379. global $wpdb;
  380. $user = new WP_User($user_id);
  381. $user->add_cap('translate');
  382. $um = get_user_meta($user_id, $wpdb->prefix . 'language_pairs', true);
  383. if(!empty($um)){
  384. foreach($um as $fr=>$to){
  385. if(isset($language_pairs[$fr])){
  386. $language_pairs[$fr] = array_merge($language_pairs[$fr], $to);
  387. }
  388. }
  389. }
  390. update_user_meta($user_id, $wpdb->prefix . 'language_pairs', $language_pairs);
  391. $this->clear_cache();
  392. }
  393. function edit_translator($user_id, $language_pairs){
  394. global $wpdb;
  395. $_user = new WP_User($user_id);
  396. if(empty($language_pairs)){
  397. $this->remove_translator($user_id);
  398. wp_redirect('admin.php?page='.WPML_TM_FOLDER.'/menu/main.php&sm=translators&icl_tm_message='.
  399. urlencode(sprintf(__('%s has been removed as a translator for this site.','sitepress'),$_user->data->display_name)).'&icl_tm_message_type=updated'); exit;
  400. }
  401. else{
  402. if(!$_user->has_cap('translate')) $_user->add_cap('translate');
  403. update_user_meta($user_id, $wpdb->prefix . 'language_pairs', $language_pairs);
  404. }
  405. }
  406. function remove_translator($user_id){
  407. global $wpdb;
  408. $user = new WP_User($user_id);
  409. $user->remove_cap('translate');
  410. delete_user_meta($user_id, $wpdb->prefix . 'language_pairs');
  411. $this->clear_cache();
  412. }
  413. function is_translator($user_id, $args = array()){
  414. // $lang_from
  415. // $lang_to
  416. // $job_id
  417. //$default_args = array();
  418. //extract($default_args);
  419. extract($args, EXTR_OVERWRITE);
  420. global $wpdb;
  421. $user = new WP_User($user_id);
  422. $is_translator = $user->has_cap('translate');
  423. if(isset($lang_from) && isset($lang_to)){
  424. $um = get_user_meta($user_id, $wpdb->prefix . 'language_pairs', true);
  425. $is_translator = $is_translator && isset($um[$lang_from][$lang_to]) && $um[$lang_from][$lang_to];
  426. }
  427. if(isset($job_id)){
  428. $translator_id = $wpdb->get_var($wpdb->prepare("
  429. SELECT j.translator_id
  430. FROM {$wpdb->prefix}icl_translate_job j
  431. JOIN {$wpdb->prefix}icl_translation_status s ON j.rid = s.rid
  432. WHERE job_id = %d AND s.translation_service='local'
  433. ", $job_id));
  434. //$is_translator = $is_translator && ($translator_id == $user_id || ($translator_id === '0'));
  435. $is_translator = $is_translator && (($translator_id == $user_id) || empty($translator_id));
  436. }
  437. return $is_translator;
  438. }
  439. function translator_exists($id, $from, $to, $type = 'local'){
  440. global $sitepress_settings;
  441. $exists = false;
  442. if($type == 'icanlocalize' && !empty($sitepress_settings['icl_lang_status'])){
  443. foreach($sitepress_settings['icl_lang_status'] as $lpair){
  444. if($lpair['from'] == $from && $lpair['to'] == $to){
  445. if(!empty($lpair['translators'])){
  446. foreach($lpair['translators'] as $t){
  447. if($t['id'] == $id){
  448. $exists = true;
  449. break(2);
  450. }
  451. }
  452. }
  453. }
  454. }
  455. }elseif($type == 'local'){
  456. $exists = $this->is_translator($id, array('lang_from'=>$from, 'lang_to'=>$to));
  457. }
  458. return $exists;
  459. }
  460. function set_default_translator($id, $from, $to, $type = 'local'){
  461. global $sitepress, $sitepress_settings;
  462. $iclsettings['default_translators'] = isset($sitepress_settings['default_translators']) ? $sitepress_settings['default_translators'] : array();
  463. $iclsettings['default_translators'][$from][$to] = array('id'=>$id, 'type'=>$type);
  464. $sitepress->save_settings($iclsettings);
  465. }
  466. function get_default_translator($from, $to){
  467. global $sitepress_settings;
  468. if(isset($sitepress_settings['default_translators'][$from][$to])){
  469. $dt = $sitepress_settings['default_translators'][$from][$to];
  470. }else{
  471. $dt = array();
  472. }
  473. return $dt;
  474. }
  475. public function get_blog_not_translators(){
  476. global $wpdb;
  477. $cached_translators = get_option($wpdb->prefix . 'icl_non_translators_cached', array());
  478. if (!empty($cached_translators)) {
  479. return $cached_translators;
  480. }
  481. $sql = "SELECT u.ID, u.user_login, u.display_name, m.meta_value AS caps
  482. FROM {$wpdb->users} u JOIN {$wpdb->usermeta} m ON u.id=m.user_id AND m.meta_key = '{$wpdb->prefix}capabilities' ORDER BY u.display_name";
  483. $res = $wpdb->get_results($sql);
  484. $users = array();
  485. foreach($res as $row){
  486. $caps = @unserialize($row->caps);
  487. if(!isset($caps['translate'])){
  488. $users[] = $row;
  489. }
  490. }
  491. update_option($wpdb->prefix . 'icl_non_translators_cached', $users);
  492. return $users;
  493. }
  494. /**
  495. * Implementation of 'icl_translators_list' hook
  496. *
  497. * @global object $sitepress
  498. * @param array $array
  499. * @return array
  500. */
  501. public function icanlocalize_translators_list() {
  502. global $sitepress_settings, $sitepress;
  503. $lang_status = isset($sitepress_settings['icl_lang_status']) ? $sitepress_settings['icl_lang_status'] : array();
  504. if (0 != key($lang_status)){
  505. $buf[] = $lang_status;
  506. $lang_status = $buf;
  507. }
  508. $translators = array();
  509. foreach($lang_status as $lpair){
  510. foreach((array)$lpair['translators'] as $translator){
  511. $translators[$translator['id']]['name'] = $translator['nickname'];
  512. $translators[$translator['id']]['langs'][$lpair['from']][] = $lpair['to'];
  513. $translators[$translator['id']]['type'] = 'ICanLocalize';
  514. $translators[$translator['id']]['action'] = $sitepress->create_icl_popup_link(ICL_API_ENDPOINT . '/websites/' . $sitepress_settings['site_id']
  515. . '/website_translation_offers/' . $lpair['id'] . '/website_translation_contracts/'
  516. . $translator['contract_id'], array('title' => __('Chat with translator', 'sitepress'), 'unload_cb' => 'icl_thickbox_refresh', 'ar'=>1)) . __('Chat with translator', 'sitepress') . '</a>';
  517. }
  518. }
  519. return $translators;
  520. }
  521. public function get_blog_translators($args = array()){
  522. global $wpdb;
  523. $args_default = array('from'=>false, 'to'=>false);
  524. extract($args_default);
  525. extract($args, EXTR_OVERWRITE);
  526. // $sql = "SELECT u.ID, u.user_login, u.display_name, u.user_email, m.meta_value AS caps
  527. // FROM {$wpdb->users} u JOIN {$wpdb->usermeta} m ON u.id=m.user_id AND m.meta_key LIKE '{$wpdb->prefix}capabilities' ORDER BY u.display_name";
  528. // $res = $wpdb->get_results($sql);
  529. $cached_translators = get_option($wpdb->prefix . 'icl_translators_cached', array());
  530. if (empty($cached_translators)) {
  531. $sql = "SELECT u.ID FROM {$wpdb->users} u JOIN {$wpdb->usermeta} m ON u.id=m.user_id AND m.meta_key = '{$wpdb->prefix}language_pairs' ORDER BY u.display_name";
  532. $res = $wpdb->get_results($sql);
  533. update_option($wpdb->prefix . 'icl_translators_cached', $res);
  534. } else {
  535. $res = $cached_translators;
  536. }
  537. $users = array();
  538. foreach($res as $row){
  539. $user = new WP_User($row->ID);
  540. // $caps = @unserialize($row->caps);
  541. // $row->language_pairs = (array)get_user_meta($row->ID, $wpdb->prefix.'language_pairs', true);
  542. $user->language_pairs = (array)get_user_meta($row->ID, $wpdb->prefix.'language_pairs', true);
  543. // if(!empty($from) && !empty($to) && (!isset($row->language_pairs[$from][$to]) || !$row->language_pairs[$from][$to])){
  544. // continue;
  545. // }
  546. if(!empty($from) && !empty($to) && (!isset($user->language_pairs[$from][$to]) || !$user->language_pairs[$from][$to])){
  547. continue;
  548. }
  549. // if(isset($caps['translate'])){
  550. // $users[] = $user;
  551. // }
  552. if($user->has_cap('translate')){
  553. $users[] = $user;
  554. }
  555. }
  556. return $users;
  557. }
  558. function get_selected_translator(){
  559. global $wpdb;
  560. if($this->selected_translator['ID']){
  561. $user = new WP_User($this->selected_translator['ID']);
  562. $this->selected_translator['display_name'] = $user->data->display_name;
  563. $this->selected_translator['user_login'] = $user->data->user_login;
  564. $this->selected_translator['language_pairs'] = get_user_meta($this->selected_translator['ID'], $wpdb->prefix.'language_pairs', true);
  565. }else{
  566. $this->selected_translator['ID'] = 0;
  567. }
  568. return (object)$this->selected_translator;
  569. }
  570. function get_current_translator(){
  571. return $this->current_translator;
  572. }
  573. public function get_translator_edit_url($translator_id){
  574. $url = '';
  575. if(!empty($translator_id)){
  576. $url = 'admin.php?page='. WPML_TM_FOLDER .'/menu/main.php&amp;sm=translators&icl_tm_action=edit&amp;user_id='. $translator_id;
  577. }
  578. return $url;
  579. }
  580. public function translators_dropdown($args = array()){
  581. global $sitepress_settings;
  582. $args_default = array(
  583. 'from'=>false, 'to'=>false,
  584. 'name' => 'translator_id',
  585. 'selected' => 0,
  586. 'echo' => true,
  587. 'services' => array('local')
  588. );
  589. extract($args_default);
  590. extract($args, EXTR_OVERWRITE);
  591. $translators = array();
  592. if(in_array('icanlocalize', $services)){
  593. if(empty($sitepress_settings['icl_lang_status'])) $sitepress_settings['icl_lang_status'] = array();
  594. foreach((array)$sitepress_settings['icl_lang_status'] as $langpair){
  595. if($from && $from != $langpair['from']) continue;
  596. if($to && $to != $langpair['to']) continue;
  597. if(!empty($langpair['translators'])){
  598. if (1 < count($langpair['translators'])) {
  599. $translators[] = (object) array(
  600. 'ID' => '0-icanlocalize',
  601. 'display_name' => __('First available', 'sitepress'),
  602. 'service' => 'ICanLocalize'
  603. );
  604. }
  605. foreach($langpair['translators'] as $tr){
  606. if(!isset($_icl_translators[$tr['id']])){
  607. $translators[] = $_icl_translators[$tr['id']] = (object) array(
  608. 'ID'=>$tr['id'].'-icanlocalize',
  609. 'display_name'=>$tr['nickname'],
  610. 'service' => 'ICanLocalize'
  611. );
  612. }
  613. }
  614. }
  615. }
  616. }
  617. if(in_array('local', $services)){
  618. $translators[] = (object) array(
  619. 'ID' => 0,
  620. 'display_name' => __('First available', 'sitepress'),
  621. );
  622. $translators = array_merge($translators, $this->get_blog_translators(array('from'=>$from,'to'=>$to)));
  623. }
  624. ?>
  625. <select name="<?php echo $name ?>">
  626. <?php foreach($translators as $t):?>
  627. <option value="<?php echo $t->ID ?>" <?php if($selected==$t->ID):?>selected="selected"<?php endif;?>><?php echo esc_html($t->display_name);
  628. ?> (<?php if(isset($t->service)) echo $t->service; else _e('Local', 'sitepress'); ?>)</option>
  629. <?php endforeach; ?>
  630. </select>
  631. <?php
  632. }
  633. public function get_number_of_docs_sent($service = 'icanlocalize'){
  634. global $wpdb;
  635. $n = $wpdb->get_var($wpdb->prepare("
  636. SELECT COUNT(rid) FROM {$wpdb->prefix}icl_translation_status WHERE translation_service=%s
  637. ", $service));
  638. return $n;
  639. }
  640. public function get_number_of_docs_pending($service = 'icanlocalize'){
  641. global $wpdb;
  642. $n = $wpdb->get_var($wpdb->prepare("
  643. SELECT COUNT(rid) FROM {$wpdb->prefix}icl_translation_status WHERE translation_service=%s AND status < " . ICL_TM_COMPLETE . "
  644. ", $service));
  645. return $n;
  646. }
  647. /* HOOKS */
  648. /* ******************************************************************************************** */
  649. function save_post_actions($post_id, $post, $force_set_status = false){
  650. global $wpdb, $sitepress, $sitepress_settings, $current_user;
  651. // skip revisions
  652. if($post->post_type == 'revision'){
  653. return;
  654. }
  655. // skip auto-drafts
  656. if($post->post_status == 'auto-draft'){
  657. return;
  658. }
  659. // skip autosave
  660. if(isset($_POST['autosave'])){
  661. return;
  662. }
  663. // is this the original document?
  664. if(!empty($_POST['icl_trid'])){
  665. $is_original = $wpdb->get_var($wpdb->prepare("SELECT source_language_code IS NULL FROM {$wpdb->prefix}icl_translations WHERE element_id=%d AND trid=%d", $post_id, $_POST['icl_trid']));
  666. }
  667. // when a manual translation is added/edited make sure to update translation tables
  668. if(!empty($_POST['icl_trid']) && !$is_original){
  669. $trid = $_POST['icl_trid'];
  670. $lang = $_POST['icl_post_language'];
  671. $res = $wpdb->get_row($wpdb->prepare("
  672. SELECT element_id, language_code FROM {$wpdb->prefix}icl_translations WHERE trid=%d AND source_language_code IS NULL
  673. ", $trid));
  674. $original_post_id = $res->element_id;
  675. $from_lang = $res->language_code;
  676. $original_post = get_post($original_post_id);
  677. $translation_id = $wpdb->get_var($wpdb->prepare("
  678. SELECT translation_id FROM {$wpdb->prefix}icl_translations WHERE trid=%d AND language_code='%s'
  679. ", $trid, $lang));
  680. $md5 = $this->post_md5($original_post);
  681. get_currentuserinfo();
  682. $user_id = $current_user->ID;
  683. if(!$this->is_translator($user_id, array('lang_from'=>$from_lang, 'lang_to'=>$lang))){
  684. $this->add_translator($user_id, array($from_lang=>array($lang=>1)));
  685. }
  686. if($translation_id){
  687. $translation_package = $this->create_translation_package($original_post_id);
  688. list($rid, $update) = $this->update_translation_status(array(
  689. 'translation_id' => $translation_id,
  690. 'status' => isset($force_set_status) && $force_set_status > 0 ? $force_set_status : ICL_TM_COMPLETE,
  691. 'translator_id' => $user_id,
  692. 'needs_update' => 0,
  693. 'md5' => $md5,
  694. 'translation_service' => 'local',
  695. 'translation_package' => serialize($translation_package)
  696. ));
  697. if(!$update){
  698. $job_id = $this->add_translation_job($rid, $user_id , $translation_package);
  699. }else{
  700. $job_id = $wpdb->get_var($wpdb->prepare("SELECT MAX(job_id) FROM {$wpdb->prefix}icl_translate_job WHERE rid=%d GROUP BY rid", $rid));
  701. }
  702. // saving the translation
  703. $this->save_job_fields_from_post($job_id, $post);
  704. /*
  705. $data['complete'] = 1;
  706. $data['job_id'] = $job_id;
  707. $job = $this->get_translation_job($job_id,1);
  708. foreach($job->elements as $element){
  709. $field_data = '';
  710. switch($element->field_type){
  711. case 'title':
  712. $field_data = $this->encode_field_data($post->post_title, $element->field_format);
  713. break;
  714. case 'body':
  715. $field_data = $this->encode_field_data($post->post_content, $element->field_format);
  716. break;
  717. case 'excerpt':
  718. $field_data = $this->encode_field_data($post->post_excerpt, $element->field_format);
  719. break;
  720. default:
  721. if(false !== strpos($element->field_type, 'field-') && !empty($this->settings['custom_fields_translation'])){
  722. $cf_name = preg_replace('#^field-#', '', $element->field_type);
  723. if(isset($this->settings['custom_fields_translation'][$cf_name])){
  724. if($this->settings['custom_fields_translation'][$cf_name] == 1){ //copy
  725. $field_data = get_post_meta($original_post->ID, $cf_name, 1);
  726. $field_data = $this->encode_field_data($field_data, $element->field_format);
  727. }elseif($this->settings['custom_fields_translation'][$cf_name] == 2){ // translate
  728. $field_data = get_post_meta($post->ID, $cf_name, 1);
  729. $field_data = $this->encode_field_data($field_data, $element->field_format);
  730. }
  731. }
  732. }else{
  733. // taxonomies
  734. // TBD
  735. }
  736. }
  737. $wpdb->update($wpdb->prefix.'icl_translate',
  738. array('field_data_translated'=>$field_data, 'field_finished'=>1),
  739. array('tid'=>$element->tid)
  740. );
  741. }
  742. $wpdb->update($wpdb->prefix . 'icl_translate_job', array('translated'=>1), array('job_id'=>$job_id));
  743. */
  744. }
  745. }
  746. // if this is an original post - compute md5 hash and mark for update if neded
  747. if(!empty($_POST['icl_trid']) && empty($_POST['icl_minor_edit'])){
  748. $needs_update = false;
  749. $is_original = false;
  750. $translations = $sitepress->get_element_translations($_POST['icl_trid'], 'post_' . $post->post_type);
  751. foreach($translations as $lang=>$translation){
  752. if($translation->original == 1 && $translation->element_id == $post_id){
  753. $is_original = true;
  754. break;
  755. }
  756. }
  757. if($is_original){
  758. $md5 = $this->post_md5($post_id);
  759. foreach($translations as $lang=>$translation){
  760. if(!$translation->original){
  761. $emd5 = $wpdb->get_var($wpdb->prepare("SELECT md5 FROM {$wpdb->prefix}icl_translation_status WHERE translation_id = %d", $translation->translation_id));
  762. if($md5 != $emd5){
  763. $wpdb->update($wpdb->prefix.'icl_translation_status', array('needs_update'=>1, 'md5'=>$md5), array('translation_id'=>$translation->translation_id));
  764. }
  765. }
  766. }
  767. }
  768. }
  769. // sync copies/duplicates
  770. $duplicates = $this->get_duplicates($post_id);
  771. foreach($duplicates as $lang => $_pid){
  772. $this->make_duplicate($post_id, $lang);
  773. }
  774. // review?
  775. /*
  776. if($_POST['icl_trid']){
  777. //
  778. // get original document
  779. $translations = $sitepress->get_element_translations($_POST['icl_trid'], 'post_' . $post->post_type);
  780. foreach($translations as $t){
  781. if($t->original){
  782. $origin = $t->language_code;
  783. }
  784. }
  785. // remove ?
  786. $rid = $wpdb->get_var($wpdb->prepare("SELECT rid FROM {$wpdb->prefix}icl_content_status WHERE nid = %d"), $post_id);
  787. if(!$rid){
  788. $wpdb->insert($wpdb->prefix.'icl_content_status', array('nid' => $post_id, 'md5'=>$this->post_md5($post), 'timestamp'=>date('Y-m-d H:i:s')));
  789. $rid = $wpdb->insert_id;
  790. }else{
  791. $wpdb->update($wpdb->prefix.'icl_content_status', array('md5'=>$this->post_md5($post)), array('rid'=>$rid));
  792. }
  793. // add update icl_core_status entry
  794. $id = $wpdb->get_var($wpdb->prepare("SELECT rid FROM {$wpdb->prefix}icl_core_status WHERE rid = %d AND target= = %s"), $rid, $_POST['icl_post_language']);
  795. if(!$id){
  796. $wpdb->insert($wpdb->prefix.'icl_core_status', array('rid' => $rid, 'origin' => $origin, 'target' => $_POST['icl_post_language'], 'status' => 1 )); //!!!!!!!
  797. }else{
  798. $wpdb->update($wpdb->prefix.'icl_content_status', array('md5'=>$this->post_md5($post)), array('rid'=>$rid));
  799. }
  800. }
  801. */
  802. }
  803. function delete_post_actions($post_id){
  804. global $wpdb;
  805. $post_type = $wpdb->get_var("SELECT post_type FROM {$wpdb->posts} WHERE ID={$post_id}");
  806. if(!empty($post_type)){
  807. $translation_id = $wpdb->get_var($wpdb->prepare("SELECT translation_id FROM {$wpdb->prefix}icl_translations WHERE element_id=%d AND element_type=%s", $post_id, 'post_' . $post_type));
  808. if($translation_id){
  809. $rid = $wpdb->get_var($wpdb->prepare("SELECT rid FROM {$wpdb->prefix}icl_translation_status WHERE translation_id=%d", $translation_id));
  810. $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->prefix}icl_translation_status WHERE translation_id=%d", $translation_id));
  811. if($rid){
  812. $jobs = $wpdb->get_col($wpdb->prepare("SELECT job_id FROM {$wpdb->prefix}icl_translate_job WHERE rid=%d", $rid));
  813. $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->prefix}icl_translate_job WHERE rid=%d", $rid));
  814. if(!empty($jobs)){
  815. $wpdb->query("DELETE FROM {$wpdb->prefix}icl_translate WHERE job_id IN (".join(',', $jobs).")");
  816. }
  817. }
  818. }
  819. }
  820. }
  821. /* TRANSLATIONS */
  822. /* ******************************************************************************************** */
  823. /**
  824. * calculate post md5
  825. *
  826. * @param object|int $post
  827. * @return string
  828. *
  829. * @todo full support for custom posts and custom taxonomies
  830. */
  831. function post_md5($post){
  832. if (isset($post->external_type) && $post->external_type) {
  833. $md5str = '';
  834. foreach ($post->string_data as $key => $value) {
  835. $md5str .= $key . $value;
  836. }
  837. } else {
  838. $post_tags = $post_categories = $custom_fields_values = array();
  839. if(is_numeric($post)){
  840. $post = get_post($post);
  841. }
  842. $post_type = $post->post_type;
  843. if($post_type=='post'){
  844. foreach(wp_get_object_terms($post->ID, 'post_tag') as $tag){
  845. $post_tags[] = $tag->name;
  846. }
  847. if(is_array($post_tags)){
  848. sort($post_tags, SORT_STRING);
  849. }
  850. foreach(wp_get_object_terms($post->ID, 'category') as $cat){
  851. $post_categories[] = $cat->name;
  852. }
  853. if(is_array($post_categories)){
  854. sort($post_categories, SORT_STRING);
  855. }
  856. global $wpdb, $sitepress_settings;
  857. // get custom taxonomies
  858. $taxonomies = $wpdb->get_col("
  859. SELECT DISTINCT tx.taxonomy
  860. FROM {$wpdb->term_taxonomy} tx JOIN {$wpdb->term_relationships} tr ON tx.term_taxonomy_id = tr.term_taxonomy_id
  861. WHERE tr.object_id = {$post->ID}
  862. ");
  863. sort($taxonomies, SORT_STRING);
  864. foreach($taxonomies as $t){
  865. if(@intval($sitepress_settings['taxonomies_sync_option'][$t]) == 1){
  866. $taxs = array();
  867. foreach(wp_get_object_terms($post->ID, $t) as $trm){
  868. $taxs[] = $trm->name;
  869. }
  870. if($taxs){
  871. sort($taxs,SORT_STRING);
  872. $all_taxs[] = '['.$t.']:'.join(',',$taxs);
  873. }
  874. }
  875. }
  876. }
  877. $custom_fields_values = array();
  878. if(is_array($this->settings['custom_fields_translation'])){
  879. foreach($this->settings['custom_fields_translation'] as $cf => $op){
  880. if ($op == 2) {
  881. $custom_fields_values[] = get_post_meta($post->ID, $cf, true);
  882. }
  883. }
  884. }
  885. $md5str =
  886. $post->post_title . ';' .
  887. $post->post_content . ';' .
  888. join(',',$post_tags).';' .
  889. join(',',$post_categories) . ';' .
  890. join(',', $custom_fields_values);
  891. if(!empty($all_taxs)){
  892. $md5str .= ';' . join(';', $all_taxs);
  893. }
  894. }
  895. $md5 = md5($md5str);
  896. return $md5;
  897. }
  898. /**
  899. * get documents
  900. *
  901. * @param array $args
  902. */
  903. function get_documents($args){
  904. extract($args);
  905. global $wpdb, $wp_query, $sitepress;
  906. $t_el_types = array_keys($sitepress->get_translatable_documents());
  907. // SELECT
  908. $select = " p.ID AS post_id, p.post_title, p.post_content, p.post_type, p.post_status, p.post_date, t.trid, t.source_language_code <> '' AS is_translation";
  909. if($to_lang){
  910. $select .= ", iclts.status, iclts.needs_update";
  911. }else{
  912. foreach($sitepress->get_active_languages() as $lang){
  913. if($lang['code'] == $from_lang) continue;
  914. $tbl_alias_suffix = str_replace('-','_',$lang['code']);
  915. $select .= ", iclts_{$tbl_alias_suffix}.status AS status_{$tbl_alias_suffix}, iclts_{$tbl_alias_suffix}.needs_update AS needs_update_{$tbl_alias_suffix}";
  916. }
  917. }
  918. // FROM
  919. $from = " {$wpdb->posts} p";
  920. // JOIN
  921. $join = "";
  922. $join .= " LEFT JOIN {$wpdb->prefix}icl_translations t ON t.element_id=p.ID\n";
  923. if($to_lang){
  924. $tbl_alias_suffix = str_replace('-','_',$to_lang);
  925. $join .= " LEFT JOIN {$wpdb->prefix}icl_translations iclt_{$tbl_alias_suffix}
  926. ON iclt_{$tbl_alias_suffix}.trid=t.trid AND iclt_{$tbl_alias_suffix}.language_code='{$to_lang}'\n";
  927. $join .= " LEFT JOIN {$wpdb->prefix}icl_translation_status iclts ON iclts.translation_id=iclt_{$tbl_alias_suffix}.translation_id\n";
  928. }else{
  929. foreach($sitepress->get_active_languages() as $lang){
  930. if($lang['code'] == $from_lang) continue;
  931. $tbl_alias_suffix = str_replace('-','_',$lang['code']);
  932. $join .= " LEFT JOIN {$wpdb->prefix}icl_translations iclt_{$tbl_alias_suffix}
  933. ON iclt_{$tbl_alias_suffix}.trid=t.trid AND iclt_{$tbl_alias_suffix}.language_code='{$lang['code']}'\n";
  934. $join .= " LEFT JOIN {$wpdb->prefix}icl_translation_status iclts_{$tbl_alias_suffix}
  935. ON iclts_{$tbl_alias_suffix}.translation_id=iclt_{$tbl_alias_suffix}.translation_id\n";
  936. }
  937. }
  938. // WHERE
  939. $where = " t.language_code = '{$from_lang}' AND p.post_status NOT IN ('trash', 'auto-draft') \n";
  940. if(!empty($type)){
  941. $where .= " AND p.post_type = '{$type}'";
  942. $where .= " AND t.element_type = 'post_{$type}'\n";
  943. }else{
  944. $where .= " AND p.post_type IN ('".join("','",$t_el_types)."')\n";
  945. foreach($t_el_types as $k=>$v){
  946. $t_el_types[$k] = 'post_' . $v;
  947. }
  948. $where .= " AND t.element_type IN ('".join("','",$t_el_types)."')\n";
  949. }
  950. if(!empty($title)){
  951. $where .= " AND p.post_title LIKE '%".$wpdb->escape($title)."%'\n";
  952. }
  953. if(!empty($status)){
  954. $where .= " AND p.post_status = '{$status}'\n";
  955. }
  956. if(isset($from_date)){
  957. $where .= " AND p.post_date > '{$from_date}'\n";
  958. }
  959. if(isset($to_date)){
  960. $where .= " AND p.post_date > '{$to_date}'\n";
  961. }
  962. if($tstatus){
  963. if($to_lang){
  964. if($tstatus == 'not'){
  965. $where .= " AND (iclts.status IS NULL OR iclts.status = ".ICL_TM_WAITING_FOR_TRANSLATOR." OR iclts.needs_update = 1)\n";
  966. }elseif($tstatus == 'in_progress'){
  967. $where .= " AND iclts.status = ".ICL_TM_IN_PROGRESS." AND iclts.needs_update = 0\n";
  968. }elseif($tstatus == 'complete'){
  969. $where .= " AND iclts.status = ".ICL_TM_COMPLETE." AND iclts.needs_update = 0\n";
  970. }
  971. }else{
  972. if($tstatus == 'not'){
  973. $where .= " AND (";
  974. $wheres = array();
  975. foreach($sitepress->get_active_languages() as $lang){
  976. if($lang['code'] == $from_lang) continue;
  977. $tbl_alias_suffix = str_replace('-','_',$lang['code']);
  978. $wheres[] = "iclts_{$tbl_alias_suffix}.status IS NULL OR iclts_{$tbl_alias_suffix}.status = ".ICL_TM_WAITING_FOR_TRANSLATOR." OR iclts_{$tbl_alias_suffix}.needs_update = 1\n";
  979. }
  980. $where .= join(' OR ', $wheres) . ")";
  981. }elseif($tstatus == 'in_progress'){
  982. $where .= " AND (";
  983. $wheres = array();
  984. foreach($sitepress->get_active_languages() as $lang){
  985. if($lang['code'] == $from_lang) continue;
  986. $tbl_alias_suffix = str_replace('-','_',$lang['code']);
  987. $wheres[] = "iclts_{$tbl_alias_suffix}.status = ".ICL_TM_IN_PROGRESS."\n";
  988. }
  989. $where .= join(' OR ', $wheres) . ")";
  990. }elseif($tstatus == 'complete'){
  991. foreach($sitepress->get_active_languages() as $lang){
  992. if($lang['code'] == $from_lang) continue;
  993. $tbl_alias_suffix = str_replace('-','_',$lang['code']);
  994. $where .= " AND iclts_{$tbl_alias_suffix}.status = ".ICL_TM_COMPLETE." AND iclts_{$tbl_alias_suffix}.needs_update = 0\n";
  995. }
  996. }
  997. }
  998. }
  999. if(isset($parent_type) && $parent_type == 'page' && $parent_id > 0){
  1000. if($parent_all){
  1001. $children = icl_get_post_children_recursive($parent_id);
  1002. $where .= ' AND p.ID IN (' . join(',', $children) . ')';
  1003. }else{
  1004. $where .= ' AND p.post_parent=' . intval($parent_id);
  1005. }
  1006. }
  1007. if(isset($parent_type) && $parent_type == 'category' && $parent_id > 0){
  1008. if($parent_all){
  1009. $children = icl_get_tax_children_recursive($parent_id);
  1010. $children[] = $parent_id;
  1011. $join .= " JOIN {$wpdb->term_relationships} tr ON p.ID = tr.object_id
  1012. JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id = tt.term_taxonomy_id AND taxonomy = 'category'
  1013. JOIN {$wpdb->terms} tm ON tt.term_id = tm.term_id AND tm.term_id IN(" . join(',', $children) . ")";
  1014. }else{
  1015. $join .= " JOIN {$wpdb->term_relationships} tr ON p.ID = tr.object_id
  1016. JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id = tt.term_taxonomy_id AND taxonomy = 'category'
  1017. JOIN {$wpdb->terms} tm ON tt.term_id = tm.term_id AND tm.term_id = " . intval($parent_id);
  1018. }
  1019. }
  1020. // ORDER
  1021. if($sort_by){
  1022. $order = " $sort_by ";
  1023. }else{
  1024. $order = " p.post_date DESC";
  1025. }
  1026. if($sort_order){
  1027. $order .= $sort_order;
  1028. }else{
  1029. $order .= 'DESC';
  1030. }
  1031. // LIMIT
  1032. if(!isset($_GET['paged'])) $_GET['paged'] = 1;
  1033. $offset = ($_GET['paged']-1)*$limit_no;
  1034. $limit = " " . $offset . ',' . $limit_no;
  1035. $sql = "
  1036. SELECT SQL_CALC_FOUND_ROWS {$select}
  1037. FROM {$from}
  1038. {$join}
  1039. WHERE {$where}
  1040. ORDER BY {$order}
  1041. LIMIT {$limit}
  1042. ";
  1043. $results = $wpdb->get_results($sql);
  1044. $count = $wpdb->get_var("SELECT FOUND_ROWS()");
  1045. $wp_query->found_posts = $count;
  1046. $wp_query->query_vars['posts_per_page'] = $limit_no;
  1047. $wp_query->max_num_pages = ceil($wp_query->found_posts/$limit_no);
  1048. // post process
  1049. foreach($results as $k=>$v){
  1050. if($v->is_translation){
  1051. $source_language = $wpdb->get_var($wpdb->prepare("SELECT language_code FROM {$wpdb->prefix}icl_translations WHERE trid=%d AND source_language_code IS NULL", $v->trid));
  1052. $_tmp = 'status_' . $source_language;
  1053. $v->$_tmp = ICL_TM_COMPLETE;
  1054. }
  1055. }
  1056. return $results;
  1057. }
  1058. function get_element_translation($element_id, $language, $element_type='post_post'){
  1059. global $wpdb, $sitepress;
  1060. $trid = $sitepress->get_element_trid($element_id, $element_type);
  1061. $translation = array();
  1062. if($trid){
  1063. $translation = $wpdb->get_row($wpdb->prepare("
  1064. SELECT *
  1065. FROM {$wpdb->prefix}icl_translations tr
  1066. JOIN {$wpdb->prefix}icl_translation_status ts ON tr.translation_id = ts.translation_id
  1067. WHERE tr.trid=%s AND tr.language_code='%s'
  1068. ", $trid, $language));
  1069. }
  1070. return $translation;
  1071. }
  1072. function get_element_translations($element_id, $element_type='post_post', $service = false){
  1073. global $wpdb, $sitepress;
  1074. $trid = $sitepress->get_element_trid($element_id, $element_type);
  1075. $translations = array();
  1076. if($trid){
  1077. $service = $service ? " AND translation_service = '$service'" : '';
  1078. $translations = $wpdb->get_results($wpdb->prepare("
  1079. SELECT *
  1080. FROM {$wpdb->prefix}icl_translations tr
  1081. JOIN {$wpdb->prefix}icl_translation_status ts ON tr.translation_id = ts.translation_id
  1082. WHERE tr.trid=%s {$service}
  1083. ", $trid));
  1084. foreach($translations as $k=>$v){
  1085. $translations[$v->language_code] = $v;
  1086. unset($translations[$k]);
  1087. }
  1088. }
  1089. return $translations;
  1090. }
  1091. /**
  1092. * returns icon file name according to status code
  1093. *
  1094. * @param int $status
  1095. */
  1096. public function status2img_filename($status, $needs_update = 0){
  1097. if($needs_update){
  1098. $img_file = 'needs-update.png';
  1099. }else{
  1100. switch($status){
  1101. case ICL_TM_NOT_TRANSLATED: $img_file = 'not-translated.png'; break;
  1102. case ICL_TM_WAITING_FOR_TRANSLATOR: $img_file = 'in-progress.png'; break;
  1103. case ICL_TM_IN_PROGRESS: $img_file = 'in-progress.png'; break;
  1104. case ICL_TM_NEEDS_UPDATE: $img_file = 'needs-update.png'; break;
  1105. case ICL_TM_DUPLICATE: $img_file = 'copy.png'; break;
  1106. case ICL_TM_COMPLETE: $img_file = 'complete.png'; break;
  1107. default: $img_file = '';
  1108. }
  1109. }
  1110. return $img_file;
  1111. }
  1112. public function status2text($status){
  1113. switch($status){
  1114. case ICL_TM_NOT_TRANSLATED: $text = __('Not translated', 'sitepress'); break;
  1115. case ICL_TM_WAITING_FOR_TRANSLATOR: $text = __('Waiting for translator', 'sitepress'); break;
  1116. case ICL_TM_IN_PROGRESS: $text = __('In progress', 'sitepress'); break;
  1117. case ICL_TM_NEEDS_UPDATE: $text = __('Needs update', 'sitepress'); break;
  1118. case ICL_TM_DUPLICATE: $text = __('Duplicate', 'sitepress'); break;
  1119. case ICL_TM_COMPLETE: $text = __('Complete', 'sitepress'); break;
  1120. default: $text = '';
  1121. }
  1122. return $text;
  1123. }
  1124. public function estimate_word_count($data, $lang_code){
  1125. global $asian_languages;
  1126. $words = 0;
  1127. if(isset($data->post_title)){
  1128. if(in_array($lang_code, $asian_languages)){
  1129. $words += strlen(strip_tags($data->post_title)) / 6;
  1130. } else {
  1131. $words += count(explode(' ',$data->post_title));
  1132. }
  1133. }
  1134. if(isset($data->post_content)){
  1135. if(in_array($lang_code, $asian_languages)){
  1136. $words += strlen(strip_tags($data->post_content)) / 6;
  1137. } else {
  1138. $words += count(explode(' ',strip_tags($data->post_content)));
  1139. }
  1140. }
  1141. return (int)$words;
  1142. }
  1143. public function estimate_custom_field_word_count($post_id, $lang_code) {
  1144. global $asian_languages;
  1145. $words = 0;
  1146. if(!empty($this->settings['custom_fields_translation']) && is_array($this->settings['custom_fields_translation'])){
  1147. $custom_fields = array();
  1148. foreach($this->settings['custom_fields_translation'] as $cf => $op){
  1149. if ($op == 2) {
  1150. $custom_fields[] = $cf;
  1151. }
  1152. }
  1153. foreach($custom_fields as $cf ){
  1154. $custom_fields_value = get_post_meta($post_id, $cf, true);
  1155. if ($custom_fields_value != "" && is_scalar($custom_fields_value)) { // only support scalar values fo rnow
  1156. if(in_array($lang_code, $asian_languages)){
  1157. $words += strlen(strip_tags($custom_fields_value)) / 6;
  1158. } else {
  1159. $words += count(explode(' ',strip_tags($custom_fields_value)));
  1160. }
  1161. }
  1162. }
  1163. }
  1164. return (int)$words;
  1165. }
  1166. public function decode_field_data($data, $format){
  1167. if($format == 'base64'){
  1168. $data = base64_decode($data);
  1169. }elseif($format == 'csv_base64'){
  1170. $exp = explode(',', $data);
  1171. foreach($exp as $k=>$e){
  1172. $exp[$k] = base64_decode(trim($e,'"'));
  1173. }
  1174. $data = $exp;
  1175. }
  1176. return $data;
  1177. }
  1178. public function encode_field_data($data, $format){
  1179. if($format == 'base64'){
  1180. $data = base64_encode($data);
  1181. }elseif($format == 'csv_base64'){
  1182. $exp = $data;
  1183. foreach($exp as $k=>$e){
  1184. $exp[$k] = '"' . base64_encode(trim($e)) . '"';
  1185. }
  1186. $data = join(',', $exp);
  1187. }
  1188. return $data;
  1189. }
  1190. /**
  1191. * create translation package
  1192. *
  1193. * @param object|int $post
  1194. */
  1195. function create_translation_package($post){
  1196. global $sitepress, $sitepress_settings;
  1197. $package = array();
  1198. if(is_numeric($post)){
  1199. $post = get_post($post);
  1200. }
  1201. if (isset($post->external_type) && $post->external_type) {
  1202. foreach ($post->string_data as $key => $value) {
  1203. $package['contents'][$key] = array(
  1204. 'translate' => 1,
  1205. 'data' => $this->encode_field_data($value, 'base64'),
  1206. 'format' => 'base64'
  1207. );
  1208. }
  1209. $package['contents']['original_id'] = array(
  1210. 'translate' => 0,
  1211. 'data' => $post->post_id,
  1212. );
  1213. } else {
  1214. if($post->post_type=='page'){
  1215. $package['url'] = htmlentities(get_option('home') . '?page_id=' . ($post->ID));
  1216. }else{
  1217. $package['url'] = htmlentities(get_option('home') . '?p=' . ($post->ID));
  1218. }
  1219. $package['contents']['title'] = array(
  1220. 'translate' => 1,
  1221. 'data' => $this->encode_field_data($post->post_title, 'base64'),
  1222. 'format' => 'base64'
  1223. );
  1224. if($sitepress_settings['translated_document_page_url'] == 'translate'){
  1225. $package['contents']['URL'] = array(
  1226. 'translate' => 1,
  1227. 'data' => $this->encode_field_data($post->post_name, 'base64'),
  1228. 'format' => 'base64'
  1229. );
  1230. }
  1231. $package['contents']['body'] = array(
  1232. 'translate' => 1,
  1233. 'data' => $this->encode_field_data($post->post_content, 'base64'),
  1234. 'format' => 'base64'
  1235. );
  1236. if(!empty($post->post_excerpt)){
  1237. $package['contents']['excerpt'] = array(
  1238. 'translate' => 1,
  1239. 'data' => base64_encode($post->post_excerpt),
  1240. 'format' => 'base64'
  1241. );
  1242. }
  1243. $package['contents']['original_id'] = array(
  1244. 'translate' => 0,
  1245. 'data' => $post->ID
  1246. );
  1247. if(!empty($this->settings['custom_fields_translation']))
  1248. foreach($this->settings['custom_fields_translation'] as $cf => $op){
  1249. if ($op == 2) { // translate
  1250. /* */
  1251. $custom_fields_value = get_post_meta($post->ID, $cf, true);
  1252. if ($custom_fields_value != '' && is_scalar($custom_fields_value)) {
  1253. $package['contents']['field-'.$cf] = array(
  1254. 'translate' => 1,
  1255. 'data' => $this->encode_field_data($custom_fields_value, 'base64'),
  1256. 'format' => 'base64'
  1257. );
  1258. $package['contents']['field-'.$cf.'-name'] = array(
  1259. 'translate' => 0,
  1260. 'data' => $cf
  1261. );
  1262. $package['contents']['field-'.$cf.'-type'] = array(
  1263. 'translate' => 0,
  1264. 'data' => 'custom_field'
  1265. );
  1266. }
  1267. /* */
  1268. /*
  1269. $post_custom = get_post_custom($post->ID);
  1270. if(isset($post_custom[$cf])){
  1271. $package['contents']['field-'.$cf] = array(
  1272. 'translate' => 1,
  1273. 'data' => $this->encode_field_data(serialize($post_custom[$cf]), 'base64'),
  1274. 'format' => 'base64'
  1275. );
  1276. $package['contents']['field-'.$cf.'-name'] = array(
  1277. 'translate' => 0,
  1278. 'data' => $cf
  1279. );
  1280. $package['contents']['field-'.$cf.'-type'] = array(
  1281. 'translate' => 0,
  1282. 'data' => 'custom_field'
  1283. );
  1284. }
  1285. */
  1286. }
  1287. }
  1288. foreach((array)$sitepress->get_translatable_taxonomies(true, $post->post_type) as $taxonomy){
  1289. $terms = get_the_terms( $post->ID , $taxonomy );
  1290. if(!empty($terms)){
  1291. $_taxs = $_tax_ids = array();
  1292. foreach($terms as $term){
  1293. $_taxs[] = $term->name;
  1294. $_tax_ids[] = $term->term_taxonomy_id;
  1295. }
  1296. if($taxonomy == 'post_tag'){
  1297. $tax_package_key = 'tags';
  1298. $tax_id_package_key = 'tag_ids';
  1299. }
  1300. elseif($taxonomy == 'category'){
  1301. $tax_package_key = 'categories';
  1302. $tax_id_package_key = 'category_ids';
  1303. }
  1304. else{
  1305. $tax_package_key = $taxonomy;
  1306. $tax_id_package_key = $taxonomy . '_ids';
  1307. }
  1308. $package['contents'][$tax_package_key] = array(
  1309. 'translate' => 1,
  1310. 'data' => $this->encode_field_data($_taxs,'csv_base64'),
  1311. 'format'=>'csv_base64'
  1312. );
  1313. $package['contents'][$tax_id_package_key] = array(
  1314. 'translate' => 0,
  1315. 'data' => join(',', $_tax_ids)
  1316. );
  1317. }
  1318. }
  1319. }
  1320. return $package;
  1321. }
  1322. /**
  1323. * add/update icl_translation_status record
  1324. *
  1325. * @param array $data
  1326. */
  1327. function update_translation_status($data){
  1328. global $wpdb;
  1329. if(!isset($data['translation_id'])) return;
  1330. if($rid = $wpdb->get_var($wpdb->prepare("SELECT rid FROM {$wpdb->prefix}icl_translation_status WHERE translation_id=%d", $data['translation_id']))){
  1331. $wpdb->update($wpdb->prefix.'icl_translation_status', $data, array('rid'=>$rid));
  1332. $update = true;
  1333. }else{
  1334. $wpdb->insert($wpdb->prefix.'icl_translation_status',$data);
  1335. $rid = $wpdb->insert_id;
  1336. $update = false;
  1337. }
  1338. return array($rid, $update);
  1339. }
  1340. function _get_post($post_id) {
  1341. if (is_string($post_id) && strcmp(substr($post_id, 0, strlen('external_')), 'external_')===0) {
  1342. $item = null;
  1343. return apply_filters('WPML_get_translatable_item', $item, $post_id);
  1344. } else {
  1345. return get_post($post_id);
  1346. }
  1347. }
  1348. /* TRANSLATION JOBS */
  1349. /* ******************************************************************************************** */
  1350. function send_jobs($data){
  1351. global $wpdb, $sitepress;
  1352. if(!isset($data['tr_action']) && isset($data['translate_to'])){ //adapt new format
  1353. $data['tr_action'] = $data['translate_to'];
  1354. unset($data['translate_to']);
  1355. }
  1356. // translate_from
  1357. // tr_action (translate_to)
  1358. // translator
  1359. // post
  1360. // service
  1361. // defaults
  1362. $data_default = array(
  1363. 'translate_from' => $sitepress->get_default_language()
  1364. );
  1365. extract($data_default);
  1366. extract($data, EXTR_OVERWRITE);
  1367. // no language selected ?
  1368. if(!isset($tr_action) || empty($tr_action)){
  1369. $this->messages[] = array(
  1370. 'type'=>'error',
  1371. 'text' => __('Please select at least one language to translate into.', 'sitepress')
  1372. );
  1373. $this->dashboard_select = $data; // prepopulate dashboard
  1374. return;
  1375. }
  1376. // no post selected ?
  1377. if(!isset($iclpost) || empty($iclpost)){
  1378. $this->messages[] = array(
  1379. 'type'=>'error',
  1380. 'text' => __('Please select at least one document to translate.', 'sitepress')
  1381. );
  1382. $this->dashboard_select = $data; // prepopulate dashboard
  1383. return;
  1384. }
  1385. $selected_posts = $iclpost;
  1386. $selected_translators = isset($translator) ? $translator : array();
  1387. $selected_languages = $tr_action;
  1388. $job_ids = array();
  1389. foreach($selected_posts as $post_id){
  1390. $post = $this->_get_post($post_id);
  1391. $post_trid = $sitepress->get_element_trid($post->ID, 'post_' . $post->post_type);
  1392. $post_translations = $sitepress->get_element_translations($post_trid, 'post_' . $post->post_type);
  1393. $md5 = $this->post_md5($post);
  1394. $translation_package = $this->create_translation_package($post);
  1395. foreach($selected_languages as $lang => $action){
  1396. // making this a duplicate?
  1397. if($action == 2){
  1398. // dont send documents that are in progress
  1399. $current_translation_status = $this->get_element_translation($post_id, $lang, 'post_' . $post->post_type);
  1400. if($current_translation_status->status == ICL_TM_IN_PROGRESS) continue;
  1401. $job_ids[] = $this->make_duplicate($post_id, $lang);
  1402. }elseif($action == 1){
  1403. if(empty($post_translations[$lang])){
  1404. $translation_id = $sitepress->set_element_language_details(null , 'post_' . $post->post_type, $post_trid, $lang, $translate_from);
  1405. }else{
  1406. $translation_id = $post_translations[$lang]->translation_id;
  1407. }
  1408. $current_translation_status = $this->get_element_translation($post_id, $lang, 'post_' . $post->post_type);
  1409. // don't send documents that are in progress
  1410. // don't send documents that are already translated and don't need update
  1411. if(!empty($current_translation_status)){
  1412. if($current_translation_status->status == ICL_TM_IN_PROGRESS) continue;
  1413. if($current_translation_status->status == ICL_TM_COMPLETE && !$current_translation_status->needs_update) continue;
  1414. }
  1415. $_status = ICL_TM_WAITING_FOR_TRANSLATOR;
  1416. $_exp = isset($selected_translators[$lang]) ? explode('-', $selected_translators[$lang]) : false;
  1417. if(!isset($service)){
  1418. $translation_service = isset($_exp[1]) ? $_exp[1] : 'local';
  1419. }else{
  1420. $translation_service = $service;
  1421. }
  1422. $translator_id = $_exp[0];
  1423. // set as default translator
  1424. if($translator_id > 0){
  1425. $this->set_default_translator($translator_id, $translate_from, $lang, $translation_service);
  1426. }
  1427. // add translation_status record
  1428. $data = array(
  1429. 'translation_id' => $translation_id,
  1430. 'status' => $_status,
  1431. 'translator_id' => $translator_id,
  1432. 'needs_update' => 0,
  1433. 'md5' => $md5,
  1434. 'translation_service' => $translation_service,
  1435. 'translation_package' => serialize($translation_package)
  1436. );
  1437. $_prevstate = $wpdb->get_row($wpdb->prepare("
  1438. SELECT status, translator_id, needs_update, md5, translation_service, translation_package, timestamp, links_fixed
  1439. FROM {$wpdb->prefix}icl_translation_status
  1440. WHERE translation_id = %d
  1441. ", $translation_id), ARRAY_A);
  1442. if(!empty($_prevstate)){
  1443. $data['_prevstate'] = serialize($_prevstate);
  1444. }
  1445. list($rid, $update) = $this->update_translation_status($data);
  1446. $job_ids[] = $this->add_translation_job($rid, $translator_id, $translation_package);
  1447. if( $translation_service == 'icanlocalize' ){
  1448. global $ICL_Pro_Translation;
  1449. $sent = $ICL_Pro_Translation->send_post($post, array($lang), $translator_id);
  1450. if(!$sent){
  1451. $job_id = array_pop($job_ids);
  1452. $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->prefix}icl_translate_job WHERE job_id=%d", $job_id));
  1453. $wpdb->query($wpdb->prepare("UPDATE {$wpdb->prefix}icl_translate_job SET revision = NULL WHERE rid=%d ORDER BY job_id DESC LIMIT 1", $rid));
  1454. $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->prefix}icl_translate WHERE job_id=%d", $job_id));
  1455. }
  1456. }
  1457. } // if / else is making a duplicate
  1458. }
  1459. }
  1460. $job_ids = array_unique($job_ids);
  1461. if(array(false) == $job_ids || empty($job_ids)){
  1462. $this->messages[] = array(
  1463. 'type'=>'error',
  1464. 'text' => __('No documents were sent to translation. Make sure that translations are not currently in progress or already translated for the selected language(s).', 'sitepress')
  1465. );
  1466. }elseif(in_array(false, $job_ids)){
  1467. $this->messages[] = array(
  1468. 'type'=>'updated',
  1469. 'text' => __('Some documents were sent to translation.', 'sitepress')
  1470. );
  1471. $this->messages[] = array(
  1472. 'type'=>'error',
  1473. 'text' => __('Some documents were <i>not</i> sent to translation. Make sure that translations are not currently in progress for the selected language(s).', 'sitepress')
  1474. );
  1475. }else{
  1476. $this->messages[] = array(
  1477. 'type'=>'updated',
  1478. 'text' => __('Selected document(s) sent to translation.', 'sitepress')
  1479. );
  1480. }
  1481. return $job_ids;
  1482. }
  1483. /**
  1484. * Adds a translation job record in icl_translate_job
  1485. *
  1486. * @param mixed $rid
  1487. * @param mixed $translator_id
  1488. */
  1489. function add_translation_job($rid, $translator_id, $translation_package){
  1490. global $wpdb, $current_user;
  1491. get_currentuserinfo();
  1492. if(!$current_user->ID){
  1493. $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));
  1494. }else{
  1495. $manager_id = $current_user->ID;
  1496. }
  1497. $translation_status = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}icl_translation_status WHERE rid=%d", $rid));
  1498. // if we have a previous job_id for this rid mark it as the top (last) revision
  1499. list($prev_job_id, $prev_job_translated) = $wpdb->get_row($wpdb->prepare("
  1500. SELECT job_id, translated FROM {$wpdb->prefix}icl_translate_job WHERE rid=%d AND revision IS NULL
  1501. ", $rid), ARRAY_N);
  1502. if(!is_null($prev_job_id)){
  1503. // if previous job is not complete bail out
  1504. if(!$prev_job_translated){
  1505. //trigger_error(sprintf(__('Translation is in progress for job: %s.', 'sitepress'), $prev_job_id), E_USER_NOTICE);
  1506. return false;
  1507. }
  1508. $last_rev = $wpdb->get_var($wpdb->prepare("
  1509. SELECT MAX(revision) AS rev FROM {$wpdb->prefix}icl_translate_job WHERE rid=%d AND revision IS NOT NULL
  1510. ", $rid));
  1511. $wpdb->update($wpdb->prefix . 'icl_translate_job', array('revision'=>$last_rev+1), array('job_id'=>$prev_job_id));
  1512. $prev_job = $this->get_translation_job($prev_job_id);
  1513. $original_post = get_post($prev_job->original_doc_id);
  1514. foreach($prev_job->elements as $element){
  1515. $prev_translation[$element->field_type] = $element->field_data_translated;
  1516. switch($element->field_type){
  1517. case 'title':
  1518. if($this->decode_field_data($element->field_data, $element->field_format) == $original_post->post_title){
  1519. //$unchanged[$element->field_type] = $element->field_data_translated;
  1520. $unchanged[$element->field_type] = true;
  1521. }
  1522. break;
  1523. case 'body':
  1524. if($this->decode_field_data($element->field_data, $element->field_format) == $original_post->post_content){
  1525. //$unchanged[$element->field_type] = $element->field_data_translated;
  1526. $unchanged[$element->field_type] = true;
  1527. }
  1528. break;
  1529. case 'excerpt':
  1530. if($this->decode_field_data($element->field_data, $element->field_format) == $original_post->post_excerpt){
  1531. //$unchanged[$element->field_type] = $element->field_data_translated;
  1532. $unchanged[$element->field_type] = true;
  1533. }
  1534. break;
  1535. case 'tags':
  1536. $terms = (array)get_the_terms( $prev_job->original_doc_id , 'post_tag' );
  1537. $_taxs = array();
  1538. foreach($terms as $term){
  1539. $_taxs[] = $term->name;
  1540. }
  1541. if($element->field_data == $this->encode_field_data($_taxs, $element->field_format)){
  1542. //$unchanged['tags'] = $element->field_data_translated;
  1543. $unchanged['tags'] = true;
  1544. }
  1545. break;
  1546. case 'categories':
  1547. $terms = get_the_terms( $prev_job->original_doc_id , 'category' );
  1548. $_taxs = array();
  1549. foreach($terms as $term){
  1550. $_taxs[] = $term->name;
  1551. }
  1552. if($element->field_data == $this->encode_field_data($_taxs, $element->field_format)){
  1553. //$unchanged['categories'] = $element->field_data_translated;
  1554. $unchanged['categories'] = true;
  1555. }
  1556. break;
  1557. default:
  1558. if(false !== strpos($element->field_type, 'field-') && !empty($this->settings['custom_fields_translation'])){
  1559. $cf_name = preg_replace('#^field-#', '', $element->field_type);
  1560. if($this->decode_field_data($element->field_data, $element->field_format) == get_post_meta($prev_job->original_doc_id, $cf_name, 1)){
  1561. //$unchanged[$element->field_type] = $element->field_data_translated;
  1562. $unchanged[$element->field_type] = true;
  1563. }
  1564. }else{
  1565. // taxonomies
  1566. if(taxonomy_exists($element->field_type)){
  1567. $terms = get_the_terms( $prev_job->original_doc_id , $element->field_type );
  1568. $_taxs = array();
  1569. foreach($terms as $term){
  1570. $_taxs[] = $term->name;
  1571. }
  1572. if($element->field_data == $this->encode_field_data($_taxs, $element->field_format)){
  1573. //$unchanged[$element->field_type] = $field['data_translated'];
  1574. $unchanged[$element->field_type] = true;
  1575. }
  1576. }
  1577. }
  1578. }
  1579. }
  1580. }
  1581. $wpdb->insert($wpdb->prefix . 'icl_translate_job', array(
  1582. 'rid' => $rid,
  1583. 'translator_id' => $translator_id,
  1584. 'translated' => 0,
  1585. 'manager_id' => $manager_id
  1586. ));
  1587. $job_id = $wpdb->insert_id;
  1588. foreach($translation_package['contents'] as $field => $value){
  1589. $job_translate = array(
  1590. 'job_id' => $job_id,
  1591. 'content_id' => 0,
  1592. 'field_type' => $field,
  1593. 'field_format' => isset($value['format'])?$value['format']:'',
  1594. 'field_translate' => $value['translate'],
  1595. 'field_data' => $value['data'],
  1596. 'field_data_translated' => isset($prev_translation[$field]) ? $prev_translation[$field] : '',
  1597. 'field_finished' => 0
  1598. );
  1599. if(isset($unchanged[$field])){
  1600. $job_translate['field_finished'] = 1;
  1601. }
  1602. //$job_translate['field_data_translated'] = $unchanged[$field];
  1603. $wpdb->insert($wpdb->prefix . 'icl_translate', $job_translate);
  1604. }
  1605. if(!defined('ICL_TM_DISABLE_ALL_NOTIFICATIONS') && $translation_status->translation_service=='local'){
  1606. if($this->settings['notification']['new-job'] == ICL_TM_NOTIFICATION_IMMEDIATELY){
  1607. require_once ICL_PLUGIN_PATH . '/inc/translation-management/tm-notification.class.php';
  1608. if($job_id){
  1609. $tn_notification = new TM_Notification();
  1610. if(empty($translator_id)){
  1611. $tn_notification->new_job_any($job_id);
  1612. }else{
  1613. $tn_notification->new_job_translator($job_id, $translator_id);
  1614. }
  1615. }
  1616. }
  1617. }
  1618. return $job_id;
  1619. }
  1620. function assign_translation_job($job_id, $translator_id, $service='local'){
  1621. global $wpdb;
  1622. 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);
  1623. require_once ICL_PLUGIN_PATH . '/inc/translation-management/tm-notification.class.php';
  1624. $tn_notification = new TM_Notification();
  1625. if(!empty($prev_translator_id) && $prev_translator_id != $translator_id){
  1626. if($job_id){
  1627. $tn_notification->translator_removed($prev_translator_id, $job_id);
  1628. }
  1629. }
  1630. if($this->settings['notification']['new-job'] == ICL_TM_NOTIFICATION_IMMEDIATELY){
  1631. if(empty($translator_id)){
  1632. $tn_notification->new_job_any($job_id);
  1633. }else{
  1634. $tn_notification->new_job_translator($job_id, $translator_id);
  1635. }
  1636. }
  1637. $wpdb->update($wpdb->prefix.'icl_translation_status',
  1638. array('translator_id'=>$translator_id, 'status'=>ICL_TM_WAITING_FOR_TRANSLATOR, 'translation_service' => $service),
  1639. array('rid'=>$rid));
  1640. $wpdb->update($wpdb->prefix.'icl_translate_job', array('translator_id'=>$translator_id), array('job_id'=>$job_id));
  1641. return true;
  1642. }
  1643. function get_translation_jobs($args = array()){
  1644. global $wpdb, $sitepress, $wp_query;
  1645. // defaults
  1646. $args_default = array(
  1647. 'translator_id' => 0,
  1648. 'status' => false,
  1649. 'include_unassigned' => false
  1650. );
  1651. extract($args_default);
  1652. extract($args, EXTR_OVERWRITE);
  1653. $_exp = explode('-', $translator_id);
  1654. $service = isset($_exp[1]) ? $_exp[1] : 'local';
  1655. $translator_id = $_exp[0];
  1656. $where = " s.status > " . ICL_TM_NOT_TRANSLATED;
  1657. if($status != ''){
  1658. $where .= " AND s.status=" . intval($status);
  1659. }
  1660. if($status != ICL_TM_DUPLICATE){
  1661. $where .= " AND s.status <> " . ICL_TM_DUPLICATE;
  1662. }
  1663. if(!empty($translator_id)){
  1664. if($include_unassigned){
  1665. $where .= " AND (j.translator_id=" . intval($translator_id) . " OR j.translator_id=0) ";
  1666. }else{
  1667. $where .= " AND j.translator_id=" . intval($translator_id);
  1668. }
  1669. if(!empty($service)){
  1670. $where .= " AND s.translation_service='{$service}'";
  1671. }
  1672. }
  1673. if(!empty($from)){
  1674. $where .= " AND t.source_language_code='".$wpdb->escape($from)."'";
  1675. }
  1676. if(!empty($to)){
  1677. $where .= " AND t.language_code='".$wpdb->escape($to)."'";
  1678. }
  1679. // ORDER BY
  1680. if($include_unassigned){
  1681. $orderby[] = 'j.translator_id DESC';
  1682. }
  1683. $orderby[] = ' j.job_id DESC ';
  1684. $orderby = join(', ', $orderby);
  1685. // LIMIT
  1686. if(!isset($_GET['paged'])) $_GET['paged'] = 1;
  1687. $offset = ($_GET['paged']-1)*$limit_no;
  1688. $limit = " " . $offset . ',' . $limit_no;
  1689. $jobs = $wpdb->get_results(
  1690. "SELECT SQL_CALC_FOUND_ROWS
  1691. j.job_id, t.trid, t.language_code, t.source_language_code,
  1692. s.translation_id, s.status, s.needs_update, s.translator_id, u.display_name AS translator_name, s.translation_service
  1693. FROM {$wpdb->prefix}icl_translate_job j
  1694. JOIN {$wpdb->prefix}icl_translation_status s ON j.rid = s.rid
  1695. JOIN {$wpdb->prefix}icl_translations t ON s.translation_id = t.translation_id
  1696. LEFT JOIN {$wpdb->users} u ON s.translator_id = u.ID
  1697. WHERE {$where} AND revision IS NULL
  1698. ORDER BY {$orderby}
  1699. LIMIT {$limit}
  1700. "
  1701. );
  1702. $count = $wpdb->get_var("SELECT FOUND_ROWS()");
  1703. $wp_query->found_posts = $count;
  1704. $wp_query->query_vars['posts_per_page'] = $limit_no;
  1705. $wp_query->max_num_pages = ceil($wp_query->found_posts/$limit_no);
  1706. foreach($jobs as $k=>$row){
  1707. //original
  1708. $post_id = $wpdb->get_var($wpdb->prepare("
  1709. SELECT field_data
  1710. FROM {$wpdb->prefix}icl_translate
  1711. WHERE job_id=%d and field_type='original_id'", $row->job_id));
  1712. $parts = explode('_', $post_id);
  1713. if ($parts[0] == 'external') {
  1714. $jobs[$k]->original_doc_id = $post_id;
  1715. $jobs[$k]->post_title = base64_decode($wpdb->get_var($wpdb->prepare("
  1716. SELECT field_data
  1717. FROM {$wpdb->prefix}icl_translate
  1718. WHERE job_id=%d and field_type='name'", $row->job_id)));
  1719. if ($jobs[$k]->post_title == "") {
  1720. // try the title field.
  1721. $jobs[$k]->post_title = base64_decode($wpdb->get_var($wpdb->prepare("
  1722. SELECT field_data
  1723. FROM {$wpdb->prefix}icl_translate
  1724. WHERE job_id=%d and field_type='title'", $row->job_id)));
  1725. }
  1726. $jobs[$k]->edit_link = $this->tm_post_link($post_id);
  1727. $ldf = $sitepress->get_language_details($row->source_language_code);
  1728. } else {
  1729. $doc = $wpdb->get_row($wpdb->prepare("SELECT ID, post_title, post_type FROM {$wpdb->posts} WHERE ID=%d", $post_id));
  1730. if ($doc) {
  1731. $jobs[$k]->post_title = $doc->post_title;
  1732. $jobs[$k]->original_doc_id = $doc->ID;
  1733. $jobs[$k]->edit_link = get_edit_post_link($doc->ID);
  1734. $ldf = $sitepress->get_language_details($sitepress->get_element_language_details($post_id, 'post_' . $doc->post_type)->language_code);
  1735. } else {
  1736. $jobs[$k]->post_title = __("The original has been deleted!", "sitepress");
  1737. $jobs[$k]->original_doc_id = 0;
  1738. $jobs[$k]->edit_link = "";
  1739. $ldf['display_name'] = __("Deleted", "sitepress");
  1740. }
  1741. }
  1742. $ldt = $sitepress->get_language_details($row->language_code);
  1743. $jobs[$k]->lang_text = $ldf['display_name'] . ' &raquo; ' . $ldt['display_name'];
  1744. if($row->translation_service=='icanlocalize'){
  1745. $row->translator_name = ICL_Pro_Translation::get_translator_name($row->translator_id);
  1746. }
  1747. }
  1748. return $jobs;
  1749. }
  1750. function get_translation_job($job_id, $include_non_translatable_elements = false, $auto_assign = false, $revisions = 0){
  1751. global $wpdb, $sitepress, $current_user;
  1752. get_currentuserinfo();
  1753. $job = $wpdb->get_row($wpdb->prepare("
  1754. SELECT
  1755. j.rid, j.translator_id, j.translated, j.manager_id,
  1756. s.status, s.needs_update, s.translation_service,
  1757. t.trid, t.language_code, t.source_language_code
  1758. FROM {$wpdb->prefix}icl_translate_job j
  1759. JOIN {$wpdb->prefix}icl_translation_status s ON j.rid = s.rid
  1760. JOIN {$wpdb->prefix}icl_translations t ON s.translation_id = t.translation_id
  1761. WHERE j.job_id = %d", $job_id));
  1762. $post_id = $wpdb->get_var($wpdb->prepare("
  1763. SELECT field_data
  1764. FROM {$wpdb->prefix}icl_translate
  1765. WHERE job_id=%d and field_type='original_id'", $job_id));
  1766. $parts = explode('_', $post_id);
  1767. if ($parts[0] == 'external') {
  1768. $job->original_doc_id = $post_id;
  1769. $job->original_doc_title = base64_decode($wpdb->get_var($wpdb->prepare("
  1770. SELECT field_data
  1771. FROM {$wpdb->prefix}icl_translate
  1772. WHERE job_id=%d and field_type='name'", $job_id)));
  1773. if ($job->original_doc_title == "") {
  1774. // try the title field.
  1775. $job->original_doc_title = base64_decode($wpdb->get_var($wpdb->prepare("
  1776. SELECT field_data
  1777. FROM {$wpdb->prefix}icl_translate
  1778. WHERE job_id=%d and field_type='title'", $job_id)));
  1779. }
  1780. $job->original_post_type = $wpdb->get_var($wpdb->prepare("
  1781. SELECT element_type
  1782. FROM {$wpdb->prefix}icl_translations
  1783. WHERE trid=%d AND language_code='%s'",
  1784. $job->trid, $job->source_language_code));
  1785. } else {
  1786. $original = $wpdb->get_row($wpdb->prepare("
  1787. SELECT t.element_id, p.post_title, p.post_type
  1788. FROM {$wpdb->prefix}icl_translations t
  1789. JOIN {$wpdb->posts} p ON t.element_id = p.ID AND t.trid = %d
  1790. WHERE t.language_code = '%s'", $job->trid, $job->source_language_code));
  1791. $job->original_doc_title = $original->post_title;
  1792. $job->original_doc_id = $original->element_id;
  1793. $job->original_post_type = $original->post_type;
  1794. }
  1795. $_ld = $sitepress->get_language_details($job->source_language_code);
  1796. $job->from_language = $_ld['display_name'];
  1797. $_ld = $sitepress->get_language_details($job->language_code);
  1798. $job->to_language = $_ld['display_name'];
  1799. if(!$include_non_translatable_elements){
  1800. $jelq = ' AND field_translate = 1';
  1801. }else{
  1802. $jelq = '';
  1803. }
  1804. $job->elements = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->prefix}icl_translate WHERE job_id = %d {$jelq} ORDER BY tid ASC", $job_id));
  1805. if($job->translator_id == 0 || $job->status == ICL_TM_WAITING_FOR_TRANSLATOR){
  1806. if($auto_assign){
  1807. $wpdb->update($wpdb->prefix . 'icl_translate_job', array('translator_id' => $this->current_translator->translator_id), array('job_id'=>$job_id));
  1808. $wpdb->update($wpdb->prefix . 'icl_translation_status',
  1809. array('translator_id' => $this->current_translator->translator_id, 'status' => ICL_TM_IN_PROGRESS),
  1810. array('rid'=>$job->rid)
  1811. );
  1812. }
  1813. }elseif($job->translator_id != @intval($this->current_translator->translator_id) && !defined('XMLRPC_REQUEST') && $job->manager_id != $current_user->ID){
  1814. static $erroronce = array();
  1815. if(empty($erroronce[$job_id])){
  1816. $this->messages[] = array(
  1817. 'type' => 'error', 'text' => sprintf(__("You can't translate this document. It's assigned to a different translator.<br /> Document: <strong>%s</strong> (ID = %d).", 'sitepress') , $job->original_doc_title, $job_id)
  1818. );
  1819. $erroronce[$job_id] = true;
  1820. }
  1821. return false;
  1822. }
  1823. //do we have a previous version
  1824. if($revisions > 0){
  1825. $prev_version_job_id = $wpdb->get_var($wpdb->prepare("
  1826. SELECT MAX(job_id)
  1827. FROM {$wpdb->prefix}icl_translate_job
  1828. WHERE rid=%d AND job_id < %d", $job->rid, $job_id));
  1829. if($prev_version_job_id){
  1830. $job->prev_version = $this->get_translation_job($prev_version_job_id, false, false, $revisions - 1);
  1831. }
  1832. }
  1833. // allow adding custom elements
  1834. $job->elements = apply_filters('icl_job_elements', $job->elements, $post_id, $job_id);
  1835. return $job;
  1836. }
  1837. function get_translation_job_id($trid, $language_code){
  1838. global $wpdb, $sitepress;
  1839. $job_id = $wpdb->get_var($wpdb->prepare("
  1840. SELECT tj.job_id FROM {$wpdb->prefix}icl_translate_job tj
  1841. JOIN {$wpdb->prefix}icl_translation_status ts ON tj.rid = ts.rid
  1842. JOIN {$wpdb->prefix}icl_translations t ON ts.translation_id = t.translation_id
  1843. WHERE t.trid = %d AND t.language_code='%s'
  1844. ORDER BY tj.job_id DESC LIMIT 1
  1845. ", $trid, $language_code));
  1846. return $job_id;
  1847. }
  1848. function _save_translation_field($tid, $field){
  1849. global $wpdb;
  1850. $update['field_data_translated'] = $this->encode_field_data($field['data'], $field['format']);
  1851. if(isset($field['finished']) && $field['finished']){
  1852. $update['field_finished'] = 1;
  1853. }
  1854. $wpdb->update($wpdb->prefix . 'icl_translate', $update, array('tid'=>$tid));
  1855. }
  1856. function save_translation($data){
  1857. global $wpdb, $sitepress, $sitepress_settings, $ICL_Pro_Translation;
  1858. $is_incomplete = false;
  1859. foreach($data['fields'] as $field){
  1860. $this->_save_translation_field($field['tid'], $field);
  1861. if(!isset($field['finished']) || !$field['finished']){
  1862. $is_incomplete = true;
  1863. }
  1864. }
  1865. if(!empty($data['complete']) && !$is_incomplete){
  1866. $wpdb->update($wpdb->prefix . 'icl_translate_job', array('translated'=>1), array('job_id'=>$data['job_id']));
  1867. $rid = $wpdb->get_var($wpdb->prepare("SELECT rid FROM {$wpdb->prefix}icl_translate_job WHERE job_id=%d", $data['job_id']));
  1868. $translation_id = $wpdb->get_var($wpdb->prepare("SELECT translation_id FROM {$wpdb->prefix}icl_translation_status WHERE rid=%d", $rid));
  1869. $wpdb->update($wpdb->prefix . 'icl_translation_status', array('status'=>ICL_TM_COMPLETE, 'needs_update'=>0), array('rid'=>$rid));
  1870. list($element_id, $trid) = $wpdb->get_row($wpdb->prepare("SELECT element_id, trid FROM {$wpdb->prefix}icl_translations WHERE translation_id=%d", $translation_id), ARRAY_N);
  1871. $job = $this->get_translation_job($data['job_id'], true);
  1872. $parts = explode('_', $job->original_doc_id);
  1873. if ($parts[0] == 'external') {
  1874. // Translations are saved in the string table for 'external' types
  1875. $id = array_pop($parts);
  1876. unset($parts[0]);
  1877. $type = implode('_', $parts);
  1878. foreach($job->elements as $field){
  1879. if ($field->field_translate) {
  1880. if (function_exists('icl_st_is_registered_string')) {
  1881. $string_id = icl_st_is_registered_string($type, $id . '_' . $field->field_type);
  1882. if (!$string_id) {
  1883. icl_register_string($type, $id . '_' . $field->field_type, $this->decode_field_data($field->field_data, $field->field_format));
  1884. $string_id = icl_st_is_registered_string($type, $id . '_' . $field->field_type);
  1885. }
  1886. if ($string_id) {
  1887. icl_add_string_translation($string_id, $job->language_code, $this->decode_field_data($field->field_data_translated, $field->field_format), ICL_STRING_TRANSLATION_COMPLETE);
  1888. }
  1889. }
  1890. }
  1891. }
  1892. } else {
  1893. if(!is_null($element_id)){
  1894. $postarr['ID'] = $_POST['post_ID'] = $element_id;
  1895. }
  1896. foreach($job->elements as $field){
  1897. switch($field->field_type){
  1898. case 'title':
  1899. $postarr['post_title'] = $this->decode_field_data($field->field_data_translated, $field->field_format);
  1900. break;
  1901. case 'body':
  1902. $postarr['post_content'] = $this->decode_field_data($field->field_data_translated, $field->field_format);
  1903. break;
  1904. case 'excerpt':
  1905. $postarr['post_excerpt'] = $this->decode_field_data($field->field_data_translated, $field->field_format);
  1906. break;
  1907. case 'URL':
  1908. $postarr['post_name'] = $this->decode_field_data($field->field_data_translated, $field->field_format);
  1909. break;
  1910. case 'tags':
  1911. $tags = $this->decode_field_data($field->field_data_translated, $field->field_format);
  1912. $original_tags = $this->decode_field_data($field->field_data, $field->field_format);
  1913. // create tags that don't exist
  1914. foreach($tags as $k=>$t){
  1915. $thetag = $sitepress->get_term_by_name_and_lang($t, 'post_tag', $job->language_code);
  1916. $tags[$k] = $t; // Save $t as we may have added @.lang to it
  1917. if(empty($thetag)){
  1918. $the_original_tag = $sitepress->get_term_by_name_and_lang($original_tags[$k], 'post_tag', $job->source_language_code);
  1919. $tmp = wp_insert_term($t, 'post_tag');
  1920. if(!is_wp_error($tmp) && isset($tmp['term_taxonomy_id'])){
  1921. $sitepress->set_term_translation($the_original_tag,
  1922. $tmp['term_taxonomy_id'],
  1923. 'post_tag',
  1924. $job->language_code,
  1925. $job->source_language_code);
  1926. }
  1927. }
  1928. }
  1929. $postarr['tags_input'] = join(',', $tags);
  1930. $postarr['tax_input']['post_tag'] = $tags;
  1931. break;
  1932. case 'categories':
  1933. $cats = $this->decode_field_data($field->field_data_translated, $field->field_format);
  1934. $original_cats = $this->decode_field_data($field->field_data, $field->field_format);
  1935. $missing_parents = array();
  1936. foreach($cats as $k=>$c){
  1937. $parent_missing = false;
  1938. $thecat = $sitepress->get_term_by_name_and_lang($c, 'category', $job->language_code);
  1939. if(empty($thecat)){
  1940. $the_original_cat = $sitepress->get_term_by_name_and_lang($original_cats[$k], 'category', $job->source_language_code);
  1941. if ($the_original_cat) {
  1942. $the_original_cat_parent = $wpdb->get_var("SELECT parent FROM {$wpdb->term_taxonomy} WHERE term_taxonomy_id=".$the_original_cat->term_taxonomy_id);
  1943. } else {
  1944. $the_original_cat_parent = false;
  1945. }
  1946. if($the_original_cat_parent){
  1947. $op_tr = icl_object_id($the_original_cat_parent, 'category', false, $job->language_code);
  1948. if (!$op_tr) {
  1949. // The parent is missing. Possibly because we haven't created a translation of it yet
  1950. $parent_missing = true;
  1951. }
  1952. }else{$op_tr = 0;}
  1953. $tmp = wp_insert_term($c, 'category', array('parent'=>$op_tr));
  1954. if(!is_wp_error($tmp) && isset($tmp['term_taxonomy_id'])){
  1955. $sitepress->set_term_translation($the_original_cat,
  1956. $tmp['term_taxonomy_id'],
  1957. 'category',
  1958. $job->language_code,
  1959. $job->source_language_code);
  1960. }
  1961. $cat_id = $tmp['term_id'];
  1962. }else{
  1963. $cat_id = $thecat->term_id;
  1964. }
  1965. $cat_ids[] = $cat_id;
  1966. if ($parent_missing) {
  1967. $missing_parents[$cat_id] = $the_original_cat_parent;
  1968. }
  1969. }
  1970. // Double check missing parents as they might be available now.
  1971. foreach ($missing_parents as $cat_id => $the_original_cat_parent) {
  1972. $op_tr = icl_object_id($the_original_cat_parent, 'category', false, $job->language_code);
  1973. $cat_trid = $sitepress->get_element_trid($cat_id,'tax_category');
  1974. wp_update_term($cat_id, 'category', array('parent' => $op_tr));
  1975. $wpdb->update($wpdb->prefix.'icl_translations',
  1976. array('language_code'=>$job->language_code, 'trid'=>$cat_trid, 'source_language_code'=>$job->source_language_code),
  1977. array('element_type'=>'tax_category','element_id'=>$cat_id));
  1978. }
  1979. $postarr['post_category'] = $cat_ids;
  1980. break;
  1981. default:
  1982. if(in_array($field->field_type, $sitepress->get_translatable_taxonomies(false, $job->original_post_type))){
  1983. $taxs = $this->decode_field_data($field->field_data_translated, $field->field_format);
  1984. $original_taxs = $this->decode_field_data($field->field_data, $field->field_format);
  1985. $taxonomy = $field->field_type;
  1986. $alltaxs = $tax_ids = array();
  1987. foreach($taxs as $k=>$c){
  1988. $thetax = $sitepress->get_term_by_name_and_lang($c, $taxonomy, $job->language_code);
  1989. $taxs[$k] = $c; // Save $c as we may have added @.lang to it
  1990. if(empty($thetax)){
  1991. $the_original_tax = $sitepress->get_term_by_name_and_lang($original_taxs[$k], $taxonomy, $job->source_language_code);
  1992. $the_original_tax_parent = $wpdb->get_var("SELECT parent FROM {$wpdb->term_taxonomy} WHERE term_taxonomy_id=".$the_original_tax->term_taxonomy_id);
  1993. if($the_original_tax_parent){
  1994. $op_tr = icl_object_id($the_original_tax_parent, $taxonomy, false, $job->language_code);
  1995. }else{$op_tr = 0;}
  1996. $tmp = wp_insert_term($c, $taxonomy, array('parent'=>$op_tr));
  1997. if(isset($tmp['term_taxonomy_id'])){
  1998. $sitepress->set_term_translation($the_original_tax,
  1999. $tmp['term_taxonomy_id'],
  2000. $taxonomy,
  2001. $job->language_code,
  2002. $job->source_language_code);
  2003. }
  2004. $tax_id = $tmp['term_id'];
  2005. }else{
  2006. $tax_id = $thetax->term_id;
  2007. }
  2008. $tax_ids[] = $tax_id;
  2009. $alltaxs[] = $c;
  2010. }
  2011. $taxonomy_obj = get_taxonomy($taxonomy);
  2012. // array = hierarchical, string = non-hierarchical.
  2013. if ($taxonomy_obj->hierarchical) {
  2014. $postarr['tax_input'][$taxonomy] = $tax_ids;
  2015. } else {
  2016. $postarr['tax_input'][$taxonomy] = $taxs;
  2017. }
  2018. }
  2019. }
  2020. }
  2021. $original_post = get_post($job->original_doc_id);
  2022. $postarr['post_author'] = $original_post->post_author;
  2023. $postarr['post_type'] = $original_post->post_type;
  2024. if($sitepress_settings['sync_comment_status']){
  2025. $postarr['comment_status'] = $original_post->comment_status;
  2026. }
  2027. if($sitepress_settings['sync_ping_status']){
  2028. $postarr['ping_status'] = $original_post->ping_status;
  2029. }
  2030. if($sitepress_settings['sync_page_ordering']){
  2031. $postarr['menu_order'] = $original_post->menu_order;
  2032. }
  2033. if($sitepress_settings['sync_private_flag'] && $original_post->post_status=='private'){
  2034. $postarr['post_status'] = 'private';
  2035. }
  2036. if($sitepress_settings['sync_post_date']){
  2037. $postarr['post_date'] = $original_post->post_date;
  2038. }
  2039. if(is_null($element_id)){
  2040. $postarr['post_status'] = !$sitepress_settings['translated_document_status'] ? 'draft' : $original_post->post_status;
  2041. } else {
  2042. // set post_status to the current post status.
  2043. $postarr['post_status'] = $wpdb->get_var("SELECT post_status FROM {$wpdb->prefix}posts WHERE ID = ".$element_id);
  2044. }
  2045. if($original_post->post_parent){
  2046. $post_parent_trid = $wpdb->get_var("SELECT trid FROM {$wpdb->prefix}icl_translations
  2047. WHERE element_type='post_{$original_post->post_type}' AND element_id='{$original_post->post_parent}'");
  2048. if($post_parent_trid){
  2049. $parent_id = $wpdb->get_var("SELECT element_id FROM {$wpdb->prefix}icl_translations
  2050. WHERE element_type='post_{$original_post->post_type}' AND trid='{$post_parent_trid}' AND language_code='{$job->language_code}'");
  2051. }
  2052. }
  2053. if(isset($parent_id) && $sitepress_settings['sync_page_parent']){
  2054. $_POST['post_parent'] = $postarr['post_parent'] = $parent_id;
  2055. $_POST['parent_id'] = $postarr['parent_id'] = $parent_id;
  2056. }
  2057. $_POST['trid'] = $trid;
  2058. $_POST['lang'] = $job->language_code;
  2059. $_POST['skip_sitepress_actions'] = true;
  2060. $postarr = apply_filters('icl_pre_save_pro_translation', $postarr);
  2061. if(isset($element_id)){ // it's an update so dont change the url
  2062. $postarr['post_name'] = $wpdb->get_var($wpdb->prepare("SELECT post_name FROM {$wpdb->posts} WHERE ID=%d", $element_id));
  2063. }
  2064. $new_post_id = wp_insert_post($postarr);
  2065. do_action('icl_pro_translation_saved', $new_post_id, $data['fields']);
  2066. // Allow identical slugs
  2067. $post_name = sanitize_title($postarr['post_title']);
  2068. $post_name_rewritten = $wpdb->get_var($wpdb->prepare("SELECT post_name FROM {$wpdb->posts} WHERE ID=%d", $new_post_id));
  2069. $post_name_base = $post_name;
  2070. if($post_name != $post_name_rewritten){
  2071. $incr = 1;
  2072. do{
  2073. $exists = $wpdb->get_var($wpdb->prepare("
  2074. SELECT p.ID FROM {$wpdb->posts} p
  2075. JOIN {$wpdb->prefix}icl_translations t ON t.element_id = p.ID AND t.element_type=%s
  2076. WHERE p.ID <> %d AND t.language_code = %s AND p.post_name=%s
  2077. ", 'post_' . $postarr['post_type'], $new_post_id, $job->language_code, $post_name));
  2078. if($exists){
  2079. $incr++;
  2080. }else{
  2081. break;
  2082. }
  2083. $post_name = $post_name_base . '-' . $incr;
  2084. }while($exists);
  2085. $wpdb->update($wpdb->posts, array('post_name' => $post_name), array('ID' => $new_post_id));
  2086. }
  2087. $ICL_Pro_Translation->_content_fix_links_to_translated_content($new_post_id, $job->language_code);
  2088. // update body translation with the links fixed
  2089. $new_post_content = $wpdb->get_var($wpdb->prepare("SELECT post_content FROM {$wpdb->posts} WHERE ID=%d", $new_post_id));
  2090. foreach($job->elements as $jel){
  2091. if($jel->field_type=='body'){
  2092. $fields_data_translated = $this->encode_field_data($new_post_content, $jel->field_format);
  2093. break;
  2094. }
  2095. }
  2096. $wpdb->update($wpdb->prefix.'icl_translate', array('field_data_translated'=>$fields_data_translated), array('job_id'=>$data['job_id'], 'field_type'=>'body'));
  2097. // set stickiness
  2098. //is the original post a sticky post?
  2099. remove_filter('option_sticky_posts', array($sitepress,'option_sticky_posts')); // remove filter used to get language relevant stickies. get them all
  2100. $sticky_posts = get_option('sticky_posts');
  2101. $is_original_sticky = $original_post->post_type=='post' && in_array($original_post->ID, $sticky_posts);
  2102. if($is_original_sticky && $sitepress_settings['sync_sticky_flag']){
  2103. stick_post($new_post_id);
  2104. }else{
  2105. if($original_post->post_type=='post' && !is_null($element_id)){
  2106. unstick_post($new_post_id); //just in case - if this is an update and the original post stckiness has changed since the post was sent to translation
  2107. }
  2108. }
  2109. //sync plugins texts
  2110. foreach((array)$this->settings['custom_fields_translation'] as $cf => $op){
  2111. if ($op == 1) {
  2112. update_post_meta($new_post_id, $cf, get_post_meta($original_post->ID,$cf,true));
  2113. }
  2114. }
  2115. // set specific custom fields
  2116. $copied_custom_fields = array('_top_nav_excluded', '_cms_nav_minihome');
  2117. foreach($copied_custom_fields as $ccf){
  2118. $val = get_post_meta($original_post->ID, $ccf, true);
  2119. update_post_meta($new_post_id, $ccf, $val);
  2120. }
  2121. // sync _wp_page_template
  2122. if($sitepress_settings['sync_page_template']){
  2123. $_wp_page_template = get_post_meta($original_post->ID, '_wp_page_template', true);
  2124. if(!empty($_wp_page_template)){
  2125. update_post_meta($new_post_id, '_wp_page_template', $_wp_page_template);
  2126. }
  2127. }
  2128. // set the translated custom fields if we have any.
  2129. foreach((array)$this->settings['custom_fields_translation'] as $field_name => $val){
  2130. if ($val == 2) { // should be translated
  2131. // find it in the translation
  2132. foreach($job->elements as $name => $eldata) {
  2133. if ($eldata->field_data == $field_name) {
  2134. if (preg_match("/field-(.*?)-name/", $eldata->field_type, $match)) {
  2135. $field_id = $match[1];
  2136. foreach($job->elements as $k => $v){
  2137. if($v->field_type=='field-'.$field_id){
  2138. $field_translation = $this->decode_field_data($v->field_data_translated, $v->field_format) ;
  2139. }
  2140. if($v->field_type=='field-'.$field_id.'-type'){
  2141. $field_type = $v->field_data;
  2142. }
  2143. }
  2144. if ($field_type == 'custom_field') {
  2145. $field_translation = str_replace ( '&#0A;', "\n", $field_translation );
  2146. // always decode html entities eg decode &amp; to &
  2147. $field_translation = html_entity_decode($field_translation);
  2148. update_post_meta($new_post_id, $field_name, $field_translation);
  2149. }
  2150. }
  2151. }
  2152. }
  2153. }
  2154. }
  2155. $link = get_edit_post_link($new_post_id);
  2156. if ($link == '') {
  2157. // the current user can't edit so just include permalink
  2158. $link = get_permalink($new_post_id);
  2159. }
  2160. if(is_null($element_id)){
  2161. $wpdb->update($wpdb->prefix.'icl_translations', array('element_id' => $new_post_id), array('translation_id' => $translation_id) );
  2162. $user_message = __('Translation added: ', 'sitepress') . '<a href="'.$link.'">' . $postarr['post_title'] . '</a>.';
  2163. }else{
  2164. $user_message = __('Translation updated: ', 'sitepress') . '<a href="'.$link.'">' . $postarr['post_title'] . '</a>.';
  2165. }
  2166. }
  2167. $this->messages[] = array(
  2168. 'type'=>'updated',
  2169. 'text' => $user_message
  2170. );
  2171. if($this->settings['notification']['completed'] != ICL_TM_NOTIFICATION_NONE){
  2172. require_once ICL_PLUGIN_PATH . '/inc/translation-management/tm-notification.class.php';
  2173. if($data['job_id']){
  2174. $tn_notification = new TM_Notification();
  2175. $tn_notification->work_complete($data['job_id'], !is_null($element_id));
  2176. }
  2177. }
  2178. self::set_page_url($new_post_id);
  2179. // redirect to jobs list
  2180. wp_redirect(admin_url(sprintf('admin.php?page=%s&%s=%d',
  2181. WPML_TM_FOLDER . '/menu/translations-queue.php', is_null($element_id) ? 'added' : 'updated', is_null($element_id) ? $new_post_id : $element_id )));
  2182. }else{
  2183. $this->messages[] = array('type'=>'updated', 'text' => __('Translation (incomplete) saved.', 'sitepress'));
  2184. }
  2185. }
  2186. // returns a front end link to a post according to the user access
  2187. // hide_empty - if current user doesn't have access to the link don't show at all
  2188. public function tm_post_link($post_id, $anchor = false, $hide_empty = false){
  2189. global $current_user;
  2190. get_currentuserinfo();
  2191. $parts = explode('_', $post_id);
  2192. if ($parts[0] == 'external') {
  2193. $link = '';
  2194. return apply_filters('WPML_get_link', $link, $post_id, $anchor, $hide_empty);
  2195. }
  2196. if(false === $anchor){
  2197. $anchor = get_the_title($post_id);
  2198. }
  2199. $opost = get_post($post_id);
  2200. if(($opost->post_status == 'draft' || $opost->post_status == 'private') && $opost->post_author != $current_user->data->ID){
  2201. if($hide_empty){
  2202. $elink = '';
  2203. }else{
  2204. $elink = sprintf('<i>%s</i>', $anchor);
  2205. }
  2206. }else{
  2207. $elink = sprintf('<a href="%s">%s</a>', get_permalink($post_id), $anchor);
  2208. }
  2209. return $elink;
  2210. }
  2211. public function tm_post_permalink($post_id){
  2212. global $current_user;
  2213. get_currentuserinfo();
  2214. $parts = explode('_', $post_id);
  2215. if ($parts[0] == 'external') {
  2216. return '';
  2217. }
  2218. $opost = get_post($post_id);
  2219. if(($opost->post_status == 'draft' || $opost->post_status == 'private') && $opost->post_author != $current_user->data->ID){
  2220. $elink = '';
  2221. }else{
  2222. $elink = get_permalink($post_id);
  2223. }
  2224. return $elink;
  2225. }
  2226. //
  2227. // when the translated post was created, we have the job_id and need to update the job
  2228. function save_job_fields_from_post($job_id, $post){
  2229. global $wpdb, $sitepress;
  2230. $data['complete'] = 1;
  2231. $data['job_id'] = $job_id;
  2232. $job = $this->get_translation_job($job_id,1);
  2233. if(is_array($job->elements))
  2234. foreach($job->elements as $element){
  2235. $field_data = '';
  2236. switch($element->field_type){
  2237. case 'title':
  2238. $field_data = $this->encode_field_data($post->post_title, $element->field_format);
  2239. break;
  2240. case 'body':
  2241. $field_data = $this->encode_field_data($post->post_content, $element->field_format);
  2242. break;
  2243. case 'excerpt':
  2244. $field_data = $this->encode_field_data($post->post_excerpt, $element->field_format);
  2245. break;
  2246. default:
  2247. if(false !== strpos($element->field_type, 'field-') && !empty($this->settings['custom_fields_translation'])){
  2248. $cf_name = preg_replace('#^field-#', '', $element->field_type);
  2249. if(isset($this->settings['custom_fields_translation'][$cf_name])){
  2250. if($this->settings['custom_fields_translation'][$cf_name] == 1){ //copy
  2251. $field_data = get_post_meta($original_post->ID, $cf_name, 1);
  2252. if(is_scalar($field_data))
  2253. $field_data = $this->encode_field_data($field_data, $element->field_format);
  2254. else $field_data = '';
  2255. }elseif($this->settings['custom_fields_translation'][$cf_name] == 2){ // translate
  2256. $field_data = get_post_meta($post->ID, $cf_name, 1);
  2257. if(is_scalar($field_data))
  2258. $field_data = $this->encode_field_data($field_data, $element->field_format);
  2259. else $field_data = '';
  2260. }
  2261. }
  2262. }else{
  2263. if(in_array($element->field_type, $sitepress->get_translatable_taxonomies(true, $post->post_type))){
  2264. $ids = array();
  2265. foreach($job->elements as $je){
  2266. if($je->field_type == $element->field_type .'_ids' ){
  2267. $ids = explode(',', $je->field_data);
  2268. }
  2269. }
  2270. $translated_tax_names = array();
  2271. foreach($ids as $id){
  2272. $translated_tax_id = icl_object_id($id, $element->field_type,false,$job->language_code);
  2273. if($translated_tax_id){
  2274. $translated_tax_names[] = $wpdb->get_var($wpdb->prepare("
  2275. SELECT t.name FROM {$wpdb->terms} t JOIN {$wpdb->term_taxonomy} x ON t.term_id = x.term_id
  2276. WHERE x.term_taxonomy_id = {$translated_tax_id}
  2277. "));
  2278. }
  2279. }
  2280. $field_data = $this->encode_field_data($translated_tax_names, $element->field_format);
  2281. }
  2282. }
  2283. }
  2284. $wpdb->update($wpdb->prefix.'icl_translate',
  2285. array('field_data_translated'=>$field_data, 'field_finished'=>1),
  2286. array('tid'=>$element->tid)
  2287. );
  2288. }
  2289. $this->mark_job_done($job_id);
  2290. }
  2291. public function determine_translated_taxonomies($elements, $taxonomy, $translated_language){
  2292. global $sitepress, $wpdb;
  2293. foreach($elements as $k=>$element){
  2294. $term = get_term_by('name', $element, $taxonomy);
  2295. if ($term) {
  2296. $trid = $sitepress->get_element_trid($term->term_taxonomy_id, 'tax_' . $taxonomy);
  2297. $translations = $sitepress->get_element_translations($trid, 'tax_' . $taxonomy);
  2298. if(isset($translations[$translated_language])){
  2299. $translated_elements[$k] = $translations[$translated_language]->name;
  2300. }else{
  2301. $translated_elements[$k] = '';
  2302. }
  2303. } else {
  2304. $translated_elements[$k] = '';
  2305. }
  2306. }
  2307. return $translated_elements;
  2308. }
  2309. function mark_job_done($job_id){
  2310. global $wpdb;
  2311. $wpdb->update($wpdb->prefix.'icl_translate_job', array('translated'=>1), array('job_id'=>$job_id));
  2312. $wpdb->update($wpdb->prefix.'icl_translate', array('field_finished'=>1), array('job_id'=>$job_id));
  2313. }
  2314. function resign_translator($job_id){
  2315. global $wpdb;
  2316. list($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);
  2317. if(!empty($translator_id)){
  2318. if($this->settings['notification']['resigned'] != ICL_TM_NOTIFICATION_NONE){
  2319. require_once ICL_PLUGIN_PATH . '/inc/translation-management/tm-notification.class.php';
  2320. if($job_id){
  2321. $tn_notification = new TM_Notification();
  2322. $tn_notification->translator_resigned($translator_id, $job_id);
  2323. }
  2324. }
  2325. }
  2326. $wpdb->update($wpdb->prefix.'icl_translate_job', array('translator_id'=>0), array('job_id'=>$job_id));
  2327. $wpdb->update($wpdb->prefix.'icl_translation_status', array('translator_id'=>0, 'status'=>ICL_TM_WAITING_FOR_TRANSLATOR), array('rid'=>$rid));
  2328. }
  2329. // $translation_id - int or array
  2330. function cancel_translation_request($translation_id){
  2331. global $wpdb;
  2332. if(is_array($translation_id)){
  2333. foreach($translation_id as $id){
  2334. $this->cancel_translation_request($id);
  2335. }
  2336. }else{
  2337. $rid = $wpdb->get_var($wpdb->prepare("SELECT rid FROM {$wpdb->prefix}icl_translation_status WHERE translation_id=%d", $translation_id));
  2338. $job_id = $wpdb->get_var($wpdb->prepare("SELECT job_id FROM {$wpdb->prefix}icl_translate_job WHERE rid=%d AND revision IS NULL ", $rid));
  2339. $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->prefix}icl_translate_job WHERE job_id=%d", $job_id));
  2340. $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->prefix}icl_translate WHERE job_id=%d", $job_id));
  2341. $max_job_id = $wpdb->get_var($wpdb->prepare("SELECT MAX(job_id) FROM {$wpdb->prefix}icl_translate_job WHERE rid=%d", $rid));
  2342. if($max_job_id){
  2343. $wpdb->query($wpdb->prepare("UPDATE {$wpdb->prefix}icl_translate_job SET revision = NULL WHERE job_id=%d", $max_job_id));
  2344. $_prevstate = $wpdb->get_var($wpdb->prepare("SELECT _prevstate FROM {$wpdb->prefix}icl_translation_status WHERE translation_id = %d", $translation_id));
  2345. if(!empty($_prevstate)){
  2346. $_prevstate = unserialize($_prevstate);
  2347. $wpdb->update($wpdb->prefix . 'icl_translation_status',
  2348. array(
  2349. 'status' => $_prevstate['status'],
  2350. 'translator_id' => $_prevstate['translator_id'],
  2351. 'status' => $_prevstate['status'],
  2352. 'needs_update' => $_prevstate['needs_update'],
  2353. 'md5' => $_prevstate['md5'],
  2354. 'translation_service' => $_prevstate['translation_service'],
  2355. 'translation_package' => $_prevstate['translation_package'],
  2356. 'timestamp' => $_prevstate['timestamp'],
  2357. 'links_fixed' => $_prevstate['links_fixed']
  2358. ),
  2359. array('translation_id'=>$translation_id)
  2360. );
  2361. }
  2362. }else{
  2363. $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->prefix}icl_translation_status WHERE translation_id=%d", $translation_id));
  2364. }
  2365. }
  2366. }
  2367. /* WPML CONFIG */
  2368. /* ******************************************************************************************** */
  2369. function _parse_wpml_config($file){
  2370. global $sitepress, $sitepress_settings;
  2371. $config = icl_xml2array(file_get_contents($file));
  2372. // custom fields
  2373. if(!empty($config['wpml-config']['custom-fields'])){
  2374. if(!is_numeric(key(current($config['wpml-config']['custom-fields'])))){
  2375. $cf[0] = $config['wpml-config']['custom-fields']['custom-field'];
  2376. }else{
  2377. $cf = $config['wpml-config']['custom-fields']['custom-field'];
  2378. }
  2379. foreach($cf as $c){
  2380. if($c['attr']['action'] == 'translate'){
  2381. $action = 2;
  2382. }elseif($c['attr']['action'] == 'copy'){
  2383. $action = 1;
  2384. }else{
  2385. $action = 0;
  2386. }
  2387. $this->settings['custom_fields_translation'][$c['value']] = $action;
  2388. if(is_array($this->settings['custom_fields_readonly_config']) && !in_array($c['value'], $this->settings['custom_fields_readonly_config'])){
  2389. $this->settings['custom_fields_readonly_config'][] = $c['value'];
  2390. }
  2391. }
  2392. }
  2393. // custom types
  2394. $cf = array();
  2395. if(!empty($config['wpml-config']['custom-types'])){
  2396. if(!is_numeric(key(current($config['wpml-config']['custom-types'])))){
  2397. $cf[0] = $config['wpml-config']['custom-types']['custom-type'];
  2398. }else{
  2399. $cf = $config['wpml-config']['custom-types']['custom-type'];
  2400. }
  2401. foreach($cf as $c){
  2402. $translate = intval($c['attr']['translate']);
  2403. if($translate){
  2404. $sitepress->verify_post_translations($c['value']);
  2405. }
  2406. $this->settings['custom_types_readonly_config'][$c['value']] = $translate;
  2407. $sitepress_settings['custom_posts_sync_option'][$c['value']] = $translate;
  2408. }
  2409. add_filter('get_translatable_documents', array($this, '_override_get_translatable_documents'));
  2410. }
  2411. // taxonomies
  2412. $cf = array();
  2413. if(!empty($config['wpml-config']['taxonomies'])){
  2414. if(!is_numeric(key(current($config['wpml-config']['taxonomies'])))){
  2415. $cf[0] = $config['wpml-config']['taxonomies']['taxonomy'];
  2416. }else{
  2417. $cf = $config['wpml-config']['taxonomies']['taxonomy'];
  2418. }
  2419. foreach($cf as $c){
  2420. $translate = intval($c['attr']['translate']);
  2421. $this->settings['taxonomies_readonly_config'][$c['value']] = $translate;
  2422. $sitepress_settings['taxonomies_sync_option'][$c['value']] = $translate;
  2423. }
  2424. add_filter('get_translatable_taxonomies', array($this, '_override_get_translatable_taxonomies'));
  2425. }
  2426. // admin texts
  2427. if(function_exists('icl_register_string')){
  2428. $admin_texts = array();
  2429. if(!empty($config['wpml-config']['admin-texts'])){
  2430. $type = (dirname($file) == get_template_directory() || dirname($file) == get_stylesheet_directory()) ? 'theme' : 'plugin';
  2431. $atid = basename(dirname($file));
  2432. if( !is_numeric(key(@current($config['wpml-config']['admin-texts'])))){
  2433. $admin_texts[0] = $config['wpml-config']['admin-texts']['key'];
  2434. }else{
  2435. $admin_texts = $config['wpml-config']['admin-texts']['key'];
  2436. }
  2437. foreach($admin_texts as $a){
  2438. $keys = array();
  2439. if(!isset($a['key'])){
  2440. $arr[$a['attr']['name']] = 1;
  2441. continue;
  2442. }elseif(!is_numeric(key($a['key']))){
  2443. $keys[0] = $a['key'];
  2444. }else{
  2445. $keys = $a['key'];
  2446. }
  2447. foreach($keys as $key){
  2448. if(isset($key['key'])){
  2449. $arr[$a['attr']['name']][$key['attr']['name']] = $this->_read_admin_texts_recursive($key['key']);
  2450. }else{
  2451. $arr[$a['attr']['name']][$key['attr']['name']] = 1;
  2452. }
  2453. }
  2454. }
  2455. foreach($arr as $key => $v){
  2456. // http://forum.wpml.org/topic.php?id=4888&replies=7#post-23038
  2457. // http://forum.wpml.org/topic.php?id=4615
  2458. // http://forum.wpml.org/topic.php?id=4761
  2459. remove_filter('option_'.$key, 'icl_st_translate_admin_string'); // dont try to translate this one below
  2460. $value = get_option($key);
  2461. add_filter('option_'.$key, 'icl_st_translate_admin_string'); // put the filter back on
  2462. $value = maybe_unserialize($value);
  2463. if(false === $value){
  2464. unset($arr[$key]);
  2465. }if(is_scalar($value)){
  2466. icl_register_string('admin_texts_' . $type . '_' . $atid, $key , $value);
  2467. }else{
  2468. if(is_object($value)) $value = (array)$value;
  2469. if(!empty($value)){
  2470. $this->_register_string_recursive($key, $value, $arr[$key], '', $type . '_' . $atid);
  2471. }
  2472. }
  2473. }
  2474. $this->admin_texts_to_translate = array_merge($this->admin_texts_to_translate, $arr);
  2475. $_icl_admin_option_names = get_option('_icl_admin_option_names');
  2476. //filter out obsolete entries
  2477. /*
  2478. $_as_changed = false;
  2479. foreach($_icl_admin_option_names[$type][$atid] as $k=>$csf){
  2480. if(empty($arr[$csf])){
  2481. unset($_icl_admin_option_names[$type][$atid][$k]);
  2482. }
  2483. }
  2484. */
  2485. $_icl_admin_option_names[$type][$atid] = @array_merge_recursive((array)$_icl_admin_option_names[$type][$atid], $this->_array_keys_recursive($arr));
  2486. $_icl_admin_option_names[$type][$atid] = __array_unique_recursive($_icl_admin_option_names[$type][$atid]);
  2487. // __array_unique_recursive is declared in the string translation plugin inc/functions.php
  2488. update_option('_icl_admin_option_names', $_icl_admin_option_names);
  2489. }
  2490. }
  2491. // language-switcher-settings
  2492. if(empty($sitepress_settings['language_selector_initialized']) || (isset($_GET['restore_ls_settings']) && $_GET['restore_ls_settings'] == 1)){
  2493. if(!empty($config['wpml-config']['language-switcher-settings'])){
  2494. if(!is_numeric(key($config['wpml-config']['language-switcher-settings']['key']))){
  2495. $cfgsettings[0] = $config['wpml-config']['language-switcher-settings']['key'];
  2496. }else{
  2497. $cfgsettings = $config['wpml-config']['language-switcher-settings']['key'];
  2498. }
  2499. $iclsettings = $this->_read_settings_recursive($cfgsettings);
  2500. $iclsettings['language_selector_initialized'] = 1;
  2501. $sitepress->save_settings($iclsettings);
  2502. if(!empty($sitepress_settings['setup_complete']) && !empty($_GET['page'])){
  2503. wp_redirect(admin_url('admin.php?page='.$_GET['page'].'&icl_ls_reset=default#icl_save_language_switcher_options'));
  2504. }
  2505. }
  2506. }
  2507. }
  2508. function _array_keys_recursive($arr){
  2509. $arr_rec_ret = array();
  2510. foreach((array)$arr as $k=>$v){
  2511. if(is_array($v)){
  2512. $arr_rec_ret[$k] = $this->_array_keys_recursive($v);
  2513. }else{
  2514. $arr_rec_ret[] = $k;
  2515. }
  2516. }
  2517. return $arr_rec_ret;
  2518. }
  2519. function _read_admin_texts_recursive($keys){
  2520. if(!is_numeric(key($keys))){
  2521. $_keys = array($keys);
  2522. $keys = $_keys;
  2523. unset($_keys);
  2524. }
  2525. foreach($keys as $key){
  2526. if(isset($key['key'])){
  2527. $arr[$key['attr']['name']] = $this->_read_admin_texts_recursive($key['key']);
  2528. }else{
  2529. $arr[$key['attr']['name']] = 1;
  2530. }
  2531. }
  2532. return $arr;
  2533. }
  2534. function _register_string_recursive($key, $value, $arr, $prefix = '', $suffix){
  2535. if(is_scalar($value)){
  2536. if(!empty($value) && $arr == 1){
  2537. icl_register_string('admin_texts_' . $suffix, $prefix . $key , $value);
  2538. }
  2539. }else{
  2540. if(!is_null($value)){
  2541. foreach($value as $sub_key=>$sub_value){
  2542. if(isset($arr[$sub_key])){
  2543. $this->_register_string_recursive($sub_key, $sub_value, $arr[$sub_key], $prefix . '[' . $key .']', $suffix);
  2544. }
  2545. }
  2546. }
  2547. }
  2548. }
  2549. function _read_settings_recursive($cfgsettings){
  2550. foreach($cfgsettings as $s){
  2551. if(isset($s['key'])){
  2552. if(!is_numeric(key($s['key']))){
  2553. $skey[0] = $s['key'];
  2554. }else{
  2555. $skey = $s['key'];
  2556. }
  2557. $iclsettings[$s['attr']['name']] = $this->_read_settings_recursive($skey);
  2558. }else{
  2559. $iclsettings[$s['attr']['name']] = $s['value'];
  2560. }
  2561. }
  2562. return $iclsettings;
  2563. }
  2564. function render_option_writes($option_name, $option_value, $option_key=''){
  2565. if(!defined('WPML_ST_FOLDER')) return;
  2566. static $option;
  2567. if(!$option_key){
  2568. $option = maybe_unserialize(get_option($option_name));
  2569. if(is_object($option)){
  2570. $option = (array)$option;
  2571. }
  2572. }
  2573. $option_names = get_option('_icl_admin_option_names');
  2574. // determine theme/plugin name (string context)
  2575. if(!empty($option_names['theme'])){
  2576. foreach((array)$option_names['theme'][basename(get_template_directory())] as $ops=>$val){
  2577. if(!empty($option_key)){
  2578. $int = preg_match_all('#\[([^\]]+)\]#', $option_key, $matches);
  2579. if($int) $opname = $matches[1][0];
  2580. }else{
  2581. $opname = $option_name;
  2582. }
  2583. if($ops == $opname){
  2584. $es_context = 'admin_texts_theme_' . basename(get_template_directory());
  2585. break;
  2586. }
  2587. }
  2588. if(get_template_directory() != get_stylesheet_directory()){
  2589. foreach((array)$option_names['theme'][basename(get_stylesheet_directory())] as $ops=>$val){
  2590. if(!empty($option_key)){
  2591. $int = preg_match_all('#\[([^\]]+)\]#', $option_key, $matches);
  2592. if($int) $opname = $matches[1][0];
  2593. }else{
  2594. $opname = $option_name;
  2595. }
  2596. if($ops == $opname){
  2597. $es_context = 'admin_texts_theme_' . get_stylesheet_directory();
  2598. break;
  2599. }
  2600. }
  2601. }
  2602. }
  2603. if(!empty($option_names['plugin'])){
  2604. foreach((array)$option_names['plugin'] as $plugin => $options){
  2605. foreach($options as $ops){
  2606. if($ops == $option_name){
  2607. $es_context = 'admin_texts_plugin_' . $plugin;
  2608. break;
  2609. }
  2610. }
  2611. }
  2612. }
  2613. echo '<ul class="icl_tm_admin_options">';
  2614. echo '<li>';
  2615. if(is_scalar($option_value)){
  2616. $int = preg_match_all('#\[([^\]]+)\]#', $option_key, $matches);
  2617. if(count($matches[1]) > 1){
  2618. $value = $option;
  2619. for($i = 1; $i < count($matches[1]); $i++){
  2620. $value = $value[$matches[1][$i]];
  2621. }
  2622. $value = $value[$option_name];
  2623. $edit_link = '';
  2624. }else{
  2625. if(is_scalar($option)){
  2626. $value = $option;
  2627. }elseif(isset($option[$option_name])){
  2628. $value = $option[$option_name];
  2629. }else{
  2630. $value = '';
  2631. }
  2632. if(!$option_key){
  2633. $edit_link = '[<a href="'.admin_url('admin.php?page='.WPML_ST_FOLDER.'/menu/string-translation.php&context='.$es_context) . '">' .
  2634. __('translate', 'sitepress') . '</a>]';
  2635. }else{
  2636. $edit_link = '';
  2637. }
  2638. }
  2639. echo '<li>' . $option_name . ': <i>' . $value . '</i> ' . $edit_link . '</li>';
  2640. }else{
  2641. $edit_link = '[<a href="'.admin_url('admin.php?page='.WPML_ST_FOLDER.'/menu/string-translation.php&context='.$es_context) . '">' .
  2642. __('translate', 'sitepress') . '</a>]';
  2643. echo '<strong>' . $option_name . '</strong> ' . $edit_link;
  2644. foreach((array)$option_value as $key=>$value){
  2645. $this->render_option_writes($key, $value, $option_key . '[' . $option_name . ']');
  2646. }
  2647. }
  2648. echo '</li>';
  2649. echo '</ul>';
  2650. }
  2651. function _override_get_translatable_documents($types){
  2652. global $wp_post_types;
  2653. foreach($types as $k=>$type){
  2654. if(isset($this->settings['custom_types_readonly_config'][$k]) && !$this->settings['custom_types_readonly_config'][$k]){
  2655. unset($types[$k]);
  2656. }
  2657. }
  2658. foreach($this->settings['custom_types_readonly_config'] as $cp=>$translate){
  2659. if($translate && !isset($types[$cp]) && isset($wp_post_types[$cp])){
  2660. $types[$cp] = $wp_post_types[$cp];
  2661. }
  2662. }
  2663. return $types;
  2664. }
  2665. function _override_get_translatable_taxonomies($taxs_obj_type){
  2666. global $wp_taxonomies, $sitepress;
  2667. $taxs = $taxs_obj_type['taxs'];
  2668. $object_type = $taxs_obj_type['object_type'];
  2669. foreach($taxs as $k=>$tax){
  2670. if(!$sitepress->is_translated_taxonomy($tax)){
  2671. unset($taxs[$k]);
  2672. }
  2673. }
  2674. foreach($this->settings['taxonomies_readonly_config'] as $tx=>$translate){
  2675. if($translate && !in_array($tx, $taxs) && isset($wp_taxonomies[$tx]) && in_array($object_type, $wp_taxonomies[$tx]->object_type)){
  2676. $taxs[] = $tx;
  2677. }
  2678. }
  2679. $ret = array('taxs'=>$taxs, 'object_type'=>$taxs_obj_type['object_type']);
  2680. return $ret;
  2681. }
  2682. function load_plugins_wpml_config(){
  2683. $plugins = get_option('active_plugins');
  2684. foreach($plugins as $p){
  2685. $config_file = ABSPATH . '/' . PLUGINDIR . '/' . dirname($p) . '/wpml-config.xml';
  2686. if(trim(dirname($p),'\/.') && file_exists($config_file)){
  2687. $this->_parse_wpml_config($config_file);
  2688. }
  2689. }
  2690. $mu_plugins = wp_get_mu_plugins();
  2691. if(!empty($mu_plugins)){
  2692. foreach($mu_plugins as $mup){
  2693. if(rtrim(dirname($mup), '/') != WPMU_PLUGIN_DIR){
  2694. $config_file = dirname($mup) . '/wpml-config.xml';
  2695. $this->_parse_wpml_config($config_file);
  2696. }
  2697. }
  2698. }
  2699. }
  2700. function load_theme_wpml_config(){
  2701. if(get_template_directory() != get_stylesheet_directory()){
  2702. $config_file = get_stylesheet_directory().'/wpml-config.xml';
  2703. if(file_exists($config_file)){
  2704. $this->_parse_wpml_config($config_file);
  2705. }
  2706. }
  2707. $config_file = get_template_directory().'/wpml-config.xml';
  2708. if(file_exists($config_file)){
  2709. $this->_parse_wpml_config($config_file);
  2710. }
  2711. }
  2712. function load_config_pre_process(){
  2713. $this->settings['__custom_types_readonly_config_prev'] = (isset($this->settings['custom_types_readonly_config']) && is_array($this->settings['custom_types_readonly_config'])) ? $this->settings['custom_types_readonly_config'] : array();
  2714. $this->settings['custom_types_readonly_config'] = array();
  2715. $this->settings['__custom_fields_readonly_config_prev'] = (isset($this->settings['custom_fields_readonly_config']) && is_array($this->settings['custom_fields_readonly_config'])) ? $this->settings['custom_fields_readonly_config'] : array();
  2716. $this->settings['custom_fields_readonly_config'] = array();
  2717. }
  2718. function load_config_post_process(){
  2719. $changed = false;
  2720. foreach($this->settings['__custom_types_readonly_config_prev'] as $pk=>$pv){
  2721. if(!isset($this->settings['custom_types_readonly_config'][$pk]) || $this->settings['custom_types_readonly_config'][$pk] != $pv){
  2722. $changed = true;
  2723. break;
  2724. }
  2725. }
  2726. foreach($this->settings['custom_types_readonly_config'] as $pk=>$pv){
  2727. if(!isset($this->settings['__custom_types_readonly_config_prev'][$pk]) || $this->settings['__custom_types_readonly_config_prev'][$pk] != $pv){
  2728. $changed = true;
  2729. break;
  2730. }
  2731. }
  2732. foreach($this->settings['__custom_fields_readonly_config_prev'] as $cf){
  2733. if(!in_array($cf, $this->settings['custom_fields_readonly_config'])){
  2734. $changed = true;
  2735. break;
  2736. }
  2737. }
  2738. foreach($this->settings['custom_fields_readonly_config'] as $cf){
  2739. if(!in_array($cf, $this->settings['__custom_fields_readonly_config_prev'])){
  2740. $changed = true;
  2741. break;
  2742. }
  2743. }
  2744. if($changed){
  2745. $this->save_settings();
  2746. }
  2747. }
  2748. public static function icanlocalize_service_info($info = array()) {
  2749. global $sitepress;
  2750. $return = array();
  2751. $return['name'] = 'ICanLocalize';
  2752. $return['logo'] = ICL_PLUGIN_URL . '/res/img/web_logo_small.png';
  2753. $return['setup_url'] = $sitepress->create_icl_popup_link('@select-translators;from_replace;to_replace@', array('ar' => 1), true);
  2754. $return['description'] = __('Looking for a quality translation service? ICanLocalize offers excellent<br /> human service done by expert translators, starts at only $0.09 per word.', 'sitepress');
  2755. $info['icanlocalize'] = $return;
  2756. return $info;
  2757. }
  2758. public function clear_cache() {
  2759. global $wpdb;
  2760. delete_option($wpdb->prefix . 'icl_translators_cached');
  2761. delete_option($wpdb->prefix . 'icl_non_translators_cached');
  2762. }
  2763. // shows post content for visual mode (iframe) in translation editor
  2764. function _show_post_content(){
  2765. global $tinymce_version;
  2766. if($id = @intval($_GET['post_id'])){
  2767. $post = get_post($id);
  2768. if($post){
  2769. if(@intval($_GET['rtl'])){
  2770. $rtl = ' dir="rtl"';
  2771. }else{
  2772. $rtl = '';
  2773. }
  2774. echo '<html'.$rtl.'>';
  2775. echo '<head>';
  2776. $csss = array(
  2777. '/' . WPINC . '/js/tinymce/themes/advanced/skins/wp_theme/content.css?ver='.$tinymce_version,
  2778. '/' . WPINC . '/js/tinymce/plugins/spellchecker/css/content.css?ver='.$tinymce_version,
  2779. '/' . WPINC . '/js/tinymce/plugins/wordpress/css/content.css?ver='.$tinymce_version
  2780. );
  2781. foreach($csss as $css){
  2782. echo '<link rel="stylesheet" href="'.get_option('siteurl') . $css . '">' . "\n";
  2783. }
  2784. echo '</head>';
  2785. echo '<body>';
  2786. switch($_GET['field_type']){
  2787. default:
  2788. if(0 === strpos($_GET['field_type'], 'field-')){
  2789. echo get_post_meta($id, preg_replace('#^field-#', '', $_GET['field_type']), true);
  2790. }else{
  2791. remove_filter('the_content', 'do_shortcode', 11);
  2792. echo apply_filters('the_content', $post->post_content);
  2793. }
  2794. }
  2795. echo '</body>';
  2796. echo '</html>';
  2797. exit;
  2798. }else{
  2799. wp_die(__('Post not found!', 'sitepress'));
  2800. }
  2801. exit;
  2802. }else{
  2803. wp_die(__('Post not found!', 'sitepress'));
  2804. }
  2805. }
  2806. function _user_search(){
  2807. $q = $_POST['q'];
  2808. $non_translators = $this->get_blog_not_translators();
  2809. $matched_users = array();
  2810. foreach($non_translators as $t){
  2811. if(false !== stripos($t->user_login, $q) || false !== stripos($t->display_name, $q)){
  2812. $matched_users[] = $t;
  2813. }
  2814. if(count($matched_users) == 100) break;
  2815. }
  2816. if(!empty($matched_users)){
  2817. $cssheight = count($matched_users) > 10 ? '200' : 20*count($matched_users) + 5;
  2818. echo '<select size="10" class="icl_tm_auto_suggest_dd" style="height:'.$cssheight.'px">';
  2819. foreach($matched_users as $u){
  2820. echo '<option value="' . $u->ID . '|' . esc_attr($u->display_name).'">'.$u->display_name . ' ('.$u->user_login.')'.'</option>';
  2821. }
  2822. echo '</select>';
  2823. }else{
  2824. echo '&nbsp;<span id="icl_user_src_nf">';
  2825. _e('No matches', 'sitepress');
  2826. echo '</span>';
  2827. }
  2828. exit;
  2829. }
  2830. function make_duplicates($data){
  2831. foreach($data['iclpost'] as $master_post_id){
  2832. foreach($data['duplicate_to'] as $lang => $one){
  2833. $this->make_duplicate($master_post_id, $lang);
  2834. }
  2835. }
  2836. }
  2837. function make_duplicate($master_post_id, $lang){
  2838. global $sitepress, $wpdb;
  2839. $master_post = get_post($master_post_id);
  2840. $trid = $sitepress->get_element_trid($master_post_id, 'post_' . $master_post->post_type);
  2841. if($trid){
  2842. $translations = $sitepress->get_element_translations($trid, 'post_' . $master_post->post_type);
  2843. if(isset($translations[$lang])){
  2844. $postarr['ID'] = $translations[$lang]->element_id;
  2845. }
  2846. }
  2847. $postarr['post_author'] = $master_post->post_author;
  2848. $postarr['post_date'] = $master_post->post_date;
  2849. $postarr['post_date_gmt'] = $master_post->post_date_gmt;
  2850. $postarr['post_content'] = $master_post->post_content;
  2851. $postarr['post_title'] = $master_post->post_title;
  2852. $postarr['post_excerpt'] = $master_post->post_excerpt;
  2853. $postarr['post_status'] = $master_post->post_status;
  2854. $postarr['comment_status'] = $master_post->comment_status;
  2855. $postarr['ping_status'] = $master_post->ping_status;
  2856. $postarr['post_name'] = $master_post->post_name;
  2857. if($master_post->post_parent){
  2858. $parent = icl_object_id($master_post->post_parent, $master_post->post_type, false, $lang);
  2859. $postarr['post_parent'] = $parent;
  2860. }
  2861. $postarr['menu_order'] = $master_post->menu_order;
  2862. $postarr['post_type'] = $master_post->post_type;
  2863. $postarr['post_mime_type'] = $master_post->post_mime_type;
  2864. $trid = $sitepress->get_element_trid($master_post->ID, 'post_' . $master_post->post_type);
  2865. $_POST['icl_trid'] = $trid;
  2866. $_POST['icl_post_language'] = $lang;
  2867. $_POST['skip_sitepress_actions'] = true;
  2868. if(isset($postarr['ID'])){
  2869. $id = wp_update_post($postarr);
  2870. }else{
  2871. $id = wp_insert_post($postarr);
  2872. }
  2873. if(!is_wp_error($id)){
  2874. $sitepress->set_element_language_details($id, 'post_' . $master_post->post_type, $trid, $lang);
  2875. $this->save_post_actions($id, get_post($id), $force_set_status = ICL_TM_DUPLICATE);
  2876. // dup comments
  2877. if($sitepress->get_option('sync_comments_on_duplicates')){
  2878. $this->duplicate_comments($id, $master_post->ID);
  2879. }
  2880. // make sure post name is copied
  2881. $wpdb->update($wpdb->posts, array('post_name'=>$master_post->post_name), array('ID'=>$id));
  2882. update_post_meta($id, '_icl_lang_duplicate_of', $master_post->ID);
  2883. // copy custom fields
  2884. $custom_fields = get_post_custom($master_post_id);
  2885. foreach($custom_fields as $key => $values){
  2886. // skip some
  2887. if(in_array($key, array('_wp_old_slug', '_edit_last', '_edit_lock', '_icl_translator_note'))) continue;
  2888. delete_post_meta($id, $key);
  2889. foreach($values as $value){
  2890. add_post_meta($id, $key, $value);
  2891. }
  2892. }
  2893. // sync taxonomies
  2894. $taxonomies = array_values(get_taxonomies());
  2895. //exclude_some
  2896. $taxonomies = array_diff($taxonomies, array('nav_menu', 'link_category'));
  2897. foreach($taxonomies as $taxonomy){
  2898. $is_translated = $sitepress->is_translated_taxonomy($taxonomy);
  2899. $terms = wp_get_post_terms($master_post_id, $taxonomy);
  2900. if(!empty($terms)){
  2901. $terms_array = array();
  2902. foreach($terms as $t){
  2903. if($is_translated){
  2904. $tr_id = icl_object_id($t->term_id, $taxonomy, false, $lang);
  2905. if($tr_id){
  2906. if(is_taxonomy_hierarchical($taxonomy)){
  2907. $terms_array[] = $tr_id;
  2908. }else{
  2909. $tr_term = get_term($tr_id, $taxonomy);
  2910. $terms_array[] = $tr_term->name;
  2911. }
  2912. }
  2913. }else{
  2914. if(is_taxonomy_hierarchical($taxonomy)){
  2915. $terms_array[] = $t->term_id;
  2916. }else{
  2917. $terms_array[] = $t->name;
  2918. }
  2919. }
  2920. }
  2921. wp_set_post_terms($id, $terms_array, $taxonomy);
  2922. }
  2923. }
  2924. $ret = $id;
  2925. do_action('icl_make_duplicate', $master_post_id, $lang, $postarr, $id);
  2926. }else{
  2927. $ret = false;
  2928. }
  2929. return $ret;
  2930. }
  2931. function make_duplicates_all($master_post_id){
  2932. global $sitepress;
  2933. $master_post = get_post($master_post_id);
  2934. $language_details_original = $sitepress->get_element_language_details($master_post_id, 'post_' . $master_post->post_type);
  2935. $data['iclpost'] = array($master_post_id);
  2936. foreach($sitepress->get_active_languages() as $lang => $details){
  2937. if($lang != $language_details_original->language_code){
  2938. $data['duplicate_to'][$lang] = 1;
  2939. }
  2940. }
  2941. $this->make_duplicates($data);
  2942. }
  2943. function reset_duplicate_flag($post_id){
  2944. global $sitepress;
  2945. $post = get_post($post_id);
  2946. $trid = $sitepress->get_element_trid($post_id, 'post_' . $post->post_type);
  2947. $translations = $sitepress->get_element_translations($trid, 'post_' . $post->post_type);
  2948. foreach($translations as $tr){
  2949. if($tr->element_id == $post_id){
  2950. $this->update_translation_status(array(
  2951. 'translation_id' => $tr->translation_id,
  2952. 'status' => ICL_TM_COMPLETE
  2953. ));
  2954. }
  2955. }
  2956. delete_post_meta($post_id, '_icl_lang_duplicate_of');
  2957. }
  2958. function set_duplicate($post_id){
  2959. global $sitepress;
  2960. // find original (source) and copy
  2961. $post = get_post($post_id);
  2962. $trid = $sitepress->get_element_trid($post_id, 'post_' . $post->post_type);
  2963. $translations = $sitepress->get_element_translations($trid, 'post_' . $post->post_type);
  2964. foreach($translations as $lang => $tr){
  2965. if($tr->original){
  2966. $master_post_id = $tr->element_id;
  2967. }elseif($tr->element_id == $post_id){
  2968. $this_language = $lang;
  2969. }
  2970. }
  2971. $this->make_duplicate($master_post_id, $this_language);
  2972. }
  2973. function get_duplicates($master_post_id){
  2974. global $wpdb, $sitepress;
  2975. $duplicates = array();
  2976. $res = $wpdb->get_col($wpdb->prepare("SELECT post_id FROM {$wpdb->postmeta}
  2977. WHERE meta_key='_icl_lang_duplicate_of' AND meta_value=%d", $master_post_id));
  2978. foreach($res as $post_id){
  2979. $post = get_post($post_id);
  2980. $language_details = $sitepress->get_element_language_details($post_id, 'post_' . $post->post_type);
  2981. $duplicates[$language_details->language_code] = $post_id;
  2982. }
  2983. return $duplicates;
  2984. }
  2985. function duplicate_comments($post_id, $master_post_id){
  2986. global $wpdb, $sitepress;
  2987. // delete existing comments
  2988. $current_comments = $wpdb->get_results($wpdb->prepare("SELECT comment_ID FROM {$wpdb->comments} WHERE comment_post_ID = %d", $post_id));
  2989. foreach($current_comments as $id){
  2990. wp_delete_comment($id);
  2991. }
  2992. $original_comments = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->comments} WHERE comment_post_id = %d", $master_post_id), ARRAY_A);
  2993. $post_type = $wpdb->get_var($wpdb->prepare("SELECT post_type FROM {$wpdb->posts} WHERE ID=%d", $post_id));
  2994. $language = $wpdb->get_var($wpdb->prepare("SELECT language_code FROM {$wpdb->prefix}icl_translations WHERE element_id=%d AND element_type=%s", $post_id, 'post_' . $post_type));
  2995. $wpdb->update($wpdb->posts, array('post_count'=>count($original_comments)), array('ID'=>$post_id));
  2996. foreach($original_comments as $comment){
  2997. $original_comment_id = $comment['comment_ID'];
  2998. unset($comment['comment_ID']);
  2999. $comment['comment_post_ID'] = $post_id;
  3000. $wpdb->insert($wpdb->comments, $comment);
  3001. $comment_id = $wpdb->insert_id;
  3002. update_comment_meta($comment_id, '_icl_duplicate_of', $original_comment_id);
  3003. // comment meta
  3004. $meta = $wpdb->get_results($wpdb->prepare("SELECT meta_key, meta_value FROM {$wpdb->commentmeta} WHERE comment_id=%d", $original_comment_id));
  3005. foreach($meta as $key => $val){
  3006. $wpdb->insert($wpdb->commentmeta, array(
  3007. 'comment_id' => $comment_id,
  3008. 'meta_key' => $key,
  3009. 'meta_value' => $val
  3010. ));
  3011. }
  3012. $original_comment_tr = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}icl_translations WHERE element_id=%d AND element_type=%s",
  3013. $original_comment_id, 'comment'));
  3014. $comment_translation = array(
  3015. 'element_type' => 'comment',
  3016. 'element_id' => $comment_id,
  3017. 'trid' => $original_comment_tr->trid,
  3018. 'language_code' => $language,
  3019. /*'source_language_code' => $original_comment_tr->language_code */
  3020. );
  3021. $comments_map[$original_comment_id] = array('trid' => $original_comment_tr->trid, 'comment' => $comment_id);
  3022. $wpdb->insert($wpdb->prefix . 'icl_translations', $comment_translation);
  3023. }
  3024. // sync parents
  3025. foreach($original_comments as $comment){
  3026. if($comment['comment_parent']){
  3027. $tr_comment_id = $comments_map[$comment['comment_ID']]['comment'];
  3028. $tr_parent = icl_object_id($comment['comment_parent'], 'comment', false, $language);
  3029. if($tr_parent){
  3030. $wpdb->update($wpdb->comments, array('comment_parent' => $tr_parent), array('comment_ID' => $tr_comment_id));
  3031. }
  3032. }
  3033. }
  3034. }
  3035. function duplication_delete_comment($comment_id){
  3036. global $wpdb;
  3037. static $_avoid_8_loop;
  3038. if(isset($_avoid_8_loop)) return;
  3039. $_avoid_8_loop = true;
  3040. $original_comment = get_comment_meta($comment_id, '_icl_duplicate_of', true);
  3041. if($original_comment){
  3042. $duplicates = $wpdb->get_col($wpdb->prepare("SELECT comment_id FROM {$wpdb->commentmeta} WHERE meta_key='_icl_duplicate_of' AND meta_value=%d", $original_comment));
  3043. $duplicates = array($original_comment) + array_diff($duplicates, array($comment_id));
  3044. foreach($duplicates as $dup){
  3045. wp_delete_comment($dup);
  3046. }
  3047. }else{
  3048. $duplicates = $wpdb->get_col($wpdb->prepare("SELECT comment_id FROM {$wpdb->commentmeta} WHERE meta_key='_icl_duplicate_of' AND meta_value=%d", $comment_id));
  3049. if($duplicates){
  3050. foreach($duplicates as $dup){
  3051. wp_delete_comment($dup);
  3052. }
  3053. }
  3054. }
  3055. unset($_avoid_8_loop);
  3056. }
  3057. function duplication_edit_comment($comment_id){
  3058. global $wpdb;
  3059. $comment = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->comments} WHERE comment_ID=%d", $comment_id), ARRAY_A);
  3060. unset($comment['comment_ID'], $comment['comment_post_ID']);
  3061. $comment_meta = $wpdb->get_results($wpdb->prepare("SELECT meta_key, meta_value FROM {$wpdb->commentmeta} WHERE comment_id=%d AND meta_key <> '_icl_duplicate_of'", $comment_id));
  3062. $original_comment = get_comment_meta($comment_id, '_icl_duplicate_of', true);
  3063. if($original_comment){
  3064. $duplicates = $wpdb->get_col($wpdb->prepare("SELECT comment_id FROM {$wpdb->commentmeta} WHERE meta_key='_icl_duplicate_of' AND meta_value=%d", $original_comment));
  3065. $duplicates = array($original_comment) + array_diff($duplicates, array($comment_id));
  3066. }else{
  3067. $duplicates = $wpdb->get_col($wpdb->prepare("SELECT comment_id FROM {$wpdb->commentmeta} WHERE meta_key='_icl_duplicate_of' AND meta_value=%d", $comment_id));
  3068. }
  3069. if(!empty($duplicates)){
  3070. foreach($duplicates as $dup){
  3071. $wpdb->update($wpdb->comments, $comment, array('comment_ID' => $dup));
  3072. $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->commentmeta} WHERE comment_id=%d AND meta_key <> '_icl_duplicate_of'", $dup));
  3073. if($comment_meta){
  3074. foreach($comment_meta as $key => $value){
  3075. update_comment_meta($dup, $meta_key, $meta_value);
  3076. }
  3077. }
  3078. }
  3079. }
  3080. }
  3081. function duplication_status_comment($comment_id, $comment_status){
  3082. global $wpdb;
  3083. static $_avoid_8_loop;
  3084. if(isset($_avoid_8_loop)) return;
  3085. $_avoid_8_loop = true;
  3086. $original_comment = get_comment_meta($comment_id, '_icl_duplicate_of', true);
  3087. if($original_comment){
  3088. $duplicates = $wpdb->get_col($wpdb->prepare("SELECT comment_id FROM {$wpdb->commentmeta} WHERE meta_key='_icl_duplicate_of' AND meta_value=%d", $original_comment));
  3089. $duplicates = array($original_comment) + array_diff($duplicates, array($comment_id));
  3090. }else{
  3091. $duplicates = $wpdb->get_col($wpdb->prepare("SELECT comment_id FROM {$wpdb->commentmeta} WHERE meta_key='_icl_duplicate_of' AND meta_value=%d", $comment_id));
  3092. }
  3093. if(!empty($duplicates)){
  3094. foreach($duplicates as $dup){
  3095. wp_set_comment_status($t->element_id, $status);
  3096. }
  3097. }
  3098. unset($_avoid_8_loop);
  3099. }
  3100. function duplication_insert_comment($comment_id){
  3101. global $wpdb, $sitepress;
  3102. $comment = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->comments} WHERE comment_ID=%d", $comment_id), ARRAY_A);
  3103. // loop duplicate posts, add new comment
  3104. $post_id = $comment['comment_post_ID'];
  3105. // if this is a duplicate post
  3106. $duplicate_of = get_post_meta($post_id, '_icl_lang_duplicate_of', true);
  3107. if($duplicate_of){
  3108. $post_duplicates = $this->get_duplicates($duplicate_of);
  3109. $_lang = $wpdb->get_var($wpdb->prepare("SELECT language_code FROM {$wpdb->prefix}icl_translations WHERE element_type='comment' AND element_id=%d", $comment_id));
  3110. unset($post_duplicates[$_lang]);
  3111. $_post = get_post($duplicate_of);
  3112. $_orig_lang = $sitepress->get_language_for_element($duplicate_of, 'post_' . $_post->post_type);
  3113. $post_duplicates[$_orig_lang] = $duplicate_of;
  3114. }else{
  3115. $post_duplicates = $this->get_duplicates($post_id);
  3116. }
  3117. unset($comment['comment_ID'], $comment['comment_post_ID']);
  3118. foreach($post_duplicates as $lang => $dup_id){
  3119. $comment['comment_post_ID'] = $dup_id;
  3120. if($comment['comment_parent']){
  3121. $comment['comment_parent'] = icl_object_id($comment['comment_parent'], 'comment', false, $lang);
  3122. }
  3123. $wpdb->insert($wpdb->comments, $comment);
  3124. $dup_comment_id = $wpdb->insert_id;
  3125. update_comment_meta($dup_comment_id, '_icl_duplicate_of', $comment_id);
  3126. // comment meta
  3127. $meta = $wpdb->get_results($wpdb->prepare("SELECT meta_key, meta_value FROM {$wpdb->commentmeta} WHERE comment_id=%d", $comment_id));
  3128. foreach($meta as $key => $val){
  3129. $wpdb->insert($wpdb->commentmeta, array(
  3130. 'comment_id' => $dup_comment_id,
  3131. 'meta_key' => $key,
  3132. 'meta_value' => $val
  3133. ));
  3134. }
  3135. $original_comment_tr = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}icl_translations WHERE element_id=%d AND element_type=%s",
  3136. $comment_id, 'comment'));
  3137. $comment_translation = array(
  3138. 'element_type' => 'comment',
  3139. 'element_id' => $dup_comment_id,
  3140. 'trid' => $original_comment_tr->trid,
  3141. 'language_code' => $lang,
  3142. /*'source_language_code' => $original_comment_tr->language_code */
  3143. );
  3144. $wpdb->insert($wpdb->prefix . 'icl_translations', $comment_translation);
  3145. }
  3146. }
  3147. // set slug according to user preference
  3148. static function set_page_url($post_id){
  3149. global $sitepress, $sitepress_settings, $wpdb;
  3150. if($sitepress_settings['translated_document_page_url'] == 'copy-encoded'){
  3151. $post = $wpdb->get_row($wpdb->prepare("SELECT post_type FROM {$wpdb->posts} WHERE ID=%d", $post_id));
  3152. $translation_row = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->prefix}icl_translations WHERE element_id=%d AND element_type=%s", $post_id, 'post_' . $post->post_type));
  3153. $encode_url = $wpdb->get_var($wpdb->prepare("SELECT encode_url FROM {$wpdb->prefix}icl_languages WHERE code=%s", $translation_row->language_code));
  3154. if($encode_url){
  3155. $trid = $sitepress->get_element_trid($post_id, 'post_' . $post->post_type);
  3156. $original_post_id = $wpdb->get_var($wpdb->prepare("SELECT element_id FROM {$wpdb->prefix}icl_translations WHERE trid=%d AND source_language_code IS NULL", $trid));
  3157. $post_name_original = $wpdb->get_var($wpdb->prepare("SELECT post_name FROM {$wpdb->posts} WHERE ID = %d", $original_post_id));
  3158. $post_name_to_be = $post_name_original;
  3159. $taken = true;
  3160. $incr = 1;
  3161. do{
  3162. $taken = $wpdb->get_var($wpdb->prepare("
  3163. SELECT ID FROM {$wpdb->posts} p
  3164. JOIN {$wpdb->prefix}icl_translations t ON p.ID = t.element_id
  3165. WHERE ID <> %d AND t.element_type = %s AND t.language_code = %s AND p.post_name = %s
  3166. ", $post_id, 'post_' . $post->post_type, $translation_row->language_code, $post_name_to_be ));
  3167. if($taken){
  3168. $incr++;
  3169. $post_name_to_be = $post_name_original . '-' . $incr;
  3170. }else{
  3171. $taken = false;
  3172. }
  3173. }while($taken == true);
  3174. $wpdb->update($wpdb->posts, array('post_name' => $post_name_to_be), array('ID' => $post_id));
  3175. }
  3176. }
  3177. }
  3178. }
  3179. ?>