PageRenderTime 62ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

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

https://bitbucket.org/acipriani/madeinapulia.com
PHP | 4216 lines | 3263 code | 643 blank | 310 comment | 770 complexity | d801fb1245a37a064a7a36afd3c95f6a MD5 | raw file
Possible License(s): GPL-3.0, MIT, BSD-3-Clause, LGPL-2.1, GPL-2.0, Apache-2.0

Large files files are truncated, but you can click here to view the full file

  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. if(!class_exists('WPML_Config')) {
  17. require ICL_PLUGIN_PATH . '/inc/wpml-config/wpml-config.class.php';
  18. }
  19. class TranslationManagement{
  20. private $selected_translator = array('ID'=>0);
  21. private $current_translator = array('ID'=>0);
  22. public $messages = array();
  23. public $dashboard_select = array();
  24. public $settings;
  25. public $admin_texts_to_translate = array();
  26. function __construct(){
  27. add_action('init', array($this, 'init'), 1500);
  28. if(isset($_GET['icl_tm_message'])){
  29. $this->messages[] = array(
  30. 'type' => isset($_GET['icl_tm_message_type']) ? $_GET['icl_tm_message_type'] : 'updated',
  31. 'text' => $_GET['icl_tm_message']
  32. );
  33. }
  34. add_action('save_post', array($this, 'save_post_actions'), 110, 2); // calling *after* the Sitepress actions
  35. add_action('delete_post', array($this, 'delete_post_actions'), 1, 1); // calling *before* the Sitepress actions
  36. //add_action('edit_term', array($this, 'edit_term'),11, 2); // calling *after* the Sitepress actions
  37. add_action('icl_ajx_custom_call', array($this, 'ajax_calls'), 10, 2);
  38. add_action('wp_ajax_show_post_content', array($this, '_show_post_content'));
  39. if(isset($_GET['sm']) && ($_GET['sm'] == 'dashboard' || $_GET['sm'] == 'jobs')){@session_start();}
  40. elseif(isset($_GET['page']) && preg_match('@/menu/translations-queue\.php$@', $_GET['page'])){@session_start();}
  41. add_filter('icl_additional_translators', array($this, 'icl_additional_translators'), 99, 3);
  42. add_filter('icl_translators_list', array(__CLASS__, 'icanlocalize_translators_list'));
  43. add_action('user_register', array($this, 'clear_cache'));
  44. add_action('profile_update', array($this, 'clear_cache'));
  45. add_action('delete_user', array($this, 'clear_cache'));
  46. add_action('added_existing_user', array($this, 'clear_cache'));
  47. add_action('remove_user_from_blog', array($this, 'clear_cache'));
  48. add_action('admin_print_scripts', array($this, '_inline_js_scripts'));
  49. add_action('wp_ajax_icl_tm_user_search', array($this, '_user_search'));
  50. add_action('wp_ajax_icl_tm_abort_translation', array($this, 'abort_translation'));
  51. }
  52. function save_settings()
  53. {
  54. global $sitepress, $sitepress_settings;
  55. $iclsettings[ 'translation-management' ] = $this->settings;
  56. $custom_posts_sync_option = isset( $sitepress_settings[ 'custom_posts_sync_option' ] ) ? $sitepress_settings[ 'custom_posts_sync_option' ] : false;
  57. if ( is_array( $custom_posts_sync_option ) ) {
  58. foreach ( $custom_posts_sync_option as $k => $v ) {
  59. $iclsettings[ 'custom_posts_sync_option' ][ $k ] = $v;
  60. }
  61. }
  62. $sitepress->save_settings( $iclsettings );
  63. }
  64. function init(){
  65. global $wpdb, $current_user, $sitepress_settings, $sitepress;
  66. $this->settings =& $sitepress_settings['translation-management'];
  67. //logic for syncing comments
  68. if($sitepress->get_option('sync_comments_on_duplicates')){
  69. add_action('delete_comment', array($this, 'duplication_delete_comment'));
  70. add_action('edit_comment', array($this, 'duplication_edit_comment'));
  71. add_action('wp_set_comment_status', array($this, 'duplication_status_comment'), 10, 2);
  72. add_action('wp_insert_comment', array($this, 'duplication_insert_comment'), 100);
  73. }
  74. $this->initial_custom_field_translate_states();
  75. // defaults
  76. if(!isset($this->settings['notification']['new-job'])) $this->settings['notification']['new-job'] = ICL_TM_NOTIFICATION_IMMEDIATELY;
  77. if(!isset($this->settings['notification']['completed'])) $this->settings['notification']['completed'] = ICL_TM_NOTIFICATION_IMMEDIATELY;
  78. if(!isset($this->settings['notification']['resigned'])) $this->settings['notification']['resigned'] = ICL_TM_NOTIFICATION_IMMEDIATELY;
  79. if(!isset($this->settings['notification']['dashboard'])) $this->settings['notification']['dashboard'] = true;
  80. if(!isset($this->settings['notification']['purge-old'])) $this->settings['notification']['purge-old'] = 7;
  81. if(!isset($this->settings['custom_fields_translation'])) $this->settings['custom_fields_translation'] = array();
  82. if(!isset($this->settings['doc_translation_method'])) $this->settings['doc_translation_method'] = ICL_TM_TMETHOD_MANUAL;
  83. get_currentuserinfo();
  84. $user = false;
  85. if(isset($current_user->ID)){
  86. $user = new WP_User($current_user->ID);
  87. }
  88. if(!$user || empty($user->data)) return;
  89. $ct['translator_id'] = $current_user->ID;
  90. $ct['display_name'] = isset($user->data->display_name) ? $user->data->display_name : $user->data->user_login;
  91. $ct['user_login'] = $user->data->user_login;
  92. $ct['language_pairs'] = get_user_meta($current_user->ID, $wpdb->prefix.'language_pairs', true);
  93. if(empty($ct['language_pairs'])) $ct['language_pairs'] = array();
  94. $this->current_translator = (object)$ct;
  95. WPML_Config::load_config();
  96. if(isset($_POST['icl_tm_action'])){
  97. $this->process_request($_POST['icl_tm_action'], $_POST);
  98. }elseif(isset($_GET['icl_tm_action'])){
  99. $this->process_request($_GET['icl_tm_action'], $_GET);
  100. }
  101. if($GLOBALS['pagenow']=='edit.php'){ // use standard WP admin notices
  102. add_action('admin_notices', array($this, 'show_messages'));
  103. }else{ // use custom WP admin notices
  104. add_action('icl_tm_messages', array($this, 'show_messages'));
  105. }
  106. if(isset($_GET['page']) && basename($_GET['page']) == 'translations-queue.php' && isset($_GET['job_id'])){
  107. add_filter('admin_head',array($this, '_show_tinyMCE'));
  108. }
  109. //if(!isset($this->settings['doc_translation_method'])){
  110. if(isset($this->settings['doc_translation_method']) && $this->settings['doc_translation_method'] < 0 ){
  111. if(isset($_GET['sm']) && $_GET['sm']=='mcsetup' && isset($_GET['src']) && $_GET['src']=='notice'){
  112. $this->settings['doc_translation_method'] = ICL_TM_TMETHOD_MANUAL;
  113. $this->save_settings();
  114. }else{
  115. add_action('admin_notices', array($this, '_translation_method_notice'));
  116. }
  117. }
  118. if(defined('WPML_TM_VERSION') && isset($_GET['page']) && $_GET['page'] == WPML_TM_FOLDER. '/menu/main.php' && isset($_GET['sm']) && $_GET['sm'] == 'translators'){
  119. $iclsettings =& $sitepress_settings;
  120. $sitepress->get_icl_translator_status($iclsettings);
  121. $sitepress->save_settings($iclsettings);
  122. }
  123. // default settings
  124. if(empty($this->settings['doc_translation_method']) || !defined('WPML_TM_VERSION')){
  125. $this->settings['doc_translation_method'] = ICL_TM_TMETHOD_MANUAL;
  126. }
  127. }
  128. function initial_custom_field_translate_states() {
  129. global $wpdb;
  130. $cf_keys_limit = 1000; // jic
  131. $custom_keys = $wpdb->get_col( "
  132. SELECT meta_key
  133. FROM $wpdb->postmeta
  134. GROUP BY meta_key
  135. ORDER BY meta_key
  136. LIMIT $cf_keys_limit" );
  137. $changed = false;
  138. foreach($custom_keys as $cfield) {
  139. if(empty($this->settings['custom_fields_translation'][$cfield]) || $this->settings['custom_fields_translation'][$cfield] == 0) {
  140. // see if a plugin handles this field
  141. $override = apply_filters('icl_cf_translate_state', 'nothing', $cfield);
  142. switch($override) {
  143. case 'nothing':
  144. break;
  145. case 'ignore':
  146. $changed = true;
  147. $this->settings['custom_fields_translation'][$cfield] = 3;
  148. break;
  149. case 'translate':
  150. $changed = true;
  151. $this->settings['custom_fields_translation'][$cfield] = 2;
  152. break;
  153. case 'copy':
  154. $changed = true;
  155. $this->settings['custom_fields_translation'][$cfield] = 1;
  156. break;
  157. }
  158. }
  159. }
  160. if ($changed) {
  161. $this->save_settings();
  162. }
  163. }
  164. function _translation_method_notice(){
  165. 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'),
  166. admin_url('admin.php?page='.WPML_TM_FOLDER.'/menu/main.php&sm=mcsetup&src=notice')) . '</p></div>';
  167. }
  168. function _show_tinyMCE() {
  169. wp_print_scripts('editor');
  170. //add_filter('the_editor', array($this, 'editor_directionality'), 9999);
  171. add_filter('tiny_mce_before_init', array($this, '_mce_set_direction'), 9999);
  172. add_filter('mce_buttons', array($this, '_mce_remove_fullscreen'), 9999);
  173. if (version_compare($GLOBALS['wp_version'], '3.1.4', '<=') && function_exists('wp_tiny_mce'))
  174. try{
  175. /** @noinspection PhpDeprecationInspection */
  176. @wp_tiny_mce();
  177. } catch(Exception $e) { /*don't do anything with this */ }
  178. }
  179. function _mce_remove_fullscreen($options){
  180. foreach($options as $k=>$v) if($v == 'fullscreen') unset($options[$k]);
  181. return $options;
  182. }
  183. function _inline_js_scripts(){
  184. // remove fullscreen mode
  185. if(defined('WPML_TM_FOLDER') && isset($_GET['page']) && $_GET['page'] == WPML_TM_FOLDER . '/menu/translations-queue.php' && isset($_GET['job_id'])){
  186. ?>
  187. <script type="text/javascript">addLoadEvent(function(){jQuery('#ed_fullscreen').remove();});</script>
  188. <?php
  189. }
  190. }
  191. function _mce_set_direction($settings) {
  192. $job = $this->get_translation_job((int)$_GET['job_id'], false, true);
  193. if (!empty($job)) {
  194. $rtl_translation = in_array($job->language_code, array('ar','he','fa'));
  195. if ($rtl_translation) {
  196. $settings['directionality'] = 'rtl';
  197. } else {
  198. $settings['directionality'] = 'ltr';
  199. }
  200. }
  201. return $settings;
  202. }
  203. /*
  204. function editor_directionality($tag) {
  205. $job = $this->get_translation_job((int)$_GET['job_id'], false, true);
  206. $rtl_translation = in_array($job->language_code, array('ar','he','fa'));
  207. if ($rtl_translation) {
  208. $dir = 'dir="rtl"';
  209. } else {
  210. $dir = 'dir="ltr"';
  211. }
  212. return str_replace('<textarea', '<textarea ' . $dir, $tag);
  213. }
  214. */
  215. function process_request($action, $data){
  216. $data = stripslashes_deep($data);
  217. switch($action){
  218. case 'add_translator':
  219. if(wp_create_nonce('add_translator') == $data['add_translator_nonce']){
  220. // Initial adding
  221. if (isset($data['from_lang']) && isset($data['to_lang'])) {
  222. $data['lang_pairs'] = array();
  223. $data['lang_pairs'][$data['from_lang']] = array($data['to_lang'] => 1);
  224. }
  225. $this->add_translator($data['user_id'], $data['lang_pairs']);
  226. $_user = new WP_User($data['user_id']);
  227. 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');
  228. }
  229. break;
  230. case 'edit_translator':
  231. if(wp_create_nonce('edit_translator') == $data['edit_translator_nonce']){
  232. $this->edit_translator($data['user_id'], isset($data['lang_pairs']) ? $data['lang_pairs'] : array());
  233. $_user = new WP_User($data['user_id']);
  234. 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');
  235. }
  236. break;
  237. case 'remove_translator':
  238. if(wp_create_nonce('remove_translator') == $data['remove_translator_nonce']){
  239. $this->remove_translator($data['user_id']);
  240. $_user = new WP_User($data['user_id']);
  241. 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');
  242. }
  243. break;
  244. case 'edit':
  245. $this->selected_translator['ID'] = intval($data['user_id']);
  246. break;
  247. case 'dashboard_filter':
  248. $_SESSION['translation_dashboard_filter'] = $data['filter'];
  249. wp_redirect('admin.php?page='.WPML_TM_FOLDER . '/menu/main.php&sm=dashboard');
  250. break;
  251. case 'sort':
  252. if(isset($data['sort_by'])) $_SESSION['translation_dashboard_filter']['sort_by'] = $data['sort_by'];
  253. if(isset($data['sort_order'])) $_SESSION['translation_dashboard_filter']['sort_order'] = $data['sort_order'];
  254. break;
  255. case 'reset_filters':
  256. unset($_SESSION['translation_dashboard_filter']);
  257. break;
  258. case 'send_jobs':
  259. if(isset($data['iclnonce']) && wp_verify_nonce($data['iclnonce'], 'pro-translation-icl')){
  260. $this->send_jobs($data);
  261. }
  262. break;
  263. case 'jobs_filter':
  264. $_SESSION['translation_jobs_filter'] = $data['filter'];
  265. wp_redirect('admin.php?page='.WPML_TM_FOLDER . '/menu/main.php&sm=jobs');
  266. break;
  267. case 'ujobs_filter':
  268. $_SESSION['translation_ujobs_filter'] = $data['filter'];
  269. wp_redirect('admin.php?page='.WPML_TM_FOLDER . '/menu/translations-queue.php');
  270. break;
  271. case 'save_translation':
  272. if(!empty($data['resign'])){
  273. $this->resign_translator($data['job_id']);
  274. wp_redirect(admin_url('admin.php?page='.WPML_TM_FOLDER.'/menu/translations-queue.php&resigned='.$data['job_id']));
  275. exit;
  276. }else{
  277. $this->save_translation($data);
  278. }
  279. break;
  280. case 'save_notification_settings':
  281. $this->settings['notification'] = $data['notification'];
  282. $this->save_settings();
  283. $this->messages[] = array(
  284. 'type'=>'updated',
  285. 'text' => __('Preferences saved.', 'sitepress')
  286. );
  287. break;
  288. case 'create_job':
  289. global $current_user;
  290. if(!isset($this->current_translator->ID) && isset($current_user->ID)){
  291. $this->current_translator->ID = $current_user->ID;
  292. }
  293. $data['translator'] = $this->current_translator->ID;
  294. $job_ids = $this->send_jobs($data);
  295. wp_redirect('admin.php?page='.WPML_TM_FOLDER . '/menu/translations-queue.php&job_id=' . array_pop($job_ids));
  296. break;
  297. case 'cancel_jobs':
  298. $ret = $this->cancel_translation_request($data['icl_translation_id']);
  299. $this->messages[] = array(
  300. 'type'=>'updated',
  301. 'text' => __('Translation requests cancelled.', 'sitepress')
  302. );
  303. break;
  304. }
  305. }
  306. function ajax_calls( $call, $data ) {
  307. global $wpdb, $sitepress, $sitepress_settings;
  308. switch ( $call ) {
  309. /*
  310. case 'save_dashboard_setting':
  311. $iclsettings['dashboard'] = $sitepress_settings['dashboard'];
  312. if(isset($data['setting']) && isset($data['value'])){
  313. $iclsettings['dashboard'][$data['setting']] = $data['value'];
  314. $sitepress->save_settings($iclsettings);
  315. }
  316. break;
  317. */
  318. case 'assign_translator':
  319. $_exp = explode( '-', $data[ 'translator_id' ] );
  320. $service = isset( $_exp[ 1 ] ) ? $_exp[ 1 ] : 'local';
  321. $translator_id = $_exp[ 0 ];
  322. if ( $this->assign_translation_job( $data[ 'job_id' ], $translator_id, $service ) ) {
  323. if ( $service == 'icanlocalize' ) {
  324. $job = $this->get_translation_job( $data[ 'job_id' ] );
  325. global $ICL_Pro_Translation;
  326. $ICL_Pro_Translation->send_post( $job->original_doc_id, array( $job->language_code ), $translator_id );
  327. $lang_tr_id = false;
  328. $contract_id = false;
  329. foreach ( $sitepress_settings[ 'icl_lang_status' ] as $lp ) {
  330. if ( $lp[ 'from' ] == $job->source_language_code && $lp[ 'to' ] == $job->language_code ) {
  331. $contract_id = $lp[ 'contract_id' ];
  332. $lang_tr_id = $lp[ 'id' ];
  333. break;
  334. }
  335. }
  336. $popup_link = ICL_API_ENDPOINT . '/websites/' . $sitepress_settings[ 'site_id' ] . '/website_translation_offers/' . $lang_tr_id . '/website_translation_contracts/' . $contract_id;
  337. $popup_args = array(
  338. 'title' => __( 'Chat with translator', 'sitepress' ),
  339. 'unload_cb' => 'icl_thickbox_refresh'
  340. );
  341. $translator_edit_link = $sitepress->create_icl_popup_link( $popup_link, $popup_args );
  342. $translator_edit_link .= esc_html( ICL_Pro_Translation::get_translator_name( $translator_id ) );
  343. $translator_edit_link .= '</a> (ICanLocalize)';
  344. } else {
  345. $translator_edit_link =
  346. '<a href="' . $this->get_translator_edit_url( $data[ 'translator_id' ] ) . '">' . esc_html( $wpdb->get_var( $wpdb->prepare( "SELECT display_name FROM {$wpdb->users} WHERE ID=%d", $data[ 'translator_id' ] ) ) ) . '</a>';
  347. }
  348. echo json_encode( array( 'error' => 0, 'message' => $translator_edit_link, 'status' => $this->status2text( ICL_TM_WAITING_FOR_TRANSLATOR ), 'service' => $service ) );
  349. } else {
  350. echo json_encode( array( 'error' => 1 ) );
  351. }
  352. break;
  353. case 'icl_cf_translation':
  354. if ( !empty( $data[ 'cf' ] ) ) {
  355. foreach ( $data[ 'cf' ] as $k => $v ) {
  356. $cft[ base64_decode( $k ) ] = $v;
  357. }
  358. if ( isset( $cft ) ) {
  359. $this->settings['custom_fields_translation'] = $cft;
  360. $this->save_settings();
  361. }
  362. }
  363. echo '1|';
  364. break;
  365. case 'icl_doc_translation_method':
  366. $this->settings['doc_translation_method'] = intval($data['t_method']);
  367. $sitepress->set_setting( 'hide_how_to_translate', empty( $data[ 'how_to_translate' ] ) );
  368. if (isset($data[ 'tm_block_retranslating_terms' ])) {
  369. $sitepress->set_setting( 'tm_block_retranslating_terms', $data[ 'tm_block_retranslating_terms' ] );
  370. } else {
  371. $sitepress->set_setting( 'tm_block_retranslating_terms', '' );
  372. }
  373. $this->save_settings();
  374. echo '1|';
  375. break;
  376. case 'reset_duplication':
  377. $this->reset_duplicate_flag( $_POST[ 'post_id' ] );
  378. break;
  379. case 'set_duplication':
  380. $this->set_duplicate( $_POST[ 'post_id' ] );
  381. break;
  382. case 'make_duplicates':
  383. $mdata[ 'iclpost' ] = array( $data[ 'post_id' ] );
  384. $langs = explode( ',', $data[ 'langs' ] );
  385. foreach ( $langs as $lang ) {
  386. $mdata[ 'duplicate_to' ][ $lang ] = 1;
  387. }
  388. $this->make_duplicates( $mdata );
  389. break;
  390. }
  391. }
  392. function show_messages(){
  393. if(!empty($this->messages)){
  394. foreach($this->messages as $m){
  395. echo '<div class="'.$m['type'].' below-h2"><p>' . $m['text'] . '</p></div>';
  396. }
  397. }
  398. }
  399. /* TRANSLATORS */
  400. /* ******************************************************************************************** */
  401. function add_translator($user_id, $language_pairs){
  402. global $wpdb;
  403. $user = new WP_User($user_id);
  404. $user->add_cap('translate');
  405. $um = get_user_meta($user_id, $wpdb->prefix . 'language_pairs', true);
  406. if(!empty($um)){
  407. foreach($um as $fr=>$to){
  408. if(isset($language_pairs[$fr])){
  409. $language_pairs[$fr] = array_merge($language_pairs[$fr], $to);
  410. }
  411. }
  412. }
  413. update_user_meta($user_id, $wpdb->prefix . 'language_pairs', $language_pairs);
  414. $this->clear_cache();
  415. }
  416. function edit_translator($user_id, $language_pairs){
  417. global $wpdb;
  418. $_user = new WP_User($user_id);
  419. if(empty($language_pairs)){
  420. $this->remove_translator($user_id);
  421. wp_redirect('admin.php?page='.WPML_TM_FOLDER.'/menu/main.php&sm=translators&icl_tm_message='.
  422. urlencode(sprintf(__('%s has been removed as a translator for this site.','sitepress'),$_user->data->display_name)).'&icl_tm_message_type=updated'); exit;
  423. }
  424. else{
  425. if(!$_user->has_cap('translate')) $_user->add_cap('translate');
  426. update_user_meta($user_id, $wpdb->prefix . 'language_pairs', $language_pairs);
  427. }
  428. }
  429. function remove_translator($user_id){
  430. global $wpdb;
  431. $user = new WP_User($user_id);
  432. $user->remove_cap('translate');
  433. delete_user_meta($user_id, $wpdb->prefix . 'language_pairs');
  434. $this->clear_cache();
  435. }
  436. function is_translator( $user_id, $args = array() )
  437. {
  438. extract( $args, EXTR_OVERWRITE );
  439. global $wpdb;
  440. $user = new WP_User( $user_id );
  441. $is_translator = $user->has_cap( 'translate' );
  442. // check if user is administrator and return true if he is
  443. $user_caps = $user->caps;
  444. if ( isset( $user_caps[ 'activate_plugins' ] ) && $user_caps[ 'activate_plugins' ] == true ) {
  445. $is_translator = true;
  446. } else {
  447. if ( isset( $lang_from ) && isset( $lang_to ) ) {
  448. $um = get_user_meta( $user_id, $wpdb->prefix . 'language_pairs', true );
  449. $is_translator = $is_translator && isset( $um[ $lang_from ] ) && isset( $um[ $lang_from ][ $lang_to ] ) && $um[ $lang_from ][ $lang_to ];
  450. }
  451. if ( isset( $job_id ) ) {
  452. $translator_id = $wpdb->get_var( $wpdb->prepare( "
  453. SELECT j.translator_id
  454. FROM {$wpdb->prefix}icl_translate_job j
  455. JOIN {$wpdb->prefix}icl_translation_status s ON j.rid = s.rid
  456. WHERE job_id = %d AND s.translation_service='local'
  457. ", $job_id ) );
  458. $is_translator = $is_translator && ( ( $translator_id == $user_id ) || empty( $translator_id ) );
  459. }
  460. }
  461. return $is_translator;
  462. }
  463. function translator_exists($id, $from, $to, $type = 'local'){
  464. global $sitepress_settings;
  465. $exists = false;
  466. if($type == 'icanlocalize' && !empty($sitepress_settings['icl_lang_status'])){
  467. foreach($sitepress_settings['icl_lang_status'] as $lpair){
  468. if($lpair['from'] == $from && $lpair['to'] == $to){
  469. if(!empty($lpair['translators'])){
  470. foreach($lpair['translators'] as $t){
  471. if($t['id'] == $id){
  472. $exists = true;
  473. break(2);
  474. }
  475. }
  476. }
  477. }
  478. }
  479. }elseif($type == 'local'){
  480. $exists = $this->is_translator($id, array('lang_from'=>$from, 'lang_to'=>$to));
  481. }
  482. return $exists;
  483. }
  484. function set_default_translator($id, $from, $to, $type = 'local'){
  485. global $sitepress, $sitepress_settings;
  486. $iclsettings['default_translators'] = isset($sitepress_settings['default_translators']) ? $sitepress_settings['default_translators'] : array();
  487. $iclsettings['default_translators'][$from][$to] = array('id'=>$id, 'type'=>$type);
  488. $sitepress->save_settings($iclsettings);
  489. }
  490. function get_default_translator($from, $to){
  491. global $sitepress_settings;
  492. if(isset($sitepress_settings['default_translators'][$from][$to])){
  493. $dt = $sitepress_settings['default_translators'][$from][$to];
  494. }else{
  495. $dt = array();
  496. }
  497. return $dt;
  498. }
  499. public static function get_blog_not_translators(){
  500. global $wpdb;
  501. $cached_translators = get_option($wpdb->prefix . 'icl_non_translators_cached', array());
  502. if (!empty($cached_translators)) {
  503. return $cached_translators;
  504. }
  505. $sql = "SELECT u.ID, u.user_login, u.display_name, m.meta_value AS caps
  506. 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";
  507. $res = $wpdb->get_results($sql);
  508. $users = array();
  509. foreach($res as $row){
  510. $caps = @unserialize($row->caps);
  511. if(!isset($caps['translate'])){
  512. $users[] = $row;
  513. }
  514. }
  515. update_option($wpdb->prefix . 'icl_non_translators_cached', $users);
  516. return $users;
  517. }
  518. /**
  519. * Implementation of 'icl_translators_list' hook
  520. *
  521. * @global object $sitepress
  522. * @param array $array
  523. * @return array
  524. */
  525. public static function icanlocalize_translators_list() {
  526. global $sitepress_settings, $sitepress;
  527. $lang_status = isset($sitepress_settings['icl_lang_status']) ? $sitepress_settings['icl_lang_status'] : array();
  528. if (0 != key($lang_status)){
  529. $buf[] = $lang_status;
  530. $lang_status = $buf;
  531. }
  532. $translators = array();
  533. foreach($lang_status as $lpair){
  534. foreach((array)$lpair['translators'] as $translator){
  535. $translators[$translator['id']]['name'] = $translator['nickname'];
  536. $translators[$translator['id']]['langs'][$lpair['from']][] = $lpair['to'];
  537. $translators[$translator['id']]['type'] = 'ICanLocalize';
  538. $translators[$translator['id']]['action'] = $sitepress->create_icl_popup_link(ICL_API_ENDPOINT . '/websites/' . $sitepress_settings['site_id']
  539. . '/website_translation_offers/' . $lpair['id'] . '/website_translation_contracts/'
  540. . $translator['contract_id'], array('title' => __('Chat with translator', 'sitepress'), 'unload_cb' => 'icl_thickbox_refresh', 'ar'=>1)) . __('Chat with translator', 'sitepress') . '</a>';
  541. }
  542. }
  543. return $translators;
  544. }
  545. public static function get_blog_translators($args = array()){
  546. global $wpdb;
  547. $args_default = array('from'=>false, 'to'=>false);
  548. extract($args_default);
  549. extract($args, EXTR_OVERWRITE);
  550. // $sql = "SELECT u.ID, u.user_login, u.display_name, u.user_email, m.meta_value AS caps
  551. // 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";
  552. // $res = $wpdb->get_results($sql);
  553. $cached_translators = get_option($wpdb->prefix . 'icl_translators_cached', array());
  554. if (empty($cached_translators)) {
  555. $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";
  556. $res = $wpdb->get_results($sql);
  557. update_option($wpdb->prefix . 'icl_translators_cached', $res);
  558. } else {
  559. $res = $cached_translators;
  560. }
  561. $users = array();
  562. foreach($res as $row){
  563. $user = new WP_User($row->ID);
  564. // $caps = @unserialize($row->caps);
  565. // $row->language_pairs = (array)get_user_meta($row->ID, $wpdb->prefix.'language_pairs', true);
  566. $user->language_pairs = (array)get_user_meta($row->ID, $wpdb->prefix.'language_pairs', true);
  567. // if(!empty($from) && !empty($to) && (!isset($row->language_pairs[$from][$to]) || !$row->language_pairs[$from][$to])){
  568. // continue;
  569. // }
  570. if(!empty($from) && !empty($to) && (!isset($user->language_pairs[$from][$to]) || !$user->language_pairs[$from][$to])){
  571. continue;
  572. }
  573. // if(isset($caps['translate'])){
  574. // $users[] = $user;
  575. // }
  576. if($user->has_cap('translate')){
  577. $users[] = $user;
  578. }
  579. }
  580. return $users;
  581. }
  582. function get_selected_translator(){
  583. global $wpdb;
  584. if($this->selected_translator['ID']){
  585. $user = new WP_User($this->selected_translator['ID']);
  586. $this->selected_translator['display_name'] = $user->data->display_name;
  587. $this->selected_translator['user_login'] = $user->data->user_login;
  588. $this->selected_translator['language_pairs'] = get_user_meta($this->selected_translator['ID'], $wpdb->prefix.'language_pairs', true);
  589. }else{
  590. $this->selected_translator['ID'] = 0;
  591. }
  592. return (object)$this->selected_translator;
  593. }
  594. function get_current_translator(){
  595. return $this->current_translator;
  596. }
  597. public function get_translator_edit_url($translator_id){
  598. $url = '';
  599. if(!empty($translator_id)){
  600. $url = 'admin.php?page='. WPML_TM_FOLDER .'/menu/main.php&amp;sm=translators&icl_tm_action=edit&amp;user_id='. $translator_id;
  601. }
  602. return $url;
  603. }
  604. public function translators_dropdown( $args = array() ) {
  605. global $sitepress_settings;
  606. $args_default = array(
  607. 'from' => false,
  608. 'to' => false,
  609. 'name' => 'translator_id',
  610. 'selected' => 0,
  611. 'echo' => true,
  612. 'services' => array( 'local' ),
  613. 'show_service' => true,
  614. 'disabled' => false
  615. );
  616. extract( $args_default );
  617. extract( $args, EXTR_OVERWRITE );
  618. $translators = array();
  619. /** @var $from string|false */
  620. /** @var $to string|false */
  621. /** @var $name string|false */
  622. /** @var $selected bool */
  623. /** @var $echo bool */
  624. /** @var $services array */
  625. /** @var $show_service bool */
  626. /** @var $disabled bool */
  627. if ( in_array( 'icanlocalize', $services ) ) {
  628. if ( empty( $sitepress_settings[ 'icl_lang_status' ] ) ) {
  629. $sitepress_settings[ 'icl_lang_status' ] = array();
  630. }
  631. foreach ( (array) $sitepress_settings[ 'icl_lang_status' ] as $language_pair ) {
  632. if ( $from && $from != $language_pair[ 'from' ] ) {
  633. continue;
  634. }
  635. if ( $to && $to != $language_pair[ 'to' ] ) {
  636. continue;
  637. }
  638. if ( !empty( $language_pair[ 'translators' ] ) ) {
  639. if ( 1 < count( $language_pair[ 'translators' ] ) ) {
  640. $translators[ ] = (object) array(
  641. 'ID' => '0-icanlocalize',
  642. 'display_name' => __( 'First available', 'sitepress' ),
  643. 'service' => 'ICanLocalize'
  644. );
  645. }
  646. foreach ( $language_pair[ 'translators' ] as $tr ) {
  647. if ( !isset( $_icl_translators[ $tr[ 'id' ] ] ) ) {
  648. $translators[ ] = $_icl_translators[ $tr[ 'id' ] ] = (object) array(
  649. 'ID' => $tr[ 'id' ] . '-icanlocalize',
  650. 'display_name' => $tr[ 'nickname' ],
  651. 'service' => 'ICanLocalize'
  652. );
  653. }
  654. }
  655. }
  656. }
  657. }
  658. if ( in_array( 'local', $services ) ) {
  659. $translators[ ] = (object) array(
  660. 'ID' => 0,
  661. 'display_name' => __( 'First available', 'sitepress' ),
  662. );
  663. $translators = array_merge( $translators, self::get_blog_translators( array( 'from' => $from, 'to' => $to ) ) );
  664. }
  665. $translators = apply_filters( 'wpml_tm_translators_list', $translators );
  666. ?>
  667. <select name="<?php echo $name ?>" <?php if ($disabled): ?>disabled="disabled"<?php endif; ?>>
  668. <?php foreach ( $translators as $t ): ?>
  669. <option value="<?php echo $t->ID ?>" <?php if ($selected == $t->ID): ?>selected="selected"<?php endif; ?>><?php echo esc_html( $t->display_name );
  670. ?> <?php if ( $show_service ) {
  671. echo '(';
  672. echo isset( $t->service ) ? $t->service : _e( 'Local', 'sitepress' );
  673. echo ')';
  674. } ?></option>
  675. <?php endforeach; ?>
  676. </select>
  677. <?php
  678. }
  679. public function get_number_of_docs_sent($service = 'icanlocalize'){
  680. global $wpdb;
  681. $n = $wpdb->get_var($wpdb->prepare("
  682. SELECT COUNT(rid) FROM {$wpdb->prefix}icl_translation_status WHERE translation_service=%s
  683. ", $service));
  684. return $n;
  685. }
  686. public function get_number_of_docs_pending($service = 'icanlocalize'){
  687. global $wpdb;
  688. $n = $wpdb->get_var($wpdb->prepare("
  689. SELECT COUNT(rid) FROM {$wpdb->prefix}icl_translation_status WHERE translation_service=%s AND status < " . ICL_TM_COMPLETE . "
  690. ", $service));
  691. return $n;
  692. }
  693. /* HOOKS */
  694. /* ******************************************************************************************** */
  695. function save_post_actions( $post_id, $post, $force_set_status = false )
  696. {
  697. global $wpdb, $sitepress, $current_user;
  698. // skip revisions
  699. if ( $post->post_type == 'revision' ) {
  700. return;
  701. }
  702. // skip auto-drafts
  703. if ( $post->post_status == 'auto-draft' ) {
  704. return;
  705. }
  706. // skip autosave
  707. if ( isset( $_POST[ 'autosave' ] ) ) {
  708. return;
  709. }
  710. if ( isset( $_POST[ 'icl_trid' ] ) && is_numeric($_POST['icl_trid']) ) {
  711. $trid = $_POST['icl_trid'];
  712. } else {
  713. $trid = $sitepress->get_element_trid( $post_id, 'post_' . $post->post_type );
  714. }
  715. // set trid and lang code if front-end translation creating
  716. $trid = apply_filters( 'wpml_tm_save_post_trid_value', isset( $trid ) ? $trid : '', $post_id );
  717. $lang = apply_filters( 'wpml_tm_save_post_lang_value', isset( $lang ) ? $lang : '', $post_id );
  718. // is this the original document?
  719. $is_original = false;
  720. if ( !empty( $trid ) ) {
  721. $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, $trid ) );
  722. }
  723. // when a manual translation is added/edited make sure to update translation tables
  724. if ( !empty( $trid ) && !$is_original ) {
  725. if ( ( !isset( $lang ) || !$lang ) && isset( $_POST[ 'icl_post_language' ] ) && !empty( $_POST[ 'icl_post_language' ] ) ) {
  726. $lang = $_POST[ 'icl_post_language' ];
  727. }
  728. $res = $wpdb->get_row( $wpdb->prepare( "
  729. SELECT element_id, language_code FROM {$wpdb->prefix}icl_translations WHERE trid=%d AND source_language_code IS NULL
  730. ", $trid ) );
  731. if ( $res ) {
  732. $original_post_id = $res->element_id;
  733. $from_lang = $res->language_code;
  734. $original_post = get_post( $original_post_id );
  735. $md5 = $this->post_md5( $original_post );
  736. $translation_id_prepared = $wpdb->prepare( "SELECT translation_id FROM {$wpdb->prefix}icl_translations WHERE trid=%d AND language_code=%s", $trid, $lang );
  737. $translation_id = $wpdb->get_var( $translation_id_prepared );
  738. get_currentuserinfo();
  739. $user_id = $current_user->ID;
  740. if ( !$this->is_translator( $user_id, array( 'lang_from' => $from_lang, 'lang_to' => $lang ) ) ) {
  741. $this->add_translator( $user_id, array( $from_lang => array( $lang => 1 ) ) );
  742. }
  743. if ( $translation_id ) {
  744. $translation_package = $this->create_translation_package( $original_post_id );
  745. list( $rid, $update ) = $this->update_translation_status( array(
  746. 'translation_id' => $translation_id,
  747. 'status' => isset( $force_set_status ) && $force_set_status > 0 ? $force_set_status : ICL_TM_COMPLETE,
  748. 'translator_id' => $user_id,
  749. 'needs_update' => 0,
  750. 'md5' => $md5,
  751. 'translation_service' => 'local',
  752. 'translation_package' => serialize( $translation_package )
  753. ) );
  754. if ( !$update ) {
  755. $job_id = $this->add_translation_job( $rid, $user_id, $translation_package );
  756. } else {
  757. $job_id = $wpdb->get_var( $wpdb->prepare( "SELECT MAX(job_id) FROM {$wpdb->prefix}icl_translate_job WHERE rid=%d GROUP BY rid", $rid ) );
  758. }
  759. // saving the translation
  760. $this->save_job_fields_from_post( $job_id, $post );
  761. }
  762. }
  763. }
  764. // if this is an original post - compute md5 hash and mark for update if neded
  765. if ( !empty( $trid ) && empty( $_POST[ 'icl_minor_edit' ] ) ) {
  766. $is_original = false;
  767. $translations = $sitepress->get_element_translations( $trid, 'post_' . $post->post_type );
  768. foreach ( $translations as $lang => $translation ) {
  769. if ( $translation->original == 1 && $translation->element_id == $post_id ) {
  770. $is_original = true;
  771. break;
  772. }
  773. }
  774. if ( $is_original ) {
  775. $md5 = $this->post_md5( $post_id );
  776. foreach ( $translations as $lang => $translation ) {
  777. if ( !$translation->original ) {
  778. $emd5_prepared = $wpdb->prepare( "SELECT md5 FROM {$wpdb->prefix}icl_translation_status WHERE translation_id = %d", $translation->translation_id );
  779. $emd5 = $wpdb->get_var( $emd5_prepared );
  780. if ( $md5 != $emd5 ) {
  781. $translation_package = $this->create_translation_package( $post_id );
  782. list( $rid, $update ) = $this->update_translation_status( array(
  783. 'translation_id' => $translation->translation_id,
  784. 'needs_update' => 1,
  785. 'md5' => $md5,
  786. 'translation_package' => serialize( $translation_package )
  787. ) );
  788. // update
  789. $translator_id_prepared = $wpdb->prepare( "SELECT translator_id FROM {$wpdb->prefix}icl_translation_status WHERE translation_id = %d", $translation->translation_id );
  790. $translator_id = $wpdb->get_var( $translator_id_prepared );
  791. $job_id = $this->add_translation_job( $rid, $translator_id, $translation_package );
  792. // updating a post that's being translated - update fields in icl_translate
  793. if ( false === $job_id ) {
  794. $job_id_prepared = $wpdb->prepare( "SELECT MAX(job_id) FROM {$wpdb->prefix}icl_translate_job WHERE rid = %d", $rid );
  795. $job_id = $wpdb->get_var( $job_id_prepared );
  796. if ( $job_id ) {
  797. $job = $this->get_translation_job( $job_id );
  798. if ( $job ) {
  799. foreach ( $job->elements as $element ) {
  800. unset( $field_data );
  801. $_taxs_ids = false;
  802. switch ( $element->field_type ) {
  803. case 'title':
  804. $field_data = $this->encode_field_data( $post->post_title, $element->field_format );
  805. break;
  806. case 'body':
  807. $field_data = $this->encode_field_data( $post->post_content, $element->field_format );
  808. break;
  809. case 'excerpt':
  810. $field_data = $this->encode_field_data( $post->post_excerpt, $element->field_format );
  811. break;
  812. case 'tags':
  813. $terms = (array)get_the_terms( $post->ID, 'post_tag' );
  814. $_taxs = array();
  815. foreach ( $terms as $term ) {
  816. $_taxs[ ] = $term->name;
  817. $_taxs_ids[ ] = $term->term_taxonomy_id;
  818. }
  819. $field_data = $this->encode_field_data( $_taxs, $element->field_format );
  820. break;
  821. case 'categories':
  822. $terms = get_the_terms( $post->ID, 'category' );
  823. $_taxs = array();
  824. foreach ( $terms as $term ) {
  825. $_taxs[ ] = $term->name;
  826. $_taxs_ids[ ] = $term->term_taxonomy_id;
  827. }
  828. $field_data = $this->encode_field_data( $_taxs, $element->field_format );
  829. break;
  830. default:
  831. if ( false !== strpos( $element->field_type, 'field-' ) && !empty( $this->settings[ 'custom_fields_translation' ] ) ) {
  832. $cf_name = preg_replace( '#^field-#', '', $element->field_type );
  833. if ( isset( $this->settings[ 'custom_fields_translation' ][ $cf_name ] ) ) {
  834. $field_data = get_post_meta( $post->ID, $cf_name, 1 );
  835. $field_data = $this->encode_field_data( $field_data, $element->field_format );
  836. }
  837. } else {
  838. // taxonomies
  839. if ( taxonomy_exists( $element->field_type ) ) {
  840. $terms = get_the_terms( $post->ID, $element->field_type );
  841. $_taxs = array();
  842. foreach ( $terms as $term ) {
  843. $_taxs[ ] = $term->name;
  844. $_taxs_ids[ ] = $term->term_taxonomy_id;
  845. }
  846. $field_data = $this->encode_field_data( $_taxs, $element->field_format );
  847. }
  848. }
  849. }
  850. if ( isset( $field_data ) && $field_data != $element->field_data ) {
  851. $wpdb->update( $wpdb->prefix . 'icl_translate', array( 'field_data' => $field_data ), array( 'tid' => $element->tid ) );
  852. if ( $_taxs_ids && $element->field_type == 'categories' ) {
  853. $wpdb->update( $wpdb->prefix . 'icl_translate', array( 'field_data' => join( ',', $_taxs_ids ) ), array( 'job_id' => $job_id, 'field_type' => 'category_ids' ) );
  854. }
  855. }
  856. }
  857. }
  858. }
  859. }
  860. }
  861. }
  862. }
  863. }
  864. }
  865. // sync copies/duplicates
  866. $duplicates = $this->get_duplicates( $post_id );
  867. static $duplicated_post_ids;
  868. if ( !isset( $duplicated_post_ids ) ) {
  869. $duplicated_post_ids = array();
  870. }
  871. foreach ( $duplicates as $lang => $_pid ) {
  872. // Avoid infinite recursions
  873. if ( !in_array( $post_id . '|' . $lang, $duplicated_post_ids ) ) {
  874. $duplicated_post_ids[ ] = $post_id . '|' . $lang;
  875. $this->make_duplicate( $post_id, $lang );
  876. }
  877. }
  878. }
  879. function make_duplicates( $data )
  880. {
  881. foreach ( $data[ 'iclpost' ] as $master_post_id ) {
  882. foreach ( $data[ 'duplicate_to' ] as $lang => $one ) {
  883. $this->make_duplicate( $master_post_id, $lang );
  884. }
  885. }
  886. }
  887. function make_duplicate( $master_post_id, $lang )
  888. {
  889. static $duplicated_post_ids;
  890. if(!isset($duplicated_post_ids)) {
  891. $duplicated_post_ids = array();
  892. }
  893. //It is already done? (avoid infinite recursions)
  894. if(in_array($master_post_id . '|' . $lang, $duplicated_post_ids)) {
  895. return true;
  896. }
  897. $duplicated_post_ids[] = $master_post_id . '|' . $lang;
  898. global $sitepress, $sitepress_settings, $wpdb;
  899. do_action( 'icl_before_make_duplicate', $master_post_id, $lang );
  900. $master_post = get_post( $master_post_id );
  901. $is_duplicated = false;
  902. $trid = $sitepress->get_element_trid( $master_post_id, 'post_' . $master_post->post_type );
  903. if ( $trid ) {
  904. $translations = $sitepress->get_element_translations( $trid, 'post_' . $master_post->post_type );
  905. if ( isset( $translations[ $lang ] ) ) {
  906. $post_array[ 'ID' ] = $translations[ $lang ]->element_id;
  907. $is_duplicated = get_post_meta( $translations[ $lang ]->element_id, '_icl_lang_duplicate_of', true );
  908. }
  909. }
  910. // covers the case when deleting in bulk from all languages
  911. // setting post_status to trash before wp_trash_post runs issues an WP error
  912. $posts_to_delete_or_restore_in_bulk = array();
  913. if ( isset( $_GET[ 'action' ] ) && ( $_GET[ 'action' ] == 'trash' || $_GET[ 'action' ] == 'untrash' ) && isset( $_GET[ 'lang' ] ) && $_GET[ 'lang' ] == 'all' ) {
  914. static $posts_to_delete_or_restore_in_bulk;
  915. if ( is_null( $posts_to_delete_or_restore_in_bulk ) ) {
  916. $posts_to_delete_or_restore_in_bulk = isset( $_GET[ 'post' ] ) && is_array( $_GET[ 'post' ] ) ? $_GET[ 'post' ] : array();
  917. }
  918. }
  919. $post_array[ 'post_author' ] = $master_post->post_author;
  920. $post_array[ 'post_date' ] = $master_post->post_date;
  921. $post_array[ 'post_date_gmt' ] = $master_post->post_date_gmt;
  922. $post_array[ 'post_content' ] = addslashes_gpc(apply_filters( 'icl_duplicate_generic_string', $master_post->post_content, $lang, array( 'context' => 'post', 'attribute' => 'content', 'key' => $master_post->ID ) ));
  923. $post_array[ 'post_title' ] = addslashes_gpc(apply_filters( 'icl_duplicate_generic_string', $master_post->post_title, $lang, array( 'context' => 'post', 'attribute' => 'title', 'key' => $master_post->ID ) ));
  924. $post_array[ 'post_excerpt' ] = addslashes_gpc(apply_filters( 'icl_duplicate_generic_string', $master_post->post_excerpt, $lang, array( 'context' => 'post', 'attribute' => 'excerpt', 'key' => $master_post->ID ) ));
  925. if ( isset( $sitepress_settings[ 'sync_post_status' ] ) && $sitepress_settings[ 'sync_post_status' ] ) {
  926. $sync_post_status = true;
  927. } else {
  928. $sync_post_status = ( !isset( $post_array[ 'ID' ] ) || ( $sitepress_settings[ 'sync_delete' ] && $master_post->post_status == 'trash' ) || $is_duplicated );
  929. $sync_post_status &= ( !$posts_to_delete_or_restore_in_bulk || ( !isset( $post_array[ 'ID' ] ) || !in_array( $post_array[ 'ID' ], $posts_to_delete_or_restore_in_bulk ) ) );
  930. }
  931. if ( $sync_post_status ) {
  932. $post_array[ 'post_status' ] = $master_post->post_status;
  933. }
  934. $post_array[ 'comment_status' ] = $master_post->comment_status;
  935. $post_array[ 'ping_status' ] = $master_post->ping_status;
  936. $post_array[ 'post_name' ] = $master_post->post_name;
  937. if ( $master_post->post_parent ) {
  938. $parent = icl_object_id( $master_post->post_parent, $master_post->post_type, false, $lang );
  939. $post_array[ 'post_parent' ] = $parent;
  940. }
  941. $post_array[ 'menu_order' ] = $master_post->menu_order;
  942. $post_array[ 'post_type' ] = $master_post->post_type;
  943. $post_array[ 'post_mime_type' ] = $master_post->post_mime_type;
  944. $trid = $sitepress->get_element_trid( $master_post->ID, 'post_' . $master_post->post_type );
  945. $_POST[ 'icl_trid' ] = $trid;
  946. $_POST[ 'icl_post_language' ] = $lang;
  947. $_POST[ 'skip_sitepress_actions' ] = true;
  948. $_POST[ 'post_type' ] = $master_post->post_type;
  949. if ( isset( $post_array[ 'ID' ] ) ) {
  950. $id = wp_update_post( $post_array );
  951. } else {
  952. $id = $this->icl_insert_post( $post_array, $lang );
  953. }
  954. require_once ICL_PLUGIN_PATH . '/inc/cache.php';
  955. icl_cache_clear( $post_array[ 'post_type' ] . 's_per_language' );
  956. global $ICL_Pro_Translation;
  957. $ICL_Pro_Translation->_content_fix_links_to_translated_content( $id, $lang );
  958. if ( !is_wp_error( $id ) ) {
  959. $sitepress->set_element_language_details( $id, 'post_' . $master_post->post_type, $trid, $lang );
  960. $this->save_post_actions( $id, get_post( $id ), ICL_TM_DUPLICATE );
  961. $this->duplicate_fix_children( $master_post_id, $lang );
  962. // dup comments
  963. if ( $sitepress->get_option( 'sync_comments_on_duplicates' ) ) {
  964. $this->duplicate_comments( $id, $master_post_id );
  965. }
  966. // make sure post name is copied
  967. $wpdb->update( $wpdb->posts, array( 'post_name' => $master_post->post_name ), array( 'ID' => $id ) );
  968. update_post_meta( $id, '_icl_lang_duplicate_of', $master_post->ID );
  969. if ( $sitepress->get_option( 'sync_post_taxonomies' ) ) {
  970. $this->duplicate_taxonomies( $master_post_id, $lang );
  971. }
  972. $this->duplicate_custom_fields( $master_post_id, $lang );
  973. $ret = $id;
  974. do_action( 'icl_make_duplicate', $master_post_id, $lang, $post_array, $id );
  975. } else {
  976. $ret = false;
  977. }
  978. return $ret;
  979. }
  980. function duplicate_taxonomies( $master_post_id, $lang )
  981. {
  982. global $wpdb, $sitepress;
  983. $post_type = get_post_field( 'post_type', $master_post_id );
  984. $taxonomies = get_object_taxonomies( $post_type );
  985. $trid = $sitepress->get_element_trid( $master_post_id, 'post_' . $post_type );
  986. $duplicate_post_id = false;
  987. if ( $trid ) {
  988. $translations = $sitepress->get_element_translations( $trid, 'post_' . $post_type, false, false, true );
  989. if ( isset( $translations[ $lang ] ) ) {
  990. $duplicate_post_id = $translations[ $lang ]->element_id;
  991. /* If we have an existing post, we first of all remove all terms currently attached to it.
  992. * The main reason behind is the removal of the potentially present default category on the post.
  993. */
  994. wp_delete_object_term_relationships( $duplicate_post_id, $taxonomies );
  995. } else {
  996. return false; // translation not found!
  997. }
  998. }
  999. foreach ( $taxonomies as $taxonomy ) {
  1000. if ( $sitepress->is_translated_taxonomy ( $taxonomy ) ) {
  1001. WPML_Terms_Translations::sync_post_and_taxonomy_terms_language( $master_post_id, $taxonomy, true );
  1002. }
  1003. }
  1004. return true;
  1005. }
  1006. function duplicate_custom_fields( $master_post_id, $lang )
  1007. {
  1008. global $wpdb, $sitepress;
  1009. $duplicate_post_id = false;
  1010. $post_type = get_post_field( 'post_type', $master_post_id );
  1011. $trid = $sitepress->get_element_trid( $master_post_id, 'post_' . $post_type );
  1012. if ( $trid ) {
  1013. $translations = $sitepress->get_element_translations( $trid, 'post_' . $post_type );
  1014. if ( isset( $translations[ $lang ] ) ) {
  1015. $duplicate_post_id = $translations[ $lang ]->element_id;
  1016. } else {
  1017. return false; // translation not found!
  1018. }
  1019. }
  1020. $default_exceptions = array(
  1021. '_wp_old_slug',
  1022. '_edit_last',
  1023. '_edit_lock',
  1024. '_icl_translator_note',
  1025. '_icl_lang_duplicate_of',
  1026. '_wpml_media_duplicate',
  1027. '_wpml_media_featured'
  1028. );
  1029. $exceptions = $default_exceptions;
  1030. //Todo: make sure the following filter won't remove the default exceptions
  1031. $exceptions = apply_filters('wpml_duplicate_custom_fields_exceptions', $exceptions);
  1032. // low level copy
  1033. $custom_fields_master = $wpdb->get_col( $wpdb->prepare( "SELECT meta_key FROM {$wpdb->postmeta} WHERE post_id=%d group by meta_key", $master_post_id ) );
  1034. $custom_fields_duplicate = $wpdb->get_col( $wpdb->prepare( "SELECT meta_key FROM {$wpdb->postmeta} WHERE post_id=%d group by meta_key", $duplicate_post_id ) );
  1035. $custom_fields_master = array_diff( $custom_fields_master, $exceptions );
  1036. $custom_fields_duplicate = array_diff( $custom_fields_duplicate, $exceptions );
  1037. $remove = array_diff( $custom_fields_duplicate, $custom_fields_master );
  1038. foreach ( $remove as $key ) {
  1039. delete_post_meta( $duplicate_post_id, $key );
  1040. }
  1041. foreach ( $custom_fields_master as $key ) {
  1042. $master_custom_field_values_array = get_post_meta( $master_post_id, $key );
  1043. $master_custom_field_values_single = get_post_meta( $master_post_id, $key, true );
  1044. $is_repeated = false;
  1045. if($master_custom_field_values_array != $master_custom_field_values_single) {
  1046. //Repeated fields
  1047. $master_custom_field_values = $master_custom_field_values_array;
  1048. $is_repeated = true;
  1049. } else {
  1050. //Field stored as serialized array
  1051. $master_custom_field_values[] = $master_custom_field_values_single;
  1052. }
  1053. if($is_repeated) {
  1054. $duplicate_custom_field_values = get_post_meta( $duplicate_post_id, $key );
  1055. } else {
  1056. $duplicate_custom_field_values[] = get_post_meta( $duplicate_post_id, $key, true );
  1057. }
  1058. if ( !$duplicate_custom_field_values || $master_custom_field_values != $duplicate_custom_field_values ) {
  1059. if($is_repeated) {
  1060. //Delete the old one
  1061. delete_post_meta($duplicate_post_id, $key);
  1062. //And add new ones from the original
  1063. foreach($master_custom_field_values as $master_custom_field_value) {
  1064. add_post_meta( $duplicate_post_id, $key, addslashes_gpc(apply_filters( 'icl_duplicate_generic_string', $master_custom_field_value, $lang, array( 'context' => 'custom_field', 'attribute' => 'value', 'key' => $key ) ) ) );
  1065. }
  1066. } else {
  1067. update_post_meta( $duplicate_post_id, $key, addslashes_gpc(apply_filters( 'icl_duplicate_generic_string', $master_custom_field_value, $lang, array( 'context' => 'custom_field', 'attribute' => 'value', 'key' => $key ) ) ) );
  1068. }
  1069. }
  1070. }
  1071. return true;
  1072. }
  1073. function duplicate_fix_children( $master_post_id, $lang )
  1074. {
  1075. global $wpdb;
  1076. $post_type = $wpdb->get_var( $wpdb->prepare( "SELECT post_type FROM {$wpdb->posts} WHERE ID=%d", $master_post_id ) );
  1077. $master_children = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_parent=%d AND post_type != 'revision'", $master_post_id ) );
  1078. $dup_parent = icl_object_id( $master_post_id, $post_type, false, $lang );
  1079. if ( $master_children ) {
  1080. foreach ( $master_children as $master_child ) {
  1081. $dup_child = icl_object_id( $master_child, $post_type, false, $lang );
  1082. if ( $dup_child ) {
  1083. $wpdb->update( $wpdb->posts, array( 'post_parent' => $dup_parent ), array( 'ID' => $dup_child ) );
  1084. }
  1085. $this->duplicate_fix_children( $master_child, $lang );
  1086. }
  1087. }
  1088. }
  1089. function make_duplicates_all( $master_post_id )
  1090. {
  1091. global $sitepress;
  1092. $master_post = get_post( $master_post_id );
  1093. if($master_post->post_status == 'auto-draft' || $master_post->post_type == 'revision') {
  1094. return;
  1095. }
  1096. $language_details_original = $sitepress->get_element_language_details( $master_post_id, 'post_' . $master_post->post_type );
  1097. if(!$language_details_original) return;
  1098. $data[ 'iclpost' ] = array( $master_post_id );
  1099. foreach ( $sitepress->get_active_languages() as $lang => $details ) {
  1100. if ( $lang != $language_de

Large files files are truncated, but you can click here to view the full file