Lingotek Translation - Version 1.4.14

Version Description

(2021-07-07) = * Fixed WordPress: consume the download_interim_translation callback

Download this release

Release Info

Developer sowmiya2021
Plugin Icon 128x128 Lingotek Translation
Version 1.4.14
Comparing to
See all releases

Code changes from version 1.4.13 to 1.4.14

Files changed (72) hide show
  1. .travis.yml +71 -0
  2. admin/actions.php +368 -203
  3. admin/admin.php +154 -140
  4. admin/content-table.php +42 -31
  5. admin/custom-fields-table.php +39 -28
  6. admin/filters-columns.php +133 -127
  7. admin/filters-media.php +2 -1
  8. admin/filters-post.php +175 -162
  9. admin/filters-term.php +13 -13
  10. admin/import.php +50 -36
  11. admin/import/FormatConverter.php +206 -182
  12. admin/import/StandardImportObject.php +90 -81
  13. admin/import/import-table.php +447 -394
  14. admin/import/view-content.php +122 -109
  15. admin/import/view-settings.php +78 -64
  16. admin/manage/view-content.php +64 -66
  17. admin/manage/view-custom-fields.php +98 -88
  18. admin/manage/view-edit-profile.php +227 -184
  19. admin/manage/view-profiles.php +83 -69
  20. admin/manage/view-string-groups.php +36 -28
  21. admin/manage/view-strings.php +27 -20
  22. admin/post-actions.php +95 -97
  23. admin/profiles-table.php +35 -25
  24. admin/settings.php +20 -16
  25. admin/settings/connect-account.php +22 -22
  26. admin/settings/view-account.php +85 -77
  27. admin/settings/view-defaults.php +60 -42
  28. admin/settings/view-preferences.php +80 -73
  29. admin/settings/view-utilities.php +17 -14
  30. admin/string-actions.php +4 -6
  31. admin/strings-table.php +55 -44
  32. admin/table-string.php +18 -11
  33. admin/term-actions.php +80 -68
  34. admin/tutorial/content.php +74 -59
  35. admin/tutorial/credits.php +124 -81
  36. admin/tutorial/faq.php +28 -28
  37. admin/tutorial/features.php +17 -17
  38. admin/utilities.php +67 -52
  39. admin/view-dashboard.php +2 -2
  40. admin/view-manage.php +44 -39
  41. admin/view-network.php +114 -109
  42. admin/view-tutorial.php +32 -27
  43. admin/workflows/credit-card-to-path.php +44 -44
  44. admin/workflows/professional-translation-workflow.php +239 -260
  45. admin/workflows/workflow-factory.php +10 -10
  46. admin/workflows/workflow.php +77 -73
  47. admin/wp-import.php +7 -7
  48. bin/githook-pre-commit.sh +37 -0
  49. bin/githook-prepare-commit-msg.sh +46 -0
  50. bin/install-git-hooks.sh +25 -0
  51. bin/install-wp-tests.sh +181 -0
  52. include/api.php +729 -476
  53. include/callback.php +99 -94
  54. include/dashboard.php +169 -159
  55. include/group-post.php +264 -255
  56. include/group-string.php +75 -50
  57. include/group-term.php +55 -54
  58. include/group.php +234 -231
  59. include/http.php +69 -38
  60. include/logger.php +38 -34
  61. include/model.php +561 -474
  62. include/plugins-compat.php +12 -11
  63. include/pointer.php +29 -25
  64. js/updater.js +24 -8
  65. lingotek.php +370 -353
  66. phpcs.xml +79 -0
  67. phpunit.xml +15 -0
  68. readme.txt +5 -2
  69. tests/README.md +46 -0
  70. tests/bootstrap.php +42 -0
  71. tests/test-lingotek-installation.php +86 -0
  72. uninstall.php +17 -16
.travis.yml ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ sudo: false
2
+ dist: trusty
3
+
4
+ language: php
5
+
6
+ notifications:
7
+ email:
8
+ on_success: never
9
+ on_failure: change
10
+
11
+ branches:
12
+ only:
13
+ - master
14
+
15
+ cache:
16
+ directories:
17
+ - $HOME/.composer/cache
18
+
19
+ matrix:
20
+ include:
21
+ - php: 7.4
22
+ env: WP_VERSION=latest
23
+ - php: 7.3
24
+ env: WP_VERSION=latest
25
+ - php: 7.2
26
+ env: WP_VERSION=latest
27
+ - php: 7.1
28
+ env: WP_VERSION=latest
29
+ - php: 7.0
30
+ env: WP_VERSION=latest
31
+ - php: 5.6
32
+ env: WP_VERSION=3.8
33
+ - php: 5.6
34
+ env: WP_VERSION=latest
35
+ - php: 5.6
36
+ env: WP_VERSION=trunk
37
+ - php: 5.6
38
+ env: WP_TRAVISCI=phpcs
39
+
40
+ before_script:
41
+ - export PATH="$HOME/.composer/vendor/bin:$PATH"
42
+ - |
43
+ if [ -f ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini ]; then
44
+ phpenv config-rm xdebug.ini
45
+ else
46
+ echo "xdebug.ini does not exist"
47
+ fi
48
+ - |
49
+ if [[ ! -z "$WP_VERSION" ]] ; then
50
+ bash bin/install-wp-tests.sh wordpress_test root '' localhost $WP_VERSION
51
+ composer global require "phpunit/phpunit=4.8.*|5.7.*"
52
+ fi
53
+ - |
54
+ if [[ "$WP_TRAVISCI" == "phpcs" ]] ; then
55
+ composer global require wp-coding-standards/wpcs
56
+ composer global require phpcompatibility/php-compatibility
57
+ composer global require phpcompatibility/phpcompatibility-paragonie
58
+ composer global require phpcompatibility/phpcompatibility-wp
59
+ phpcs --config-set installed_paths $HOME/.composer/vendor/wp-coding-standards/wpcs,$HOME/.composer/vendor/phpcompatibility/php-compatibility,$HOME/.composer/vendor/phpcompatibility/phpcompatibility-paragonie,$HOME/.composer/vendor/phpcompatibility/phpcompatibility-wp
60
+ fi
61
+
62
+ script:
63
+ - |
64
+ if [[ ! -z "$WP_VERSION" ]] ; then
65
+ phpunit
66
+ WP_MULTISITE=1 phpunit
67
+ fi
68
+ - |
69
+ if [[ "$WP_TRAVISCI" == "phpcs" ]] ; then
70
+ phpcs
71
+ fi
admin/actions.php CHANGED
@@ -79,106 +79,106 @@ abstract class Lingotek_Actions {
79
  */
80
  public function __construct( $type ) {
81
  // confirm message.
82
- self::$confirm_message = sprintf( ' onclick = "return confirm(\'%s\');"', __( 'You are about to overwrite existing translations. Are you sure?', 'lingotek-translation' ) );
83
- self::$confirm_delete = sprintf(' onclick = "return confirm(\'%s\');"', __( 'Content will be deleted from WordPress. The associated content in the TMS will be cancelled. Are you sure?', 'lingotek-translation' ) );
84
- self::$confirm_cancel = sprintf(' onclick = "return confirm(\'%s\');"', __( 'You are about to cancel existing translations in your Lingotek community. Are you sure?', 'lingotek-translation' ) );
85
- self::$confirm_delete_translation = sprintf(' onclick = "return confirm(\'%s\');"', __( 'Translation will be deleted from WordPress. The associated translation in the TMS will be cancelled. Are you sure?', 'lingotek-translation' ) );
86
- self::$confirm_cancel_translation = sprintf(' onclick = "return confirm(\'%s\');"', __( 'You are about to cancel this translation in your Lingotek community. Are you sure?', 'lingotek-translation' ) );
87
  // row actions.
88
  self::$actions = array(
89
- 'upload' => array(
90
  'action' => __( 'Upload to Lingotek', 'lingotek-translation' ),
91
  'progress' => __( 'Uploading...', 'lingotek-translation' ),
92
  'description' => __( 'Upload this item to Lingotek TMS', 'lingotek-translation' ),
93
  ),
94
 
95
- 'request' => array(
96
  'action' => __( 'Request translations', 'lingotek-translation' ),
97
  'progress' => __( 'Requesting translations...', 'lingotek-translation' ),
98
  'description' => __( 'Request translations of this item to Lingotek TMS', 'lingotek-translation' ),
99
  ),
100
 
101
- 'status' => array(
102
  'action' => __( 'Update translations status', 'lingotek-translation' ),
103
  'progress' => __( 'Updating translations status...', 'lingotek-translation' ),
104
  'description' => __( 'Update translations status of this item in Lingotek TMS', 'lingotek-translation' ),
105
  ),
106
 
107
- 'download' => array(
108
  'action' => __( 'Download translations', 'lingotek-translation' ),
109
  'progress' => __( 'Downloading translations...', 'lingotek-translation' ),
110
  'description' => __( 'Download translations of this item from Lingotek TMS', 'lingotek-translation' ),
111
  ),
112
 
113
- 'cancel' => array(
114
  'action' => __( 'Cancel translations', 'lingotek-translation' ),
115
  'progress' => __( 'Cancelling translations...', 'lingotek-translation' ),
116
  'description' => __( 'Cancel the translations of this item from Lingotek TMS', 'lingotek-translation' ),
117
  ),
118
 
119
- 'delete' => array(
120
  'action' => __( 'Delete translations', 'lingotek-translation' ),
121
  'progress' => __( 'Deleting translations...', 'lingotek-translation' ),
122
  'description' => __( 'Delete the translations of this item from Lingotek TMS', 'lingotek-translation' ),
123
  ),
124
 
125
  'cancel-translation' => array(
126
- 'action' => __('Cancel translation', 'lingotek-translation'),
127
- 'progress' => __('Cancelling translation', 'lingotek-translation'),
128
- 'description' => __('Cancel this translation from Lingotek TMS', 'lingotek-translation'),
129
  ),
130
 
131
  'delete-translation' => array(
132
- 'action' => __('Delete translation', 'lingotek-translation'),
133
- 'progress' => __('Deleting translation', 'lingotek-translation'),
134
- 'description' => __('Delete this translation from Lingotek TMS', 'lingotek-translation'),
135
  ),
136
  );
137
 
138
  // action icons
139
  self::$icons = array(
140
- 'upload' => array(
141
  'title' => __( 'Upload Now', 'lingotek-translation' ),
142
  'icon' => 'upload',
143
  ),
144
 
145
- 'importing' => array(
146
  'title' => __( 'Importing source', 'lingotek-translation' ),
147
  'icon' => 'clock',
148
  ),
149
 
150
- 'failed' => array(
151
  'title' => __( 'Upload Failed. Click to re-upload', 'lingotek-translation' ),
152
  'icon' => 'no',
153
- 'class' => 'lingotek-failed-color'
154
  ),
155
 
156
- 'uploaded' => array(
157
  'title' => __( 'Source uploaded', 'lingotek-translation' ),
158
  'icon' => 'yes',
159
  ),
160
 
161
- 'request' => array(
162
  'title' => __( 'Request a translation', 'lingotek-translation' ),
163
  'icon' => 'plus',
164
  ),
165
 
166
- 'pending' => array(
167
  'title' => __( 'In Progress', 'lingotek-translation' ),
168
  'icon' => 'clock',
169
  ),
170
 
171
- 'ready' => array(
172
  'title' => __( 'Ready to download', 'lingotek-translation' ),
173
  'icon' => 'download',
174
  ),
175
 
176
- 'interim' => array(
177
- 'title' => __('Interim Translation Downloaded', 'lingotek-translation'),
178
- 'icon' => 'edit'
179
  ),
180
 
181
- 'current' => array(
182
  'title' => __( 'Current', 'lingotek-translation' ),
183
  'icon' => 'edit',
184
  ),
@@ -188,19 +188,19 @@ abstract class Lingotek_Actions {
188
  'icon' => 'edit',
189
  ),
190
 
191
- 'error' => array(
192
  'title' => __( 'There was an error contacting Lingotek', 'lingotek-translation' ),
193
  'icon' => 'no',
194
  ),
195
 
196
- 'copy' => array(
197
  'title' => __( 'Copy source language', 'lingotek-translation' ),
198
  'icon' => 'welcome-add-page',
199
  ),
200
 
201
- 'cancelled' => array(
202
- 'title' => __('Translation has been cancelled', 'lingotek-translation'),
203
- 'icon' => 'warning',
204
  ),
205
  );
206
 
@@ -213,13 +213,13 @@ abstract class Lingotek_Actions {
213
  add_action( 'wp_ajax_estimate_cost', array( &$this, 'ajax_estimate_cost' ) );
214
  add_action( 'wp_ajax_request_professional_translation', array( &$this, 'ajax_request_professional_translation' ) );
215
  add_action( 'wp_ajax_get_user_payment_information', array( &$this, 'ajax_get_user_payment_information' ) );
216
- add_action( 'wp_ajax_get_ltk_terms_and_conditions', array( &$this, 'ajax_get_ltk_terms_and_conditions' ) );
217
 
218
  foreach ( array_keys( self::$actions ) as $action ) {
219
- if(strpos($action, '-translation')){
220
  continue;
221
  }
222
- add_action( 'wp_ajax_lingotek_progress_' . $this->type . '_' . $action , array( &$this, 'ajax_' . $action ) );
223
  }
224
  }
225
 
@@ -229,12 +229,12 @@ abstract class Lingotek_Actions {
229
  * @since 0.1
230
  *
231
  * @param string $document_id
232
- * @param string $locale Lingotek locale
233
- * @return string workbench link
234
  */
235
  public static function workbench_link( $document_id, $locale ) {
236
- $document_id = $document_id ?: '';
237
- $locale = $locale ? Lingotek::map_to_lingotek_locale($locale) : '';
238
  return Lingotek_API::PRODUCTION_URL . "/workbench/document/$document_id/locale/$locale";
239
  }
240
 
@@ -245,16 +245,28 @@ abstract class Lingotek_Actions {
245
  *
246
  * @param string $name
247
  * @param string $link
248
- * @param string $additional parameters to add (js, target)
249
  */
250
  public static function display_icon( $name, $link, $additional = '' ) {
251
- self::link_to_settings_if_not_connected($link);
252
- if ($name == 'interim') {
253
- return sprintf('<a class="lingotek-interim-color dashicons dashicons-%s dashicons-%s-lingotek" title="%s" href="%s"%s></a>',
254
- self::$icons[ $name ]['icon'], self::$icons[ $name ]['icon'], self::$icons[ $name ]['title'], esc_url( $link ), $additional);
 
 
 
 
 
 
255
  }
256
- return sprintf('<a class="lingotek-color dashicons dashicons-%s dashicons-%s-lingotek" title="%s" href="%s"%s></a>',
257
- self::$icons[ $name ]['icon'], self::$icons[ $name ]['icon'], self::$icons[ $name ]['title'], esc_url( $link ), $additional);
 
 
 
 
 
 
258
  }
259
 
260
  /**
@@ -263,65 +275,83 @@ abstract class Lingotek_Actions {
263
  * @since 1.2
264
  *
265
  * @param string $name
266
- * @param string $additional parameters to add (js, target)
 
267
  */
268
  public static function display_error_icon( $name, $api_error, $additional = '' ) {
269
- return sprintf('<span class="lingotek-error dashicons dashicons-%s" title="%s"></span>',
270
- self::$icons[ $name ]['icon'], self::$icons[ $name ]['title'] . "\n" . $api_error, $additional);
 
 
 
 
271
  }
272
-
273
  /**
274
  * Outputs an upload icon
275
  *
276
  * @since 0.2
277
  *
278
  * @param int|string $object_id
279
- * @param bool $warning
280
  */
281
  public function upload_icon( $object_id, $confirm = false ) {
282
- $args = array( $this->type => $object_id, 'action' => 'lingotek-upload', 'noheader' => true );
283
- if (isset($args['string'])) {
284
- $args['string'] = urlencode($args['string']);
 
 
 
 
285
  }
286
  $link = wp_nonce_url( defined( 'DOING_AJAX' ) && DOING_AJAX ? add_query_arg( $args, wp_get_referer() ) : add_query_arg( $args ), 'lingotek-upload' );
287
- self::link_to_settings_if_not_connected($link);
288
  return self::display_icon( 'upload', $link, $confirm ? self::$confirm_message : '' );
289
  }
290
 
291
- /**
292
  * Outputs a cancelled icon
293
  *
294
  * @since 1.4.13
295
  *
296
  * @param int|string $object_id
297
  * id of the object
298
- * @param bool $target
299
  * boolean to show if icon is for a target or source document
300
- * @param bool $confirm
301
  * boolean to enable the cancel confirm pop up
302
  */
303
  public function cancelled_icon( $object_id, $target = false, $confirm = false ) {
304
  $action = $target ? 'edit' : 'lingotek-upload';
305
- $args = array( $this->type => $object_id, 'action' => $action, 'noheader' => true );
306
- if (isset($args['string'])) {
307
- $args['string'] = urlencode($args['string']);
 
 
 
 
308
  }
309
- $link = wp_nonce_url( defined( 'DOING_AJAX' ) && DOING_AJAX ? add_query_arg( $args, wp_get_referer() ) : add_query_arg( $args ), $action);
310
- self::link_to_settings_if_not_connected($link);
311
- return self::display_icon( 'cancelled', $link, $confirm ? self::$confirm_message : '');
312
  }
313
 
314
  /**
315
  * Outputs a copy icon
316
  *
317
  * @param int|string $object_id
318
- * @param string $target
319
- * @param bool $warning
320
  */
321
  public function copy_icon( $object_id, $target, $confirm = false ) {
322
- $args = array( $this->type => $object_id, 'target' => $target, 'action' => 'lingotek-copy', 'noheader' => true );
 
 
 
 
 
323
  $link = wp_nonce_url( defined( 'DOING_AJAX' ) && DOING_AJAX ? add_query_arg( $args, wp_get_referer() ) : add_query_arg( $args ), 'lingotek-copy' );
324
- self::link_to_settings_if_not_connected($link);
325
  return self::display_icon( 'copy', $link, $confirm ? self::$confirm_message : '' );
326
  }
327
 
@@ -333,9 +363,13 @@ abstract class Lingotek_Actions {
333
  * @param object $document
334
  */
335
  public static function importing_icon( $document ) {
336
- $args = array( 'document_id' => $document->document_id, 'action' => 'lingotek-status', 'noheader' => true );
 
 
 
 
337
  $link = wp_nonce_url( defined( 'DOING_AJAX' ) && DOING_AJAX ? add_query_arg( $args, wp_get_referer() ) : add_query_arg( $args ), 'lingotek-status' );
338
- self::link_to_settings_if_not_connected($link);
339
  return self::display_icon( 'importing', $link );
340
  }
341
 
@@ -350,41 +384,71 @@ abstract class Lingotek_Actions {
350
  public static function translation_icon( $document, $language ) {
351
  if ( isset( $document->translations[ $language->locale ] ) ) {
352
  if ( 'ready' === $document->translations[ $language->locale ] ) {
353
- $link = wp_nonce_url( add_query_arg( array( 'document_id' => $document->document_id, 'locale' => $language->locale, 'action' => 'lingotek-download', 'noheader' => true ) ), 'lingotek-download' );
354
- self::link_to_settings_if_not_connected($link);
 
 
 
 
 
 
 
 
 
 
355
  return self::display_icon( $document->translations[ $language->locale ], $link );
356
  } elseif ( 'not-current' === $document->translations[ $language->locale ] ) {
357
  return '<div class="lingotek-color dashicons dashicons-no"></div>';
358
- } elseif ('current' !== $document->translations[ $language->locale ] && $custom_icon = $document->get_custom_in_progress_icon($language)) {
 
359
  return $custom_icon;
360
  } else {
361
  $link = self::workbench_link( $document->document_id, $language->lingotek_locale );
362
- self::link_to_settings_if_not_connected($link);
363
  return self::display_icon( $document->translations[ $language->locale ], $link, ' target="_blank"' );
364
- }
365
  } else {
366
- $link = wp_nonce_url( add_query_arg( array( 'document_id' => $document->document_id, 'locale' => $language->locale, 'action' => 'lingotek-request', 'noheader' => true ), defined( 'DOING_AJAX' ) && DOING_AJAX ? wp_get_referer() : wp_get_referer() ), 'lingotek-request' );
367
- self::link_to_settings_if_not_connected($link);
 
 
 
 
 
 
 
 
 
 
 
368
  return self::display_icon( 'request', $link );
369
- }
370
  }
371
 
372
  /**
373
  * Outputs icon for failed import callback
374
  *
375
  * @since 1.4.3
376
- *
377
  */
378
- public function failed_import_icon($name, $object_id) {
379
- $args = array( $this->type => $object_id, 'action' => 'lingotek-upload', 'noheader' => true );
380
- if (isset($args['string'])) {
381
- $args['string'] = urlencode($args['string']);
 
 
 
 
382
  }
383
  $link = wp_nonce_url( defined( 'DOING_AJAX' ) && DOING_AJAX ? add_query_arg( $args, wp_get_referer() ) : add_query_arg( $args ), 'lingotek-upload' );
384
- self::link_to_settings_if_not_connected($link);
385
 
386
- return sprintf('<a class="%s dashicons dashicons-%s" title="%s" href="%s"></a>',
387
- self::$icons[ $name ]['class'], self::$icons[ $name ]['icon'], self::$icons[ $name ]['title'], esc_url($link));
 
 
 
 
 
388
  }
389
 
390
  /**
@@ -392,36 +456,36 @@ abstract class Lingotek_Actions {
392
  *
393
  * @since 0.2
394
  *
395
- * @param array $args parameters to add to the link
396
- * @param bool $warning whether to display an alert or not, optional, defaults to false
397
  * @return string
398
  */
399
  protected function get_action_link( $args, $warning = false ) {
400
- $action = $args['action'];
401
- $args['action'] = 'lingotek-' . $action;
402
  $args['noheader'] = true;
403
- if (isset($args['string'])) {
404
- $args['string'] = urlencode($args['string']);
405
  }
406
  $link = wp_nonce_url( defined( 'DOING_AJAX' ) && DOING_AJAX ? add_query_arg( $args, wp_get_referer() ) : add_query_arg( $args ), 'lingotek-' . $action );
407
- self::link_to_settings_if_not_connected($link);
408
-
409
- switch($action){
410
  case 'delete-translation':
411
  $message = self::$confirm_delete_translation;
412
- break;
413
  case 'delete':
414
  $message = self::$confirm_delete;
415
- break;
416
  case 'cancel-translation':
417
  $message = self::$confirm_cancel_translation;
418
- break;
419
  case 'cancel':
420
  $message = self::$confirm_cancel;
421
- break;
422
  default:
423
  $message = self::$confirm_message;
424
- break;
425
  }
426
 
427
  return sprintf(
@@ -433,10 +497,9 @@ abstract class Lingotek_Actions {
433
  );
434
  }
435
 
436
- private static function link_to_settings_if_not_connected(&$link)
437
- {
438
- if (! get_option('lingotek_token') || ! get_option('lingotek_community')) {
439
- $link = get_site_url(null, '/wp-admin/admin.php?page=lingotek-translation_settings');
440
  }
441
  }
442
 
@@ -445,8 +508,8 @@ abstract class Lingotek_Actions {
445
  *
446
  * @since 0.2
447
  *
448
- * @param array $actions list of action links
449
- * @param $id object id
450
  * @return array
451
  */
452
  protected function _row_actions( $actions, $id ) {
@@ -455,19 +518,22 @@ abstract class Lingotek_Actions {
455
  return $actions;
456
  }
457
  $document = $this->lgtm->get_group( $this->type, $id );
458
-
459
  $target_id = $id;
460
- if ( $this->type !== 'string' && isset( $document->desc_array['lingotek']['source'] ) ) {
461
  $id = $document->desc_array['lingotek']['source'];
462
  }
463
 
464
- if ( $this->lgtm->can_upload( $this->type, $id ) || (isset( $document->source ) && 'string' !== $this->type && $this->lgtm->can_upload( $this->type, $document->source )) ) {
465
  if ( $document ) {
466
  $desc_array = $document->desc_array;
467
  unset( $desc_array['lingotek'] );
468
- $data = array( $this->type => $id, 'action' => 'upload' );
 
 
 
469
  if ( count( $desc_array ) >= 2 ) {
470
- $actions['lingotek-upload'] = $this->get_action_link( $data , true );
471
  } else {
472
  $actions['lingotek-upload'] = $this->get_action_link( $data );
473
  }
@@ -477,29 +543,55 @@ abstract class Lingotek_Actions {
477
  * update translation status option.
478
  */
479
  if ( 'importing' === $document->status || $document->has_translation_status( 'pending' ) ) {
480
- $actions['lingotek-status'] = $this->get_action_link( array( 'document_id' => $document->document_id, 'action' => 'status' ) );
 
 
 
 
 
481
  }
482
 
483
  if ( $document->has_translation_status( 'ready' ) ) {
484
- $actions['lingotek-download'] = $this->get_action_link( array( 'document_id' => $document->document_id, 'action' => 'download' ) );
 
 
 
 
 
485
  }
486
  } else {
487
- $actions['lingotek-upload'] = $this->get_action_link( array( $this->type => $id, 'action' => 'upload' ) );
488
- }
 
 
 
 
 
489
  } elseif ( isset( $document->translations ) ) {
490
  // translations to download ?
491
  if ( $document->has_translation_status( 'ready' ) ) {
492
- $actions['lingotek-download'] = $this->get_action_link( array( 'document_id' => $document->document_id, 'action' => 'download' ) );
 
 
 
 
 
493
  }
494
 
495
- if ($document->has_translation_status('interim')) {
496
- $actions['lingotek-status'] = $this->get_action_link( array( 'document_id' => $document->document_id, 'action' => 'status' ) );
 
 
 
 
 
497
  }
498
 
499
  //need to request translations?
500
- $language = $this->get_language( $document->source );
501
  $all_locales = array_flip( $this->pllm->get_languages_list( array( 'fields' => 'locale' ) ) );
502
- if ( ! empty( $language ) ) { // in case a language has been deleted
 
503
  unset( $all_locales[ $language->locale ] );
504
  }
505
  $untranslated = array_diff_key( $all_locales, $document->translations );
@@ -512,25 +604,70 @@ abstract class Lingotek_Actions {
512
  }
513
 
514
  if ( 'current' === $document->status && ! empty( $untranslated ) ) {
515
- $actions['lingotek-request'] = $this->get_action_link( array( 'document_id' => $document->document_id, 'action' => 'request' ) );
 
 
 
 
 
516
  }
517
 
518
  // offers to update translations status
519
  if ( 'importing' === $document->status || $document->has_translation_status( 'pending' ) ) {
520
- $actions['lingotek-status'] = $this->get_action_link( array( 'document_id' => $document->document_id, 'action' => 'status' ) );
 
 
 
 
 
521
  }
522
  } elseif ( empty( $document->source ) ) {
523
- $actions['lingotek-upload'] = $this->get_action_link( array( $this->type => $id, 'action' => 'upload' ), true );
524
- }
525
-
526
- $target_locale = $this->get_language($target_id)->locale;
527
- if ( $id == $target_id && isset( $document->source ) && $document->status !== 'cancelled' ) {
528
- $actions['lingotek-cancel'] = $this->get_action_link( array( 'document_id' => $document->document_id, 'action' => 'cancel' ), true );
529
- $actions['lingotek-delete'] = $this->get_action_link( array( 'document_id' => $document->document_id, 'action' => 'delete' ), true );
530
- } else if ( isset($document->source) && isset($document->translations[$target_locale]) && $document->translations[$target_locale] != 'cancelled' ) {
531
- $actions['lingotek-cancel-translation'] = $this->get_action_link(array('document_id' => $document->document_id, 'target_id' => $target_id, 'target_locale' => $target_locale, 'action' => 'cancel-translation'), true);
532
- $actions['lingotek-delete-translation'] = $this->get_action_link(array('document_id' => $document->document_id, 'target_id' => $target_id, 'target_locale' => $target_locale, 'action' => 'delete-translation'), true);
533
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
534
 
535
  return $actions;
536
  }
@@ -544,9 +681,10 @@ abstract class Lingotek_Actions {
544
  */
545
  protected function _add_bulk_actions( $bulk_actions ) {
546
  foreach ( self::$actions as $action => $strings ) {
547
- if(strpos($action, '-translation')){
548
  continue;
549
  }
 
550
  $bulk_actions[ 'bulk-lingotek-' . $action ] = __( $strings['action'], $action );
551
  if ( null !== filter_input( INPUT_GET, 'bulk-lingotek-' . $action ) ) {
552
  $text = $strings['progress'];
@@ -561,27 +699,29 @@ abstract class Lingotek_Actions {
561
 
562
  /**
563
  * Outputs javascript data for progress.js
564
- * wp_localize_script($handle, $name, $data) $handle needs to be lingotek_myhandle
565
- * where myhandle is handle of script you loaded previously with wp_enqueue_script (probably in admin.php)
566
  *
567
  * @since 0.1
568
  */
569
  public function admin_enqueue_scripts() {
570
  foreach ( array_keys( self::$actions ) as $action ) {
571
  if ( null !== filter_input( INPUT_GET, "bulk-lingotek-$action" ) ) {
572
- $action_message = $action === 'delete' ? 'cancel' : $action;
573
- $data = array(
574
- 'action' => null === filter_input( INPUT_GET, 'page' ) ? (null === filter_input( INPUT_GET, 'taxonomy' ) ? "post_$action" : "term_$action") : "string_$action",
575
  'taxonomy' => null === filter_input( INPUT_GET, 'taxonomy' ) || ! taxonomy_exists( wp_unslash( filter_input( INPUT_GET, 'taxonomy' ) ) ) ? '' : filter_input( INPUT_GET, 'taxonomy' ),
576
- 'sendback' => remove_query_arg( array( "bulk-lingotek-$action", 'ids', 'lingotek_warning', 'locales'), wp_get_referer() ),
577
  'ids' => array_map( 'intval', explode( ',', filter_input( INPUT_GET, 'ids' ) ) ),
578
- 'warning' => null === filter_input( INPUT_GET, 'lingotek_warning' ) ? (null === filter_input(INPUT_GET, 'lingotek_remove') ? '' : __("You are about to $action_message existing translations from your Lingotek community. Are you sure?", 'lingotek-translation')) : __( 'You are about to overwrite existing translations. Are you sure?', 'lingotek-translation' ),
 
 
579
  'nonce' => wp_create_nonce( 'lingotek_progress' ),
580
  );
581
- if (null!== filter_input( INPUT_GET, 'locales')){
582
- $data['locales'] = explode( ',', filter_input( INPUT_GET, 'locales'));
583
  }
584
- wp_localize_script('lingotek_progress', 'lingotek_data', $data);
585
  return;
586
  }
587
  }
@@ -592,13 +732,13 @@ abstract class Lingotek_Actions {
592
  *
593
  * @since 0.2
594
  *
595
- * @param string $action action name
596
- * @return bool true if the action was managed, false otherwise
597
  */
598
  protected function _manage_actions( $action ) {
599
  if ( null !== filter_input( INPUT_GET, 'document_id' ) ) {
600
  $document_id = filter_input( INPUT_GET, 'document_id' );
601
- $document = $this->lgtm->get_group_by_id( $document_id );
602
  }
603
 
604
  switch ( $action ) {
@@ -610,13 +750,31 @@ abstract class Lingotek_Actions {
610
 
611
  case 'lingotek-request':
612
  check_admin_referer( 'lingotek-request' );
613
- Lingotek_Logger::info("User requested to translate an item", array("document_id" => isset($document_id) ? $document_id : "", "locale" => filter_input( INPUT_GET, 'locale' )));
 
 
 
 
 
 
 
 
 
614
  null !== filter_input( INPUT_GET, 'locale' ) ? $document->request_translation( filter_input( INPUT_GET, 'locale' ) ) : $document->request_translations();
615
  break;
616
 
617
  case 'lingotek-download':
618
  check_admin_referer( 'lingotek-download' );
619
- Lingotek_Logger::info("User requested to download translation", array("document_id"=> isset($document_id) ? $document_id : "", "locale" => filter_input( INPUT_GET, 'locale' )));
 
 
 
 
 
 
 
 
 
620
  null !== filter_input( INPUT_GET, 'locale' ) ? $document->create_translation( filter_input( INPUT_GET, 'locale' ) ) : $document->create_translations();
621
  break;
622
 
@@ -632,7 +790,7 @@ abstract class Lingotek_Actions {
632
  exit();
633
  }
634
  break;
635
-
636
  case 'lingotek-cancel':
637
  check_admin_referer( 'lingotek-cancel' );
638
  $document->cancel();
@@ -644,34 +802,34 @@ abstract class Lingotek_Actions {
644
  break;
645
 
646
  case 'lingotek-delete-translation':
647
- check_admin_referer('lingotek-delete-translation');
648
- $target_locale = filter_input(INPUT_GET, 'target_locale');
649
- $target_id = filter_input(INPUT_GET, 'target_id');
650
- $language = PLL()->model->post->get_language($target_id);
651
- $document->delete_translation($language, $target_id);
652
- if(null !== filter_input(INPUT_GET, 'lingotek_redirect') && filter_input(INPUT_GET, 'lingotek_redirect') === true) {
653
  $site_id = get_current_blog_id();
654
- wp_safe_redirect(get_site_url($site_id, '/wp-admin/edit.php?post_type=page'));
655
  exit();
656
  }
657
  break;
658
 
659
  case 'lingotek-cancel-translation':
660
- check_admin_referer('lingotek-cancel-translation');
661
- $target_locale = filter_input(INPUT_GET, 'target_locale');
662
- $target_id = filter_input(INPUT_GET, 'target_id');
663
- $language = PLL()->model->post->get_language($target_id);
664
- $document->cancel_translation($language, $target_id);
665
- if(null !== filter_input(INPUT_GET, 'lingotek_redirect') && filter_input(INPUT_GET, 'lingotek_redirect') === true) {
666
  $site_id = get_current_blog_id();
667
- wp_safe_redirect(get_site_url($site_id, '/wp-admin/edit.php?post_type=page'));
668
  exit();
669
  }
670
  break;
671
-
672
  default:
673
  return false;
674
- }
675
 
676
  return true;
677
  }
@@ -683,9 +841,10 @@ abstract class Lingotek_Actions {
683
  */
684
  public function ajax_download() {
685
  check_ajax_referer( 'lingotek_progress', '_lingotek_nonce' );
686
- if ( $document = $this->lgtm->get_group( $this->type, filter_input( INPUT_POST, 'id' ) ) ) {
 
687
  foreach ( $document->translations as $locale => $status ) {
688
- if ( 'pending' === $status || 'ready' === $status || 'interim' === $status || 'current' === $status) {
689
  $document->create_translation( $locale );
690
  }
691
  }
@@ -700,7 +859,8 @@ abstract class Lingotek_Actions {
700
  */
701
  public function ajax_request() {
702
  check_ajax_referer( 'lingotek_progress', '_lingotek_nonce' );
703
- if ( $document = $this->lgtm->get_group( $this->type, filter_input( INPUT_POST, 'id' ) ) ) {
 
704
  $document->request_translations();
705
  }
706
  die();
@@ -713,7 +873,8 @@ abstract class Lingotek_Actions {
713
  */
714
  public function ajax_status() {
715
  check_ajax_referer( 'lingotek_progress', '_lingotek_nonce' );
716
- if ( $document = $this->lgtm->get_group( $this->type, filter_input( INPUT_POST, 'id' ) ) ) {
 
717
  $document->source_status();
718
  $document->translations_status();
719
  }
@@ -727,33 +888,36 @@ abstract class Lingotek_Actions {
727
  */
728
  public function ajax_delete() {
729
  check_ajax_referer( 'lingotek_progress', '_lingotek_nonce' );
730
- $id = filter_input(INPUT_POST, 'id');
731
- $language = PLL()->model->post->get_language($id);
732
  $document = $this->lgtm->get_group( $this->type, $id );
 
733
  if ( $document && $document->source == $id ) {
734
  /**it was left as disassociate so that the delete functionality wouldn't break as it
735
  * did when changing disassociate to delete/cancel in other connectors
736
  */
737
  $document->delete();
738
- } else if ($document && $document->source != $id && $language) {
739
- $document->delete_translation($language, $id);
 
740
  }
741
  die();
742
  }
743
 
744
  /**
745
  * Ajax response cancel translations and showing progress
746
- *
747
  */
748
  public function ajax_cancel() {
749
  check_ajax_referer( 'lingotek_progress', '_lingotek_nonce' );
750
- $id = filter_input(INPUT_POST, 'id');
751
- $language = PLL()->model->post->get_language($id);
752
- $document = $this->lgtm->get_group( $this->type, $id);
 
753
  if ( $document && $document->source == $id ) {
754
  $document->cancel();
755
- } else if ($document && $document->source != $id && $language){
756
- $document->cancel_translation($language, $id);
 
757
  }
758
  die();
759
  }
@@ -763,29 +927,30 @@ abstract class Lingotek_Actions {
763
  */
764
  public function ajax_estimate_cost() {
765
  check_ajax_referer( 'lingotek_professional', '_lingotek_nonce' );
766
- $document_id = filter_input( INPUT_GET, 'document_id' );
767
- $locale = filter_input( INPUT_GET, 'locale' );
768
  $lingotek_auth = filter_input( INPUT_GET, 'Authorization-Lingotek' );
769
- $client = new Lingotek_API();
770
- $response = $client->get_cost_estimate($lingotek_auth, $document_id, $locale);
771
- echo json_encode($response);
772
  die();
773
  }
774
 
775
  /**
776
- * Ajax call to request professional translation of a document through bridge.
777
- */
778
  public function ajax_request_professional_translation() {
779
  check_ajax_referer( 'lingotek_professional', '_lingotek_nonce' );
780
- $post_vars = filter_input_array(INPUT_POST);
781
- $client = new Lingotek_API();
782
- $response = $client->request_professional_translation_bulk($post_vars['workflow_id'], $post_vars['translations'], $post_vars['total_estimate'], $post_vars['summary']);
783
- if (true === $response['data']['transaction_approved']) {
784
- foreach ($post_vars['translations'] as $document_id => $locales) {
785
- if ( $document = $this->lgtm->get_group( $post_vars['type'], $post_vars['ids'][$document_id] ) ) {
786
- foreach ($locales as $locale) {
787
- $locale = $post_vars['lingotek_locale_to_wp_locale'][$locale];
788
- $document->update_translation_status($locale, 'pending');
 
789
  }
790
  } else {
791
  // TODO: what if a document doesn't exists? T_T
@@ -793,22 +958,22 @@ abstract class Lingotek_Actions {
793
  }
794
  }
795
 
796
- echo json_encode($response);
797
  die();
798
  }
799
 
800
  public function ajax_get_ltk_terms_and_conditions() {
801
  check_ajax_referer( 'lingotek_professional', '_lingotek_nonce' );
802
  $client = new Lingotek_API();
803
- echo json_encode($client->get_lingotek_terms_and_conditions());
804
  die();
805
  }
806
 
807
  public function ajax_get_user_payment_information() {
808
  check_ajax_referer( 'lingotek_professional', '_lingotek_nonce' );
809
- $client = new Lingotek_API();
810
  $response = $client->get_user_payment_information();
811
- echo json_encode($response);
812
  die();
813
  }
814
 
@@ -817,7 +982,7 @@ abstract class Lingotek_Actions {
817
  *
818
  * @since 1.1
819
  *
820
- * @param string errors
821
  */
822
  public static function retrieve_api_error( $errors ) {
823
  $api_error = "\n";
79
  */
80
  public function __construct( $type ) {
81
  // confirm message.
82
+ self::$confirm_message = sprintf( ' onclick = "return confirm(\'%s\');"', __( 'You are about to overwrite existing translations. Are you sure?', 'lingotek-translation' ) );
83
+ self::$confirm_delete = sprintf( ' onclick = "return confirm(\'%s\');"', __( 'Content will be deleted from WordPress. The associated content in the TMS will be cancelled. Are you sure?', 'lingotek-translation' ) );
84
+ self::$confirm_cancel = sprintf( ' onclick = "return confirm(\'%s\');"', __( 'You are about to cancel existing translations in your Lingotek community. Are you sure?', 'lingotek-translation' ) );
85
+ self::$confirm_delete_translation = sprintf( ' onclick = "return confirm(\'%s\');"', __( 'Translation will be deleted from WordPress. The associated translation in the TMS will be cancelled. Are you sure?', 'lingotek-translation' ) );
86
+ self::$confirm_cancel_translation = sprintf( ' onclick = "return confirm(\'%s\');"', __( 'You are about to cancel this translation in your Lingotek community. Are you sure?', 'lingotek-translation' ) );
87
  // row actions.
88
  self::$actions = array(
89
+ 'upload' => array(
90
  'action' => __( 'Upload to Lingotek', 'lingotek-translation' ),
91
  'progress' => __( 'Uploading...', 'lingotek-translation' ),
92
  'description' => __( 'Upload this item to Lingotek TMS', 'lingotek-translation' ),
93
  ),
94
 
95
+ 'request' => array(
96
  'action' => __( 'Request translations', 'lingotek-translation' ),
97
  'progress' => __( 'Requesting translations...', 'lingotek-translation' ),
98
  'description' => __( 'Request translations of this item to Lingotek TMS', 'lingotek-translation' ),
99
  ),
100
 
101
+ 'status' => array(
102
  'action' => __( 'Update translations status', 'lingotek-translation' ),
103
  'progress' => __( 'Updating translations status...', 'lingotek-translation' ),
104
  'description' => __( 'Update translations status of this item in Lingotek TMS', 'lingotek-translation' ),
105
  ),
106
 
107
+ 'download' => array(
108
  'action' => __( 'Download translations', 'lingotek-translation' ),
109
  'progress' => __( 'Downloading translations...', 'lingotek-translation' ),
110
  'description' => __( 'Download translations of this item from Lingotek TMS', 'lingotek-translation' ),
111
  ),
112
 
113
+ 'cancel' => array(
114
  'action' => __( 'Cancel translations', 'lingotek-translation' ),
115
  'progress' => __( 'Cancelling translations...', 'lingotek-translation' ),
116
  'description' => __( 'Cancel the translations of this item from Lingotek TMS', 'lingotek-translation' ),
117
  ),
118
 
119
+ 'delete' => array(
120
  'action' => __( 'Delete translations', 'lingotek-translation' ),
121
  'progress' => __( 'Deleting translations...', 'lingotek-translation' ),
122
  'description' => __( 'Delete the translations of this item from Lingotek TMS', 'lingotek-translation' ),
123
  ),
124
 
125
  'cancel-translation' => array(
126
+ 'action' => __( 'Cancel translation', 'lingotek-translation' ),
127
+ 'progress' => __( 'Cancelling translation', 'lingotek-translation' ),
128
+ 'description' => __( 'Cancel this translation from Lingotek TMS', 'lingotek-translation' ),
129
  ),
130
 
131
  'delete-translation' => array(
132
+ 'action' => __( 'Delete translation', 'lingotek-translation' ),
133
+ 'progress' => __( 'Deleting translation', 'lingotek-translation' ),
134
+ 'description' => __( 'Delete this translation from Lingotek TMS', 'lingotek-translation' ),
135
  ),
136
  );
137
 
138
  // action icons
139
  self::$icons = array(
140
+ 'upload' => array(
141
  'title' => __( 'Upload Now', 'lingotek-translation' ),
142
  'icon' => 'upload',
143
  ),
144
 
145
+ 'importing' => array(
146
  'title' => __( 'Importing source', 'lingotek-translation' ),
147
  'icon' => 'clock',
148
  ),
149
 
150
+ 'failed' => array(
151
  'title' => __( 'Upload Failed. Click to re-upload', 'lingotek-translation' ),
152
  'icon' => 'no',
153
+ 'class' => 'lingotek-failed-color',
154
  ),
155
 
156
+ 'uploaded' => array(
157
  'title' => __( 'Source uploaded', 'lingotek-translation' ),
158
  'icon' => 'yes',
159
  ),
160
 
161
+ 'request' => array(
162
  'title' => __( 'Request a translation', 'lingotek-translation' ),
163
  'icon' => 'plus',
164
  ),
165
 
166
+ 'pending' => array(
167
  'title' => __( 'In Progress', 'lingotek-translation' ),
168
  'icon' => 'clock',
169
  ),
170
 
171
+ 'ready' => array(
172
  'title' => __( 'Ready to download', 'lingotek-translation' ),
173
  'icon' => 'download',
174
  ),
175
 
176
+ 'interim' => array(
177
+ 'title' => __( 'Interim Translation Downloaded', 'lingotek-translation' ),
178
+ 'icon' => 'edit',
179
  ),
180
 
181
+ 'current' => array(
182
  'title' => __( 'Current', 'lingotek-translation' ),
183
  'icon' => 'edit',
184
  ),
188
  'icon' => 'edit',
189
  ),
190
 
191
+ 'error' => array(
192
  'title' => __( 'There was an error contacting Lingotek', 'lingotek-translation' ),
193
  'icon' => 'no',
194
  ),
195
 
196
+ 'copy' => array(
197
  'title' => __( 'Copy source language', 'lingotek-translation' ),
198
  'icon' => 'welcome-add-page',
199
  ),
200
 
201
+ 'cancelled' => array(
202
+ 'title' => __( 'Translation has been cancelled', 'lingotek-translation' ),
203
+ 'icon' => 'warning',
204
  ),
205
  );
206
 
213
  add_action( 'wp_ajax_estimate_cost', array( &$this, 'ajax_estimate_cost' ) );
214
  add_action( 'wp_ajax_request_professional_translation', array( &$this, 'ajax_request_professional_translation' ) );
215
  add_action( 'wp_ajax_get_user_payment_information', array( &$this, 'ajax_get_user_payment_information' ) );
216
+ add_action( 'wp_ajax_get_ltk_terms_and_conditions', array( &$this, 'ajax_get_ltk_terms_and_conditions' ) );
217
 
218
  foreach ( array_keys( self::$actions ) as $action ) {
219
+ if ( strpos( $action, '-translation' ) ) {
220
  continue;
221
  }
222
+ add_action( 'wp_ajax_lingotek_progress_' . $this->type . '_' . $action, array( &$this, 'ajax_' . $action ) );
223
  }
224
  }
225
 
229
  * @since 0.1
230
  *
231
  * @param string $document_id
232
+ * @param string $locale Lingotek locale.
233
+ * @return string Workbench link.
234
  */
235
  public static function workbench_link( $document_id, $locale ) {
236
+ $document_id = ! empty( $document_id ) ? $document_id : '';
237
+ $locale = $locale ? Lingotek::map_to_lingotek_locale( $locale ) : '';
238
  return Lingotek_API::PRODUCTION_URL . "/workbench/document/$document_id/locale/$locale";
239
  }
240
 
245
  *
246
  * @param string $name
247
  * @param string $link
248
+ * @param string $additional Parameters to add (js, target).
249
  */
250
  public static function display_icon( $name, $link, $additional = '' ) {
251
+ self::link_to_settings_if_not_connected( $link );
252
+ if ( 'interim' === $name ) {
253
+ return sprintf(
254
+ '<a class="lingotek-interim-color dashicons dashicons-%s dashicons-%s-lingotek" title="%s" href="%s"%s></a>',
255
+ self::$icons[ $name ]['icon'],
256
+ self::$icons[ $name ]['icon'],
257
+ self::$icons[ $name ]['title'],
258
+ esc_url( $link ),
259
+ $additional
260
+ );
261
  }
262
+ return sprintf(
263
+ '<a class="lingotek-color dashicons dashicons-%s dashicons-%s-lingotek" title="%s" href="%s"%s></a>',
264
+ self::$icons[ $name ]['icon'],
265
+ self::$icons[ $name ]['icon'],
266
+ self::$icons[ $name ]['title'],
267
+ esc_url( $link ),
268
+ $additional
269
+ );
270
  }
271
 
272
  /**
275
  * @since 1.2
276
  *
277
  * @param string $name
278
+ * @param string $api_error
279
+ * @param string $additional Parameters to add (js, target).
280
  */
281
  public static function display_error_icon( $name, $api_error, $additional = '' ) {
282
+ return sprintf(
283
+ '<span class="lingotek-error dashicons dashicons-%s" title="%s"></span>',
284
+ self::$icons[ $name ]['icon'],
285
+ self::$icons[ $name ]['title'] . "\n" . $api_error,
286
+ $additional
287
+ );
288
  }
289
+
290
  /**
291
  * Outputs an upload icon
292
  *
293
  * @since 0.2
294
  *
295
  * @param int|string $object_id
296
+ * @param bool $confirm
297
  */
298
  public function upload_icon( $object_id, $confirm = false ) {
299
+ $args = array(
300
+ $this->type => $object_id,
301
+ 'action' => 'lingotek-upload',
302
+ 'noheader' => true,
303
+ );
304
+ if ( isset( $args['string'] ) ) {
305
+ $args['string'] = rawurlencode( $args['string'] );
306
  }
307
  $link = wp_nonce_url( defined( 'DOING_AJAX' ) && DOING_AJAX ? add_query_arg( $args, wp_get_referer() ) : add_query_arg( $args ), 'lingotek-upload' );
308
+ self::link_to_settings_if_not_connected( $link );
309
  return self::display_icon( 'upload', $link, $confirm ? self::$confirm_message : '' );
310
  }
311
 
312
+ /**
313
  * Outputs a cancelled icon
314
  *
315
  * @since 1.4.13
316
  *
317
  * @param int|string $object_id
318
  * id of the object
319
+ * @param bool $target
320
  * boolean to show if icon is for a target or source document
321
+ * @param bool $confirm
322
  * boolean to enable the cancel confirm pop up
323
  */
324
  public function cancelled_icon( $object_id, $target = false, $confirm = false ) {
325
  $action = $target ? 'edit' : 'lingotek-upload';
326
+ $args = array(
327
+ $this->type => $object_id,
328
+ 'action' => $action,
329
+ 'noheader' => true,
330
+ );
331
+ if ( isset( $args['string'] ) ) {
332
+ $args['string'] = rawurlencode( $args['string'] );
333
  }
334
+ $link = wp_nonce_url( defined( 'DOING_AJAX' ) && DOING_AJAX ? add_query_arg( $args, wp_get_referer() ) : add_query_arg( $args ), $action );
335
+ self::link_to_settings_if_not_connected( $link );
336
+ return self::display_icon( 'cancelled', $link, $confirm ? self::$confirm_message : '' );
337
  }
338
 
339
  /**
340
  * Outputs a copy icon
341
  *
342
  * @param int|string $object_id
343
+ * @param string $target
344
+ * @param bool $confirm
345
  */
346
  public function copy_icon( $object_id, $target, $confirm = false ) {
347
+ $args = array(
348
+ $this->type => $object_id,
349
+ 'target' => $target,
350
+ 'action' => 'lingotek-copy',
351
+ 'noheader' => true,
352
+ );
353
  $link = wp_nonce_url( defined( 'DOING_AJAX' ) && DOING_AJAX ? add_query_arg( $args, wp_get_referer() ) : add_query_arg( $args ), 'lingotek-copy' );
354
+ self::link_to_settings_if_not_connected( $link );
355
  return self::display_icon( 'copy', $link, $confirm ? self::$confirm_message : '' );
356
  }
357
 
363
  * @param object $document
364
  */
365
  public static function importing_icon( $document ) {
366
+ $args = array(
367
+ 'document_id' => $document->document_id,
368
+ 'action' => 'lingotek-status',
369
+ 'noheader' => true,
370
+ );
371
  $link = wp_nonce_url( defined( 'DOING_AJAX' ) && DOING_AJAX ? add_query_arg( $args, wp_get_referer() ) : add_query_arg( $args ), 'lingotek-status' );
372
+ self::link_to_settings_if_not_connected( $link );
373
  return self::display_icon( 'importing', $link );
374
  }
375
 
384
  public static function translation_icon( $document, $language ) {
385
  if ( isset( $document->translations[ $language->locale ] ) ) {
386
  if ( 'ready' === $document->translations[ $language->locale ] ) {
387
+ $link = wp_nonce_url(
388
+ add_query_arg(
389
+ array(
390
+ 'document_id' => $document->document_id,
391
+ 'locale' => $language->locale,
392
+ 'action' => 'lingotek-download',
393
+ 'noheader' => true,
394
+ )
395
+ ),
396
+ 'lingotek-download'
397
+ );
398
+ self::link_to_settings_if_not_connected( $link );
399
  return self::display_icon( $document->translations[ $language->locale ], $link );
400
  } elseif ( 'not-current' === $document->translations[ $language->locale ] ) {
401
  return '<div class="lingotek-color dashicons dashicons-no"></div>';
402
+ // phpcs:ignore WordPress.CodeAnalysis.AssignmentInCondition.Found,Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure
403
+ } elseif ( 'current' !== $document->translations[ $language->locale ] && $custom_icon = $document->get_custom_in_progress_icon( $language ) ) {
404
  return $custom_icon;
405
  } else {
406
  $link = self::workbench_link( $document->document_id, $language->lingotek_locale );
407
+ self::link_to_settings_if_not_connected( $link );
408
  return self::display_icon( $document->translations[ $language->locale ], $link, ' target="_blank"' );
409
+ }//end if
410
  } else {
411
+ $link = wp_nonce_url(
412
+ add_query_arg(
413
+ array(
414
+ 'document_id' => $document->document_id,
415
+ 'locale' => $language->locale,
416
+ 'action' => 'lingotek-request',
417
+ 'noheader' => true,
418
+ ),
419
+ defined( 'DOING_AJAX' ) && DOING_AJAX ? wp_get_referer() : wp_get_referer()
420
+ ),
421
+ 'lingotek-request'
422
+ );
423
+ self::link_to_settings_if_not_connected( $link );
424
  return self::display_icon( 'request', $link );
425
+ }//end if
426
  }
427
 
428
  /**
429
  * Outputs icon for failed import callback
430
  *
431
  * @since 1.4.3
 
432
  */
433
+ public function failed_import_icon( $name, $object_id ) {
434
+ $args = array(
435
+ $this->type => $object_id,
436
+ 'action' => 'lingotek-upload',
437
+ 'noheader' => true,
438
+ );
439
+ if ( isset( $args['string'] ) ) {
440
+ $args['string'] = rawurlencode( $args['string'] );
441
  }
442
  $link = wp_nonce_url( defined( 'DOING_AJAX' ) && DOING_AJAX ? add_query_arg( $args, wp_get_referer() ) : add_query_arg( $args ), 'lingotek-upload' );
443
+ self::link_to_settings_if_not_connected( $link );
444
 
445
+ return sprintf(
446
+ '<a class="%s dashicons dashicons-%s" title="%s" href="%s"></a>',
447
+ self::$icons[ $name ]['class'],
448
+ self::$icons[ $name ]['icon'],
449
+ self::$icons[ $name ]['title'],
450
+ esc_url( $link )
451
+ );
452
  }
453
 
454
  /**
456
  *
457
  * @since 0.2
458
  *
459
+ * @param array $args Parameters to add to the link.
460
+ * @param bool $warning Whether to display an alert or not, optional, defaults to false.
461
  * @return string
462
  */
463
  protected function get_action_link( $args, $warning = false ) {
464
+ $action = $args['action'];
465
+ $args['action'] = 'lingotek-' . $action;
466
  $args['noheader'] = true;
467
+ if ( isset( $args['string'] ) ) {
468
+ $args['string'] = rawurlencode( $args['string'] );
469
  }
470
  $link = wp_nonce_url( defined( 'DOING_AJAX' ) && DOING_AJAX ? add_query_arg( $args, wp_get_referer() ) : add_query_arg( $args ), 'lingotek-' . $action );
471
+ self::link_to_settings_if_not_connected( $link );
472
+
473
+ switch ( $action ) {
474
  case 'delete-translation':
475
  $message = self::$confirm_delete_translation;
476
+ break;
477
  case 'delete':
478
  $message = self::$confirm_delete;
479
+ break;
480
  case 'cancel-translation':
481
  $message = self::$confirm_cancel_translation;
482
+ break;
483
  case 'cancel':
484
  $message = self::$confirm_cancel;
485
+ break;
486
  default:
487
  $message = self::$confirm_message;
488
+ break;
489
  }
490
 
491
  return sprintf(
497
  );
498
  }
499
 
500
+ private static function link_to_settings_if_not_connected( &$link ) {
501
+ if ( ! get_option( 'lingotek_token' ) || ! get_option( 'lingotek_community' ) ) {
502
+ $link = get_site_url( null, '/wp-admin/admin.php?page=lingotek-translation_settings' );
 
503
  }
504
  }
505
 
508
  *
509
  * @since 0.2
510
  *
511
+ * @param array $actions List of action links.
512
+ * @param mixed $id Object id.
513
  * @return array
514
  */
515
  protected function _row_actions( $actions, $id ) {
518
  return $actions;
519
  }
520
  $document = $this->lgtm->get_group( $this->type, $id );
521
+
522
  $target_id = $id;
523
+ if ( 'string' !== $this->type && isset( $document->desc_array['lingotek']['source'] ) ) {
524
  $id = $document->desc_array['lingotek']['source'];
525
  }
526
 
527
+ if ( $this->lgtm->can_upload( $this->type, $id ) || ( isset( $document->source ) && 'string' !== $this->type && $this->lgtm->can_upload( $this->type, $document->source ) ) ) {
528
  if ( $document ) {
529
  $desc_array = $document->desc_array;
530
  unset( $desc_array['lingotek'] );
531
+ $data = array(
532
+ $this->type => $id,
533
+ 'action' => 'upload',
534
+ );
535
  if ( count( $desc_array ) >= 2 ) {
536
+ $actions['lingotek-upload'] = $this->get_action_link( $data, true );
537
  } else {
538
  $actions['lingotek-upload'] = $this->get_action_link( $data );
539
  }
543
  * update translation status option.
544
  */
545
  if ( 'importing' === $document->status || $document->has_translation_status( 'pending' ) ) {
546
+ $actions['lingotek-status'] = $this->get_action_link(
547
+ array(
548
+ 'document_id' => $document->document_id,
549
+ 'action' => 'status',
550
+ )
551
+ );
552
  }
553
 
554
  if ( $document->has_translation_status( 'ready' ) ) {
555
+ $actions['lingotek-download'] = $this->get_action_link(
556
+ array(
557
+ 'document_id' => $document->document_id,
558
+ 'action' => 'download',
559
+ )
560
+ );
561
  }
562
  } else {
563
+ $actions['lingotek-upload'] = $this->get_action_link(
564
+ array(
565
+ $this->type => $id,
566
+ 'action' => 'upload',
567
+ )
568
+ );
569
+ }//end if
570
  } elseif ( isset( $document->translations ) ) {
571
  // translations to download ?
572
  if ( $document->has_translation_status( 'ready' ) ) {
573
+ $actions['lingotek-download'] = $this->get_action_link(
574
+ array(
575
+ 'document_id' => $document->document_id,
576
+ 'action' => 'download',
577
+ )
578
+ );
579
  }
580
 
581
+ if ( $document->has_translation_status( 'interim' ) ) {
582
+ $actions['lingotek-status'] = $this->get_action_link(
583
+ array(
584
+ 'document_id' => $document->document_id,
585
+ 'action' => 'status',
586
+ )
587
+ );
588
  }
589
 
590
  //need to request translations?
591
+ $language = $this->get_language( $document->source );
592
  $all_locales = array_flip( $this->pllm->get_languages_list( array( 'fields' => 'locale' ) ) );
593
+ // In case a language has been deleted.
594
+ if ( ! empty( $language ) ) {
595
  unset( $all_locales[ $language->locale ] );
596
  }
597
  $untranslated = array_diff_key( $all_locales, $document->translations );
604
  }
605
 
606
  if ( 'current' === $document->status && ! empty( $untranslated ) ) {
607
+ $actions['lingotek-request'] = $this->get_action_link(
608
+ array(
609
+ 'document_id' => $document->document_id,
610
+ 'action' => 'request',
611
+ )
612
+ );
613
  }
614
 
615
  // offers to update translations status
616
  if ( 'importing' === $document->status || $document->has_translation_status( 'pending' ) ) {
617
+ $actions['lingotek-status'] = $this->get_action_link(
618
+ array(
619
+ 'document_id' => $document->document_id,
620
+ 'action' => 'status',
621
+ )
622
+ );
623
  }
624
  } elseif ( empty( $document->source ) ) {
625
+ $actions['lingotek-upload'] = $this->get_action_link(
626
+ array(
627
+ $this->type => $id,
628
+ 'action' => 'upload',
629
+ ),
630
+ true
631
+ );
632
+ }//end if
633
+
634
+ $target_locale = $this->get_language( $target_id )->locale;
635
+ // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
636
+ if ( $id == $target_id && isset( $document->source ) && 'cancelled' !== $document->status ) {
637
+ $actions['lingotek-cancel'] = $this->get_action_link(
638
+ array(
639
+ 'document_id' => $document->document_id,
640
+ 'action' => 'cancel',
641
+ ),
642
+ true
643
+ );
644
+ $actions['lingotek-delete'] = $this->get_action_link(
645
+ array(
646
+ 'document_id' => $document->document_id,
647
+ 'action' => 'delete',
648
+ ),
649
+ true
650
+ );
651
+ } elseif ( isset( $document->source ) && isset( $document->translations[ $target_locale ] ) && 'cancelled' !== $document->translations[ $target_locale ] ) {
652
+ $actions['lingotek-cancel-translation'] = $this->get_action_link(
653
+ array(
654
+ 'document_id' => $document->document_id,
655
+ 'target_id' => $target_id,
656
+ 'target_locale' => $target_locale,
657
+ 'action' => 'cancel-translation',
658
+ ),
659
+ true
660
+ );
661
+ $actions['lingotek-delete-translation'] = $this->get_action_link(
662
+ array(
663
+ 'document_id' => $document->document_id,
664
+ 'target_id' => $target_id,
665
+ 'target_locale' => $target_locale,
666
+ 'action' => 'delete-translation',
667
+ ),
668
+ true
669
+ );
670
+ }//end if
671
 
672
  return $actions;
673
  }
681
  */
682
  protected function _add_bulk_actions( $bulk_actions ) {
683
  foreach ( self::$actions as $action => $strings ) {
684
+ if ( strpos( $action, '-translation' ) ) {
685
  continue;
686
  }
687
+ // phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText,WordPress.WP.I18n.NonSingularStringLiteralDomain
688
  $bulk_actions[ 'bulk-lingotek-' . $action ] = __( $strings['action'], $action );
689
  if ( null !== filter_input( INPUT_GET, 'bulk-lingotek-' . $action ) ) {
690
  $text = $strings['progress'];
699
 
700
  /**
701
  * Outputs javascript data for progress.js
702
+ * wp_localize_script($handle, $name, $data) $handle needs to be lingotek_myhandle
703
+ * where myhandle is handle of script you loaded previously with wp_enqueue_script (probably in admin.php)
704
  *
705
  * @since 0.1
706
  */
707
  public function admin_enqueue_scripts() {
708
  foreach ( array_keys( self::$actions ) as $action ) {
709
  if ( null !== filter_input( INPUT_GET, "bulk-lingotek-$action" ) ) {
710
+ $action_message = 'delete' === $action ? 'cancel' : $action;
711
+ $data = array(
712
+ 'action' => null === filter_input( INPUT_GET, 'page' ) ? ( null === filter_input( INPUT_GET, 'taxonomy' ) ? "post_$action" : "term_$action" ) : "string_$action",
713
  'taxonomy' => null === filter_input( INPUT_GET, 'taxonomy' ) || ! taxonomy_exists( wp_unslash( filter_input( INPUT_GET, 'taxonomy' ) ) ) ? '' : filter_input( INPUT_GET, 'taxonomy' ),
714
+ 'sendback' => remove_query_arg( array( "bulk-lingotek-$action", 'ids', 'lingotek_warning', 'locales' ), wp_get_referer() ),
715
  'ids' => array_map( 'intval', explode( ',', filter_input( INPUT_GET, 'ids' ) ) ),
716
+ // TODO: Fix this based on the possible $action_message values.
717
+ // phpcs:ignore WordPress.WP.I18n.InterpolatedVariableText
718
+ 'warning' => null === filter_input( INPUT_GET, 'lingotek_warning' ) ? ( null === filter_input( INPUT_GET, 'lingotek_remove' ) ? '' : __( "You are about to $action_message existing translations from your Lingotek community. Are you sure?", 'lingotek-translation' ) ) : __( 'You are about to overwrite existing translations. Are you sure?', 'lingotek-translation' ),
719
  'nonce' => wp_create_nonce( 'lingotek_progress' ),
720
  );
721
+ if ( null !== filter_input( INPUT_GET, 'locales' ) ) {
722
+ $data['locales'] = explode( ',', filter_input( INPUT_GET, 'locales' ) );
723
  }
724
+ wp_localize_script( 'lingotek_progress', 'lingotek_data', $data );
725
  return;
726
  }
727
  }
732
  *
733
  * @since 0.2
734
  *
735
+ * @param string $action Action name.
736
+ * @return bool True if the action was managed, false otherwise.
737
  */
738
  protected function _manage_actions( $action ) {
739
  if ( null !== filter_input( INPUT_GET, 'document_id' ) ) {
740
  $document_id = filter_input( INPUT_GET, 'document_id' );
741
+ $document = $this->lgtm->get_group_by_id( $document_id );
742
  }
743
 
744
  switch ( $action ) {
750
 
751
  case 'lingotek-request':
752
  check_admin_referer( 'lingotek-request' );
753
+ Lingotek_Logger::info(
754
+ 'User requested to translate an item',
755
+ array(
756
+ 'document_id' => isset( $document_id ) ? $document_id : '',
757
+ 'locale' => filter_input(
758
+ INPUT_GET,
759
+ 'locale'
760
+ ),
761
+ )
762
+ );
763
  null !== filter_input( INPUT_GET, 'locale' ) ? $document->request_translation( filter_input( INPUT_GET, 'locale' ) ) : $document->request_translations();
764
  break;
765
 
766
  case 'lingotek-download':
767
  check_admin_referer( 'lingotek-download' );
768
+ Lingotek_Logger::info(
769
+ 'User requested to download translation',
770
+ array(
771
+ 'document_id' => isset( $document_id ) ? $document_id : '',
772
+ 'locale' => filter_input(
773
+ INPUT_GET,
774
+ 'locale'
775
+ ),
776
+ )
777
+ );
778
  null !== filter_input( INPUT_GET, 'locale' ) ? $document->create_translation( filter_input( INPUT_GET, 'locale' ) ) : $document->create_translations();
779
  break;
780
 
790
  exit();
791
  }
792
  break;
793
+
794
  case 'lingotek-cancel':
795
  check_admin_referer( 'lingotek-cancel' );
796
  $document->cancel();
802
  break;
803
 
804
  case 'lingotek-delete-translation':
805
+ check_admin_referer( 'lingotek-delete-translation' );
806
+ $target_locale = filter_input( INPUT_GET, 'target_locale' );
807
+ $target_id = filter_input( INPUT_GET, 'target_id' );
808
+ $language = PLL()->model->post->get_language( $target_id );
809
+ $document->delete_translation( $language, $target_id );
810
+ if ( null !== filter_input( INPUT_GET, 'lingotek_redirect' ) && filter_input( INPUT_GET, 'lingotek_redirect' ) === true ) {
811
  $site_id = get_current_blog_id();
812
+ wp_safe_redirect( get_site_url( $site_id, '/wp-admin/edit.php?post_type=page' ) );
813
  exit();
814
  }
815
  break;
816
 
817
  case 'lingotek-cancel-translation':
818
+ check_admin_referer( 'lingotek-cancel-translation' );
819
+ $target_locale = filter_input( INPUT_GET, 'target_locale' );
820
+ $target_id = filter_input( INPUT_GET, 'target_id' );
821
+ $language = PLL()->model->post->get_language( $target_id );
822
+ $document->cancel_translation( $language, $target_id );
823
+ if ( null !== filter_input( INPUT_GET, 'lingotek_redirect' ) && filter_input( INPUT_GET, 'lingotek_redirect' ) === true ) {
824
  $site_id = get_current_blog_id();
825
+ wp_safe_redirect( get_site_url( $site_id, '/wp-admin/edit.php?post_type=page' ) );
826
  exit();
827
  }
828
  break;
829
+
830
  default:
831
  return false;
832
+ }//end switch
833
 
834
  return true;
835
  }
841
  */
842
  public function ajax_download() {
843
  check_ajax_referer( 'lingotek_progress', '_lingotek_nonce' );
844
+ $document = $this->lgtm->get_group( $this->type, filter_input( INPUT_POST, 'id' ) );
845
+ if ( $document ) {
846
  foreach ( $document->translations as $locale => $status ) {
847
+ if ( 'pending' === $status || 'ready' === $status || 'interim' === $status || 'current' === $status ) {
848
  $document->create_translation( $locale );
849
  }
850
  }
859
  */
860
  public function ajax_request() {
861
  check_ajax_referer( 'lingotek_progress', '_lingotek_nonce' );
862
+ $document = $this->lgtm->get_group( $this->type, filter_input( INPUT_POST, 'id' ) );
863
+ if ( $document ) {
864
  $document->request_translations();
865
  }
866
  die();
873
  */
874
  public function ajax_status() {
875
  check_ajax_referer( 'lingotek_progress', '_lingotek_nonce' );
876
+ $document = $this->lgtm->get_group( $this->type, filter_input( INPUT_POST, 'id' ) );
877
+ if ( $document ) {
878
  $document->source_status();
879
  $document->translations_status();
880
  }
888
  */
889
  public function ajax_delete() {
890
  check_ajax_referer( 'lingotek_progress', '_lingotek_nonce' );
891
+ $id = filter_input( INPUT_POST, 'id' );
892
+ $language = PLL()->model->post->get_language( $id );
893
  $document = $this->lgtm->get_group( $this->type, $id );
894
+ // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
895
  if ( $document && $document->source == $id ) {
896
  /**it was left as disassociate so that the delete functionality wouldn't break as it
897
  * did when changing disassociate to delete/cancel in other connectors
898
  */
899
  $document->delete();
900
+ // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
901
+ } elseif ( $document && $document->source != $id && $language ) {
902
+ $document->delete_translation( $language, $id );
903
  }
904
  die();
905
  }
906
 
907
  /**
908
  * Ajax response cancel translations and showing progress
 
909
  */
910
  public function ajax_cancel() {
911
  check_ajax_referer( 'lingotek_progress', '_lingotek_nonce' );
912
+ $id = filter_input( INPUT_POST, 'id' );
913
+ $language = PLL()->model->post->get_language( $id );
914
+ $document = $this->lgtm->get_group( $this->type, $id );
915
+ // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
916
  if ( $document && $document->source == $id ) {
917
  $document->cancel();
918
+ // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
919
+ } elseif ( $document && $document->source != $id && $language ) {
920
+ $document->cancel_translation( $language, $id );
921
  }
922
  die();
923
  }
927
  */
928
  public function ajax_estimate_cost() {
929
  check_ajax_referer( 'lingotek_professional', '_lingotek_nonce' );
930
+ $document_id = filter_input( INPUT_GET, 'document_id' );
931
+ $locale = filter_input( INPUT_GET, 'locale' );
932
  $lingotek_auth = filter_input( INPUT_GET, 'Authorization-Lingotek' );
933
+ $client = new Lingotek_API();
934
+ $response = $client->get_cost_estimate( $lingotek_auth, $document_id, $locale );
935
+ echo wp_json_encode( $response );
936
  die();
937
  }
938
 
939
  /**
940
+ * Ajax call to request professional translation of a document through bridge.
941
+ */
942
  public function ajax_request_professional_translation() {
943
  check_ajax_referer( 'lingotek_professional', '_lingotek_nonce' );
944
+ $post_vars = filter_input_array( INPUT_POST );
945
+ $client = new Lingotek_API();
946
+ $response = $client->request_professional_translation_bulk( $post_vars['workflow_id'], $post_vars['translations'], $post_vars['total_estimate'], $post_vars['summary'] );
947
+ if ( true === $response['data']['transaction_approved'] ) {
948
+ foreach ( $post_vars['translations'] as $document_id => $locales ) {
949
+ $document = $this->lgtm->get_group( $post_vars['type'], $post_vars['ids'][ $document_id ] );
950
+ if ( $document ) {
951
+ foreach ( $locales as $locale ) {
952
+ $locale = $post_vars['lingotek_locale_to_wp_locale'][ $locale ];
953
+ $document->update_translation_status( $locale, 'pending' );
954
  }
955
  } else {
956
  // TODO: what if a document doesn't exists? T_T
958
  }
959
  }
960
 
961
+ echo wp_json_encode( $response );
962
  die();
963
  }
964
 
965
  public function ajax_get_ltk_terms_and_conditions() {
966
  check_ajax_referer( 'lingotek_professional', '_lingotek_nonce' );
967
  $client = new Lingotek_API();
968
+ echo wp_json_encode( $client->get_lingotek_terms_and_conditions() );
969
  die();
970
  }
971
 
972
  public function ajax_get_user_payment_information() {
973
  check_ajax_referer( 'lingotek_professional', '_lingotek_nonce' );
974
+ $client = new Lingotek_API();
975
  $response = $client->get_user_payment_information();
976
+ echo wp_json_encode( $response );
977
  die();
978
  }
979
 
982
  *
983
  * @since 1.1
984
  *
985
+ * @param string $errors
986
  */
987
  public static function retrieve_api_error( $errors ) {
988
  $api_error = "\n";
admin/admin.php CHANGED
@@ -15,9 +15,9 @@ class Lingotek_Admin {
15
  * @since 0.1
16
  */
17
  public function __construct() {
18
- $plugin = Lingotek::get_instance();
19
  $this->plugin_slug = $plugin->get_plugin_slug();
20
- $this->dashboard = new Lingotek_Dashboard( $plugin );
21
 
22
  $this->pllm = $GLOBALS['polylang']->model;
23
 
@@ -26,45 +26,48 @@ class Lingotek_Admin {
26
  // adds a 'settings' link in the plugins table.
27
  add_filter( 'plugin_action_links_' . LINGOTEK_BASENAME, array( &$this, 'plugin_action_links' ) );
28
 
29
- // adds the link to the languages panel in the wordpress admin menu.
30
  add_action( 'admin_menu', array( &$this, 'add_menus' ) );
31
 
32
- add_action( 'load-translation_page_lingotek-translation_manage', array( &$this, 'load_manage_page' ) );
33
  add_filter( 'set-screen-option', array( $this, 'set_screen_option' ), 10, 3 );
34
 
35
  add_action( 'wp_ajax_' . $this->ajax_dashboard_language_endpoint, array( &$this->dashboard, 'ajax_language_dashboard' ) );
36
  add_action( 'wp_ajax_get_current_status', array( $this, 'ajax_get_current_status' ) );
37
  // Network admin menu.
38
  add_action( 'network_admin_menu', array( $this, 'add_network_admin_menu' ) );
39
- add_action('wp_ajax_lingotek_authorization_action', array($this,'lingotek_authorization_action'));
40
  }
41
 
42
  public function lingotek_authorization_action() {
43
- $access_token = $_SERVER['HTTP_TOKEN'];
44
- update_option( 'lingotek_token', array( 'access_token' => $access_token ));
 
 
 
45
  }
46
 
47
  /**
48
  * Gets current status.
49
  */
50
  public function ajax_get_current_status() {
51
- $lgtm = &$GLOBALS['wp_lingotek']->model;
52
- $pllm = $GLOBALS['polylang']->model;
53
- $languages = pll_languages_list( array( 'fields' => 'locale' ) );
54
- $post_vars = filter_input_array(INPUT_POST);
55
- $object_ids = isset($post_vars['check_ids']) ? $post_vars['check_ids'] : NULL;
56
  if ( null === $object_ids ) {
57
  return;
58
  }
59
- $terms_translations = $this->get_if_exists($post_vars,'terms_translations');
60
- $terms = ! empty( $terms_translations );
61
 
62
  // The main array consists of ids and nonces. Each id has a source language, languages with statuses, and a workbench link.
63
  $content_metadata = array();
64
  foreach ( $object_ids as $object_id ) {
65
- $id = $object_id;
66
- $type = $terms ? 'term' : 'post';
67
- $taxonomy = $this->get_if_exists($post_vars,'taxonomy');
68
  if ( ! empty( $taxonomy ) ) {
69
  if ( strpos( $taxonomy, '&' ) ) {
70
  $taxonomy = strstr( $taxonomy, '&', true );
@@ -73,12 +76,12 @@ class Lingotek_Admin {
73
  $taxonomy = get_post_type( $id );
74
  }
75
  $content_metadata[ $id ] = array(
76
- 'existing_trans' => false,
77
- 'source' => false,
78
- 'doc_id' => null,
79
- 'source_id' => null,
80
- 'source_status' => null,
81
- );
82
 
83
  $document = $lgtm->get_group( $type, $object_id );
84
  if ( $document && ! isset( $document->source ) && count( $document->desc_array ) >= 3 ) {
@@ -88,46 +91,47 @@ class Lingotek_Admin {
88
  if ( $document->source !== (int) $object_id ) {
89
  $document = $lgtm->get_group( $type, $document->source );
90
  }
91
- $source_id = null !== $document->source ? $document->source : $object_id;
92
- $source_language = $terms ? pll_get_term_language( $document->source, 'locale' )
93
  : pll_get_post_language( $document->source, 'locale' );
94
- $existing_translations = $type = 'term' ? PLL()->model->term->get_translations( $source_id ) : PLL()->model->post->get_translations( $source_id );
95
 
96
  if ( count( $existing_translations ) > 1 ) {
97
  $content_metadata[ $id ]['existing_trans'] = true;
98
  }
99
- $content_metadata[ $id ]['source'] = $source_language;
100
- $content_metadata[ $id ]['doc_id'] = $document->document_id;
101
- $content_metadata[ $id ]['source_id'] = $document->source;
102
  $content_metadata[ $id ]['source_status'] = $document->status;
103
- $target_status = 'edited' === $document->status || null === $document->status ? 'edited' : $document->status;
104
  $content_metadata[ $id ][ $source_language ]['status'] = $document->source === $object_id ? $document->status : $target_status;
105
  if ( is_array( $document->translations ) ) {
106
  foreach ( $document->translations as $locale => $translation_status ) {
107
- $content_metadata[ $id ][ $locale ]['status'] = $translation_status;
108
- $workbench_link = Lingotek_Actions::workbench_link( $document->document_id, $locale );
109
  $content_metadata[ $id ][ $locale ]['workbench_link'] = $workbench_link;
110
  }
111
  }
112
 
113
  // fills in missing languages, makes life easier for the updater.
114
  foreach ( $languages as $language ) {
115
- if (!Lingotek::is_allowed_tms_locale($language)) { continue; }
 
116
  foreach ( $content_metadata as $group => $status ) {
117
- $language_obj = $pllm->get_language( $source_language );
118
  $target_lang_obj = $pllm->get_language( $language );
119
- $profile = Lingotek_Model::get_profile( $taxonomy, $language_obj, $group );
120
  if ( 'disabled' !== $profile['profile'] && false !== $status['source'] ) {
121
  if ( ! isset( $status[ $language ] ) ) {
122
  $content_metadata[ $group ][ $language ]['status'] = 'none';
123
- if ( $document->is_disabled_target( $pllm->get_language( $source_language ), $pllm->get_language( $language ) ) || (isset( $document->desc_array[ $target_lang_obj->slug ] ) && ! isset( $document->source )) ) {
124
  $content_metadata[ $group ][ $language ]['status'] = 'disabled';
125
  }
126
  }
127
  }
128
  }
129
  }
130
- }
131
 
132
  $language = 'post' === $type ? pll_get_post_language( $id ) : pll_get_term_language( $id );
133
  $language = $pllm->get_language( $language );
@@ -137,13 +141,13 @@ class Lingotek_Admin {
137
  $content_metadata[ $id ]['source'] = 'disabled';
138
  }
139
  }
140
- }
141
 
142
  // get the nonces associated with the different actions.
143
- $content_metadata['request_nonce'] = $this->lingotek_get_matching_nonce( 'lingotek-request' );
144
  $content_metadata['download_nonce'] = $this->lingotek_get_matching_nonce( 'lingotek-download' );
145
- $content_metadata['upload_nonce'] = $this->lingotek_get_matching_nonce( 'lingotek-upload' );
146
- $content_metadata['status_nonce'] = $this->lingotek_get_matching_nonce( 'lingotek-status' );
147
  wp_send_json( $content_metadata );
148
  }
149
 
@@ -156,7 +160,7 @@ class Lingotek_Admin {
156
  public function lingotek_get_matching_nonce( $action ) {
157
  $upload_link = wp_nonce_url( add_query_arg( array( 'action' => $action ) ), $action );
158
  $nonce_begin = strpos( $upload_link, 'wpnonce=' ) + 8;
159
- $nonce = substr( $upload_link,$nonce_begin );
160
  return $nonce;
161
  }
162
 
@@ -201,20 +205,20 @@ class Lingotek_Admin {
201
  // 2 => int,bool 1 to enqueue script before </body> instead of in the head. Default is false (see wp_enqueue_script in wp doc)
202
  // FIXME: check if I can load more scripts in footer.
203
  $scripts = array(
204
- 'progress' => array( array( 'edit', 'upload', 'edit-tags', 'translation_page_lingotek-translation_manage', 'translation_page_lingotek-translation_settings' ), array( 'jquery-ui-progressbar', 'jquery-ui-dialog', 'wp-ajax-response' ), 1 ),
205
- 'updater' => array( array( 'edit', 'upload', 'edit-tags' ), array( 'jquery-ui-progressbar', 'jquery-ui-dialog', 'wp-ajax-response' ), 1 ),
206
  );
207
 
208
  $styles = array(
209
- 'admin' => array( array( 'edit', 'upload', 'edit-tags', 'translation_page_lingotek-translation_manage', 'translation_page_lingotek-translation_settings' ), array( 'wp-jquery-ui-dialog' ) ),
210
  );
211
 
212
  foreach ( $scripts as $script => $v ) {
213
  if ( in_array( $screen->base, $v[0], true ) ) {
214
  wp_enqueue_script( 'lingotek_' . $script, LINGOTEK_URL . '/js/' . $script . $suffix . '.js', $v[1], LINGOTEK_VERSION, $v[2] );
215
- $lingotek_prefs = get_option( 'lingotek_prefs' );
216
- $auto_update_interval = isset($lingotek_prefs['auto_update_status']) ? intval($lingotek_prefs['auto_update_status']) : 10;
217
- wp_localize_script( 'lingotek_' . $script, 'updater_data', array('interval' => $auto_update_interval));
218
  }
219
  }
220
 
@@ -225,9 +229,9 @@ class Lingotek_Admin {
225
  }
226
 
227
  //for target select dropdown modal
228
- if (in_array($screen->base, array('edit', 'upload', 'edit-tags'), true)){
229
- wp_enqueue_script('lingotek_select2_js', 'https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.10/js/select2.min.js', array());
230
- wp_enqueue_style('lingotek_select2_css', 'https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.10/css/select2.min.css', array());
231
  }
232
  }
233
 
@@ -245,17 +249,19 @@ class Lingotek_Admin {
245
  }
246
 
247
  /**
248
- * Adds the links to the Lingotek panels in the wordpress admin menu
249
  *
250
  * @since 0.0.1
251
  */
252
  public function add_menus() {
 
253
  add_menu_page(
254
- $title = __( 'Translation', 'lingotek-translation' ),
255
  $title,
256
  'manage_options',
257
  $this->plugin_slug,
258
- array( $this, 'display_dashboard_page' ), 'dashicons-translation'
 
259
  );
260
 
261
  add_submenu_page( $this->plugin_slug, __( 'Translation Dashboard', 'lingotek-translation' ), __( 'Dashboard', 'lingotek-translation' ), 'manage_options', $this->plugin_slug, array( $this, 'display_dashboard_page' ) );
@@ -265,7 +271,7 @@ class Lingotek_Admin {
265
 
266
  $selected_options = Lingotek_Model::get_prefs();
267
  if ( isset( $selected_options['import_enabled'] ) && '1' === $selected_options['import_enabled']['enabled'] ) {
268
- add_submenu_page( $this->plugin_slug, __( 'Lingotek Import', 'lingotek-translation' ), __( 'Import', 'lingotek-translation' ), 'manage_options', $this->plugin_slug . '_import', array( $this, 'display_import_page' ) ); }
269
  }
270
  /**
271
  * Displays the settings page
@@ -283,14 +289,20 @@ class Lingotek_Admin {
283
  }
284
 
285
  // connect Lingotek account.
286
- $database_token_details = get_option('lingotek_token', []);
287
- $access_token = isset($database_token_details['access_token']) ? $database_token_details['access_token'] : null;
288
  if ( ! empty( $access_token ) && empty( $delete_access_token ) ) {
289
  // set and get token details.
290
- $client = new Lingotek_API();
291
  $token_details = $client->get_token_details( $access_token );
292
  if ( $token_details && strlen( $token_details->login_id ) ) {
293
- update_option( 'lingotek_token', array( 'access_token' => $access_token, 'login_id' => $token_details->login_id ) );
 
 
 
 
 
 
294
  add_settings_error( 'lingotek_token', 'account-connection', __( 'Your Lingotek account has been successfully connected.', 'lingotek-translation' ), 'updated' );
295
  } else {
296
  add_settings_error( 'lingotek_token', 'account-connection', __( 'Your Lingotek account was not connected. The Access Token received was invalid.', 'lingotek-translation' ), 'error' );
@@ -299,7 +311,7 @@ class Lingotek_Admin {
299
 
300
  // set page key primarily used for form submissions.
301
  $page_key = $this->plugin_slug . '_settings';
302
- $sm = filter_input( INPUT_GET, 'sm' );
303
  if ( ! empty( $sm ) ) {
304
  $page_key .= '&sm=' . sanitize_text_field( $sm );
305
  }
@@ -318,13 +330,13 @@ class Lingotek_Admin {
318
  }
319
 
320
  $token_details = self::has_token_details();
321
- $redirect_url = admin_url( 'admin.php?page=' . $this->plugin_slug . '_settings&sm=account' );
322
 
323
  if ( $token_details ) {
324
  $access_token = $token_details['access_token'];
325
- $login_id = $token_details['login_id'];
326
- $base_url = get_option( 'lingotek_base_url' );
327
- include( LINGOTEK_ADMIN_INC . '/settings.php' );
328
  } else {
329
  $connect_url = '';
330
  // connect cloak redirect.
@@ -332,13 +344,13 @@ class Lingotek_Admin {
332
  if ( ! empty( $connect ) ) {
333
  update_option( 'lingotek_base_url', Lingotek_API::PRODUCTION_URL );
334
  $client = new Lingotek_API();
335
- echo '<div class="wrap"><p class="description">' . esc_html( __( 'Redirecting to Lingotek to connect your account...','lingotek-translation' ) ) . '</p></div>';
336
 
337
- $connect_url = (0 === strcasecmp( $connect,'new' )) ? $client->get_new_url( $redirect_url ) : $client->get_connect_url( $redirect_url );
338
  }
339
- $connect_account_cloak_url_new = admin_url( 'admin.php?page=' . $this->plugin_slug . '_settings&connect=new' );
340
  $connect_account_cloak_url_prod = admin_url( 'admin.php?page=' . $this->plugin_slug . '_settings&connect=production' );
341
- include( LINGOTEK_ADMIN_INC . '/settings/connect-account.php' );
342
  }
343
  }
344
 
@@ -351,44 +363,39 @@ class Lingotek_Admin {
351
  * @return array
352
  */
353
  public function get_profiles_settings( $defaults = false ) {
354
-
355
  $resources = get_option( 'lingotek_community_resources' );
356
- $options = array(
357
- 'manual' => __( 'Manual', 'lingotek-translation' ),
 
358
  );
359
 
360
-
361
- if (/**get_option('lingotek_automatic_enabled')*/ true) {
362
- $options['automatic'] = __( 'Automatic', 'lingotek-translation' );
363
- }
364
-
365
  $download_options = array(
366
- 'manual' => __( 'Manual', 'lingotek-translation' ),
367
  'automatic' => __( 'Automatic', 'lingotek-translation' ),
368
  );
369
 
370
  return array(
371
- 'upload' => array(
372
  'label' => __( 'Upload content', 'lingotek-translation' ),
373
  'options' => $options,
374
  'description' => __( 'How should new and modified content be uploaded to Lingotek?', 'lingotek-translation' ),
375
  ),
376
- 'download' => array(
377
  'label' => __( 'Download translations', 'lingotek-translation' ),
378
  'options' => $download_options,
379
  'description' => __( 'How should completed translations be downloaded to WordPress?', 'lingotek-translation' ),
380
  ),
381
- 'project_id' => array(
382
- 'label' => $defaults ? __( 'Default Project', 'lingotek-translation' ) : __( 'Project', 'lingotek-translation' ),
383
  'options' => $resources['projects'],
384
  'description' => __( 'Changes will affect new entities only', 'lingotek-translation' ),
385
  ),
386
- 'workflow_id' => array(
387
- 'label' => $defaults ? __( 'Default Workflow', 'lingotek-translation' ) : __( 'Workflow', 'lingotek-translation' ),
388
  'options' => $resources['workflows'],
389
  'description' => __( 'Changes will affect new entities only', 'lingotek-translation' ),
390
  ),
391
- 'primary_filter_id' => array(
392
  'label' => $defaults ? __( 'Primary Filter', 'lingotek-translation' ) : __( 'Primary Filter', 'lingotek-translation' ),
393
  'options' => $resources['filters'],
394
  'description' => __( 'Changes will affect new entities only', 'lingotek-translation' ),
@@ -423,7 +430,8 @@ class Lingotek_Admin {
423
  $profiles[ $content_types[ $type ]['profile'] ]['usage'] += 1;
424
  } elseif ( 'post' === $type ) {
425
  $profiles['automatic']['usage'] += 1;
426
- } else { $profiles['manual']['usage'] += 1;
 
427
  }
428
 
429
  if ( isset( $content_types[ $type ]['sources'] ) ) {
@@ -444,9 +452,9 @@ class Lingotek_Admin {
444
  * @param bool $update_first_project_callback boolean flag.
445
  */
446
  public function set_community_resources( $community_id, $update_first_project_callback = false ) {
447
- $client = new Lingotek_API();
448
  $refresh_success = array(
449
- 'projects' => false,
450
  'workflows' => false,
451
  );
452
 
@@ -461,11 +469,12 @@ class Lingotek_Admin {
461
  $client->update_callback_url( $project->properties->id );
462
  }
463
  }
464
- natcasesort( $projects ); // order by title (case-insensitive).
 
465
  $refresh_success['projects'] = true;
466
  }
467
 
468
- $api_data = $client->get_workflows( $community_id );
469
  $default_workflows = array(
470
  'c675bd20-0688-11e2-892e-0800200c9a66' => 'Machine Translation',
471
  'ddf6e3c0-0688-11e2-892e-0800200c9a66' => 'Machine Translation + Post-Edit',
@@ -475,7 +484,7 @@ class Lingotek_Admin {
475
  '2210b148-0c44-4ae2-91d0-ca2ee47c069e' => 'Translation + 3 reviews',
476
  '7993b4d7-4ada-46d0-93d5-858db46c4c7d' => 'Translation Only',
477
  );
478
- $workflows = array();
479
  if ( $api_data ) {
480
  foreach ( $api_data->entities as $workflow ) {
481
  $workflows[ $workflow->properties->id ] = $workflow->properties->title;
@@ -486,16 +495,17 @@ class Lingotek_Admin {
486
  'c675bd20-0688-11e2-892e-0800200c9a66' => 'Machine Translation',
487
  );
488
  }
489
- natcasesort( $workflows ); // order by title (case-insensitive).
490
- if (Lingotek_Professional_Translation_Workflow::is_allowed_user()) {
 
491
  $workflows['ltk-professional-translation'] = 'Lingotek Professional Translation';
492
  }
493
- $workflows = array_merge(array('project-default' => 'Use Project Default'), $workflows);
494
  $refresh_success['workflows'] = true;
495
  }
496
-
497
  $api_data = $client->get_filters();
498
- $filters = array();
499
  if ( $api_data && $api_data->properties->total > 0 ) {
500
  foreach ( $api_data->entities as $filter ) {
501
  if ( ! $filter->properties->is_public ) {
@@ -505,20 +515,20 @@ class Lingotek_Admin {
505
  $filters[ $filter->properties->id ] = $filter->properties->title;
506
  }
507
  }
508
- $primary_filter_id = array_search( 'okf_json@with-html-subfilter.fprm', $filters, true );
509
  $secondary_filter_id = array_search( 'okf_html@wordpress.fprm', $filters, true );
510
- $defaults = get_option( 'lingotek_defaults' );
511
- if ( !$defaults ) {
512
- $defaults['primary_filter_id'] = $primary_filter_id;
513
  $defaults['secondary_filter_id'] = $secondary_filter_id;
514
  update_option( 'lingotek_defaults', $defaults );
515
  }
516
  }
517
 
518
  $resources = array(
519
- 'projects' => $projects,
520
  'workflows' => $workflows,
521
- 'filters' => $filters,
522
  );
523
 
524
  if ( true === $refresh_success['projects'] || true === $refresh_success['workflows'] ) {
@@ -532,13 +542,13 @@ class Lingotek_Admin {
532
  * Ensures valid defaults.
533
  */
534
  public function ensure_valid_defaults() {
535
- $resources = get_option( 'lingotek_community_resources' );
536
- $defaults = get_option( 'lingotek_defaults' );
537
  $valid_default = array();
538
  foreach ( $resources as $resource_key => $options ) {
539
- $key = substr( $resource_key,0,strlen( $resource_key ) -1 ) . '_id';
540
  $valid_default[ $key ] = 0;
541
- if ( ! is_array( $defaults ) ) {
542
  continue;
543
  }
544
  foreach ( $options as $option_key => $option_val ) {
@@ -552,7 +562,7 @@ class Lingotek_Admin {
552
  }
553
  }
554
  foreach ( $valid_default as $key => $valid ) {
555
- $resource_key = substr( $key,0,strpos( $key,'_' ) ) . 's';
556
  if ( $valid ) {
557
  continue;
558
  } else {
@@ -562,6 +572,7 @@ class Lingotek_Admin {
562
  $num_valid_defaults = array_sum( $valid_default );
563
 
564
  if ( $num_valid_defaults < count( $valid_default ) ) {
 
565
  add_settings_error( 'lingotek_defaults', 'community-selected', sprintf( __( 'Your <a href="%s"><i>Defaults</i></a> have been updated to valid options for this community.', 'lingotek-translation' ), admin_url( 'admin.php?page=lingotek-translation_settings&sm=defaults' ) ), 'updated' );
566
  }
567
  unset( $defaults['filter_id'] );
@@ -581,7 +592,7 @@ class Lingotek_Admin {
581
  */
582
  ob_start();
583
  if ( self::has_token_details() ) {
584
- include( LINGOTEK_ADMIN_INC . '/view-manage.php' );
585
  } else {
586
  $this->display_settings_page();
587
  }
@@ -594,11 +605,14 @@ class Lingotek_Admin {
594
  * @since 0.2
595
  */
596
  public function load_manage_page() {
597
- add_screen_option('per_page', array(
598
- 'label' => __( 'Strings groups', 'lingotek-translation' ),
599
- 'default' => 10,
600
- 'option' => 'lingotek_strings_per_page',
601
- ));
 
 
 
602
  }
603
 
604
  /**
@@ -626,34 +640,34 @@ class Lingotek_Admin {
626
  $token_details = self::has_token_details();
627
  if ( $token_details ) {
628
  $community_id = get_option( 'lingotek_community' );
629
- $defaults = get_option( 'lingotek_defaults' );
630
- $user = wp_get_current_user();
631
 
632
  // The data that will be passed to the Lingotek GMC dashboard.
633
  $cms_data = array(
634
- // lingotek.
635
- 'community_id' => $community_id,
636
- 'external_id' => $token_details['login_id'],
637
- 'workflow_id' => $defaults['workflow_id'],
638
- 'project_id' => $defaults['project_id'],
639
- 'first_name' => $user->display_name,
640
- 'last_name' => '',
641
- 'email' => get_bloginfo( 'admin_email' ),
642
- // cms.
643
- 'cms_site_id' => site_url(),
644
- 'cms_site_key' => site_url(),
645
- 'cms_site_name' => get_bloginfo( 'name' ),
646
- 'cms_type' => 'Wordpress',
647
- 'cms_version' => get_bloginfo( 'version' ),
648
- 'cms_tag' => LINGOTEK_PLUGIN_SLUG,
649
- 'locale' => pll_current_language( 'lingotek_locale' ),
650
- 'module_version' => LINGOTEK_VERSION,
651
- 'endpoint_url' => $this->get_dashboard_endpoint(),
652
  );
653
- include( LINGOTEK_ADMIN_INC . '/view-dashboard.php' );
654
  } else {
655
  $this->display_settings_page();
656
- }
657
  }
658
 
659
  /**
@@ -663,7 +677,7 @@ class Lingotek_Admin {
663
  */
664
  public static function has_token_details() {
665
  $token_details = get_option( 'lingotek_token' );
666
- $has_token = false;
667
  if ( false !== $token_details && key_exists( 'access_token', $token_details ) && key_exists( 'login_id', $token_details ) && strlen( $token_details['access_token'] ) && strlen( $token_details['login_id'] ) ) {
668
  $has_token = true;
669
  return $token_details;
@@ -676,7 +690,7 @@ class Lingotek_Admin {
676
  */
677
  public function display_network_settings_page() {
678
  if ( is_multisite() && self::has_token_details() ) {
679
- include( LINGOTEK_ADMIN_INC . '/view-network.php' );
680
  } else {
681
  $this->display_settings_page();
682
  }
@@ -696,7 +710,7 @@ class Lingotek_Admin {
696
  */
697
  public function display_tutorial_page() {
698
  if ( self::has_token_details() ) {
699
- include( LINGOTEK_ADMIN_INC . '/view-tutorial.php' );
700
  } else {
701
  $this->display_settings_page();
702
  }
@@ -708,14 +722,14 @@ class Lingotek_Admin {
708
  public function display_import_page() {
709
  if ( self::has_token_details() ) {
710
  settings_errors();
711
- include( LINGOTEK_ADMIN_INC ) . '/import.php';
712
  } else {
713
  $this->display_settings_page();
714
  }
715
  }
716
 
717
- private function get_if_exists($array, $key){
718
- return is_array($array) && array_key_exists($key, $array) ? $array[$key] : null;
719
  }
720
 
721
  }
15
  * @since 0.1
16
  */
17
  public function __construct() {
18
+ $plugin = Lingotek::get_instance();
19
  $this->plugin_slug = $plugin->get_plugin_slug();
20
+ $this->dashboard = new Lingotek_Dashboard( $plugin );
21
 
22
  $this->pllm = $GLOBALS['polylang']->model;
23
 
26
  // adds a 'settings' link in the plugins table.
27
  add_filter( 'plugin_action_links_' . LINGOTEK_BASENAME, array( &$this, 'plugin_action_links' ) );
28
 
29
+ // adds the link to the languages panel in the WordPress admin menu.
30
  add_action( 'admin_menu', array( &$this, 'add_menus' ) );
31
 
32
+ add_action( 'load-translation_page_lingotek-translation_manage', array( &$this, 'load_manage_page' ) );
33
  add_filter( 'set-screen-option', array( $this, 'set_screen_option' ), 10, 3 );
34
 
35
  add_action( 'wp_ajax_' . $this->ajax_dashboard_language_endpoint, array( &$this->dashboard, 'ajax_language_dashboard' ) );
36
  add_action( 'wp_ajax_get_current_status', array( $this, 'ajax_get_current_status' ) );
37
  // Network admin menu.
38
  add_action( 'network_admin_menu', array( $this, 'add_network_admin_menu' ) );
39
+ add_action( 'wp_ajax_lingotek_authorization_action', array( $this, 'lingotek_authorization_action' ) );
40
  }
41
 
42
  public function lingotek_authorization_action() {
43
+ $access_token = isset( $_SERVER['HTTP_TOKEN'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_TOKEN'] ) ) : null;
44
+ if ( is_null( $access_token ) ) {
45
+ Lingotek_Logger::error( 'access_token was empty in lingotek_authorization_action().' );
46
+ }
47
+ update_option( 'lingotek_token', array( 'access_token' => $access_token ) );
48
  }
49
 
50
  /**
51
  * Gets current status.
52
  */
53
  public function ajax_get_current_status() {
54
+ $lgtm = &$GLOBALS['wp_lingotek']->model;
55
+ $pllm = $GLOBALS['polylang']->model;
56
+ $languages = pll_languages_list( array( 'fields' => 'locale' ) );
57
+ $post_vars = filter_input_array( INPUT_POST );
58
+ $object_ids = isset( $post_vars['check_ids'] ) ? $post_vars['check_ids'] : null;
59
  if ( null === $object_ids ) {
60
  return;
61
  }
62
+ $terms_translations = $this->get_if_exists( $post_vars, 'terms_translations' );
63
+ $terms = ! empty( $terms_translations );
64
 
65
  // The main array consists of ids and nonces. Each id has a source language, languages with statuses, and a workbench link.
66
  $content_metadata = array();
67
  foreach ( $object_ids as $object_id ) {
68
+ $id = $object_id;
69
+ $type = $terms ? 'term' : 'post';
70
+ $taxonomy = $this->get_if_exists( $post_vars, 'taxonomy' );
71
  if ( ! empty( $taxonomy ) ) {
72
  if ( strpos( $taxonomy, '&' ) ) {
73
  $taxonomy = strstr( $taxonomy, '&', true );
76
  $taxonomy = get_post_type( $id );
77
  }
78
  $content_metadata[ $id ] = array(
79
+ 'existing_trans' => false,
80
+ 'source' => false,
81
+ 'doc_id' => null,
82
+ 'source_id' => null,
83
+ 'source_status' => null,
84
+ );
85
 
86
  $document = $lgtm->get_group( $type, $object_id );
87
  if ( $document && ! isset( $document->source ) && count( $document->desc_array ) >= 3 ) {
91
  if ( $document->source !== (int) $object_id ) {
92
  $document = $lgtm->get_group( $type, $document->source );
93
  }
94
+ $source_id = null !== $document->source ? $document->source : $object_id;
95
+ $source_language = $terms ? pll_get_term_language( $document->source, 'locale' )
96
  : pll_get_post_language( $document->source, 'locale' );
97
+ $existing_translations = ( 'term' === $type ) ? PLL()->model->term->get_translations( $source_id ) : PLL()->model->post->get_translations( $source_id );
98
 
99
  if ( count( $existing_translations ) > 1 ) {
100
  $content_metadata[ $id ]['existing_trans'] = true;
101
  }
102
+ $content_metadata[ $id ]['source'] = $source_language;
103
+ $content_metadata[ $id ]['doc_id'] = $document->document_id;
104
+ $content_metadata[ $id ]['source_id'] = $document->source;
105
  $content_metadata[ $id ]['source_status'] = $document->status;
106
+ $target_status = 'edited' === $document->status || null === $document->status ? 'edited' : $document->status;
107
  $content_metadata[ $id ][ $source_language ]['status'] = $document->source === $object_id ? $document->status : $target_status;
108
  if ( is_array( $document->translations ) ) {
109
  foreach ( $document->translations as $locale => $translation_status ) {
110
+ $content_metadata[ $id ][ $locale ]['status'] = $translation_status;
111
+ $workbench_link = Lingotek_Actions::workbench_link( $document->document_id, $locale );
112
  $content_metadata[ $id ][ $locale ]['workbench_link'] = $workbench_link;
113
  }
114
  }
115
 
116
  // fills in missing languages, makes life easier for the updater.
117
  foreach ( $languages as $language ) {
118
+ if ( ! Lingotek::is_allowed_tms_locale( $language ) ) {
119
+ continue; }
120
  foreach ( $content_metadata as $group => $status ) {
121
+ $language_obj = $pllm->get_language( $source_language );
122
  $target_lang_obj = $pllm->get_language( $language );
123
+ $profile = Lingotek_Model::get_profile( $taxonomy, $language_obj, $group );
124
  if ( 'disabled' !== $profile['profile'] && false !== $status['source'] ) {
125
  if ( ! isset( $status[ $language ] ) ) {
126
  $content_metadata[ $group ][ $language ]['status'] = 'none';
127
+ if ( $document->is_disabled_target( $pllm->get_language( $source_language ), $pllm->get_language( $language ) ) || ( isset( $document->desc_array[ $target_lang_obj->slug ] ) && ! isset( $document->source ) ) ) {
128
  $content_metadata[ $group ][ $language ]['status'] = 'disabled';
129
  }
130
  }
131
  }
132
  }
133
  }
134
+ }//end if
135
 
136
  $language = 'post' === $type ? pll_get_post_language( $id ) : pll_get_term_language( $id );
137
  $language = $pllm->get_language( $language );
141
  $content_metadata[ $id ]['source'] = 'disabled';
142
  }
143
  }
144
+ }//end foreach
145
 
146
  // get the nonces associated with the different actions.
147
+ $content_metadata['request_nonce'] = $this->lingotek_get_matching_nonce( 'lingotek-request' );
148
  $content_metadata['download_nonce'] = $this->lingotek_get_matching_nonce( 'lingotek-download' );
149
+ $content_metadata['upload_nonce'] = $this->lingotek_get_matching_nonce( 'lingotek-upload' );
150
+ $content_metadata['status_nonce'] = $this->lingotek_get_matching_nonce( 'lingotek-status' );
151
  wp_send_json( $content_metadata );
152
  }
153
 
160
  public function lingotek_get_matching_nonce( $action ) {
161
  $upload_link = wp_nonce_url( add_query_arg( array( 'action' => $action ) ), $action );
162
  $nonce_begin = strpos( $upload_link, 'wpnonce=' ) + 8;
163
+ $nonce = substr( $upload_link, $nonce_begin );
164
  return $nonce;
165
  }
166
 
205
  // 2 => int,bool 1 to enqueue script before </body> instead of in the head. Default is false (see wp_enqueue_script in wp doc)
206
  // FIXME: check if I can load more scripts in footer.
207
  $scripts = array(
208
+ 'progress' => array( array( 'edit', 'upload', 'edit-tags', 'translation_page_lingotek-translation_manage', 'translation_page_lingotek-translation_settings' ), array( 'jquery-ui-progressbar', 'jquery-ui-dialog', 'wp-ajax-response' ), 1 ),
209
+ 'updater' => array( array( 'edit', 'upload', 'edit-tags' ), array( 'jquery-ui-progressbar', 'jquery-ui-dialog', 'wp-ajax-response' ), 1 ),
210
  );
211
 
212
  $styles = array(
213
+ 'admin' => array( array( 'edit', 'upload', 'edit-tags', 'translation_page_lingotek-translation_manage', 'translation_page_lingotek-translation_settings' ), array( 'wp-jquery-ui-dialog' ) ),
214
  );
215
 
216
  foreach ( $scripts as $script => $v ) {
217
  if ( in_array( $screen->base, $v[0], true ) ) {
218
  wp_enqueue_script( 'lingotek_' . $script, LINGOTEK_URL . '/js/' . $script . $suffix . '.js', $v[1], LINGOTEK_VERSION, $v[2] );
219
+ $lingotek_prefs = get_option( 'lingotek_prefs' );
220
+ $auto_update_interval = isset( $lingotek_prefs['auto_update_status'] ) ? intval( $lingotek_prefs['auto_update_status'] ) : 10;
221
+ wp_localize_script( 'lingotek_' . $script, 'updater_data', array( 'interval' => $auto_update_interval ) );
222
  }
223
  }
224
 
229
  }
230
 
231
  //for target select dropdown modal
232
+ if ( in_array( $screen->base, array( 'edit', 'upload', 'edit-tags' ), true ) ) {
233
+ wp_enqueue_script( 'lingotek_select2_js', 'https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.10/js/select2.min.js', array(), LINGOTEK_VERSION, false );
234
+ wp_enqueue_style( 'lingotek_select2_css', 'https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.10/css/select2.min.css', array(), LINGOTEK_VERSION );
235
  }
236
  }
237
 
249
  }
250
 
251
  /**
252
+ * Adds the links to the Lingotek panels in the WordPress admin menu
253
  *
254
  * @since 0.0.1
255
  */
256
  public function add_menus() {
257
+ $title = __( 'Translation', 'lingotek-translation' );
258
  add_menu_page(
259
+ $title,
260
  $title,
261
  'manage_options',
262
  $this->plugin_slug,
263
+ array( $this, 'display_dashboard_page' ),
264
+ 'dashicons-translation'
265
  );
266
 
267
  add_submenu_page( $this->plugin_slug, __( 'Translation Dashboard', 'lingotek-translation' ), __( 'Dashboard', 'lingotek-translation' ), 'manage_options', $this->plugin_slug, array( $this, 'display_dashboard_page' ) );
271
 
272
  $selected_options = Lingotek_Model::get_prefs();
273
  if ( isset( $selected_options['import_enabled'] ) && '1' === $selected_options['import_enabled']['enabled'] ) {
274
+ add_submenu_page( $this->plugin_slug, __( 'Lingotek Import', 'lingotek-translation' ), __( 'Import', 'lingotek-translation' ), 'manage_options', $this->plugin_slug . '_import', array( $this, 'display_import_page' ) ); }
275
  }
276
  /**
277
  * Displays the settings page
289
  }
290
 
291
  // connect Lingotek account.
292
+ $database_token_details = get_option( 'lingotek_token', array() );
293
+ $access_token = isset( $database_token_details['access_token'] ) ? $database_token_details['access_token'] : null;
294
  if ( ! empty( $access_token ) && empty( $delete_access_token ) ) {
295
  // set and get token details.
296
+ $client = new Lingotek_API();
297
  $token_details = $client->get_token_details( $access_token );
298
  if ( $token_details && strlen( $token_details->login_id ) ) {
299
+ update_option(
300
+ 'lingotek_token',
301
+ array(
302
+ 'access_token' => $access_token,
303
+ 'login_id' => $token_details->login_id,
304
+ )
305
+ );
306
  add_settings_error( 'lingotek_token', 'account-connection', __( 'Your Lingotek account has been successfully connected.', 'lingotek-translation' ), 'updated' );
307
  } else {
308
  add_settings_error( 'lingotek_token', 'account-connection', __( 'Your Lingotek account was not connected. The Access Token received was invalid.', 'lingotek-translation' ), 'error' );
311
 
312
  // set page key primarily used for form submissions.
313
  $page_key = $this->plugin_slug . '_settings';
314
+ $sm = filter_input( INPUT_GET, 'sm' );
315
  if ( ! empty( $sm ) ) {
316
  $page_key .= '&sm=' . sanitize_text_field( $sm );
317
  }
330
  }
331
 
332
  $token_details = self::has_token_details();
333
+ $redirect_url = admin_url( 'admin.php?page=' . $this->plugin_slug . '_settings&sm=account' );
334
 
335
  if ( $token_details ) {
336
  $access_token = $token_details['access_token'];
337
+ $login_id = $token_details['login_id'];
338
+ $base_url = get_option( 'lingotek_base_url' );
339
+ include LINGOTEK_ADMIN_INC . '/settings.php';
340
  } else {
341
  $connect_url = '';
342
  // connect cloak redirect.
344
  if ( ! empty( $connect ) ) {
345
  update_option( 'lingotek_base_url', Lingotek_API::PRODUCTION_URL );
346
  $client = new Lingotek_API();
347
+ echo '<div class="wrap"><p class="description">' . esc_html( __( 'Redirecting to Lingotek to connect your account...', 'lingotek-translation' ) ) . '</p></div>';
348
 
349
+ $connect_url = ( 0 === strcasecmp( $connect, 'new' ) ) ? $client->get_new_url( $redirect_url ) : $client->get_connect_url( $redirect_url );
350
  }
351
+ $connect_account_cloak_url_new = admin_url( 'admin.php?page=' . $this->plugin_slug . '_settings&connect=new' );
352
  $connect_account_cloak_url_prod = admin_url( 'admin.php?page=' . $this->plugin_slug . '_settings&connect=production' );
353
+ include LINGOTEK_ADMIN_INC . '/settings/connect-account.php';
354
  }
355
  }
356
 
363
  * @return array
364
  */
365
  public function get_profiles_settings( $defaults = false ) {
 
366
  $resources = get_option( 'lingotek_community_resources' );
367
+ $options = array(
368
+ 'manual' => __( 'Manual', 'lingotek-translation' ),
369
+ 'automatic' => __( 'Automatic', 'lingotek-translation' ),
370
  );
371
 
 
 
 
 
 
372
  $download_options = array(
373
+ 'manual' => __( 'Manual', 'lingotek-translation' ),
374
  'automatic' => __( 'Automatic', 'lingotek-translation' ),
375
  );
376
 
377
  return array(
378
+ 'upload' => array(
379
  'label' => __( 'Upload content', 'lingotek-translation' ),
380
  'options' => $options,
381
  'description' => __( 'How should new and modified content be uploaded to Lingotek?', 'lingotek-translation' ),
382
  ),
383
+ 'download' => array(
384
  'label' => __( 'Download translations', 'lingotek-translation' ),
385
  'options' => $download_options,
386
  'description' => __( 'How should completed translations be downloaded to WordPress?', 'lingotek-translation' ),
387
  ),
388
+ 'project_id' => array(
389
+ 'label' => $defaults ? __( 'Default Project', 'lingotek-translation' ) : __( 'Project', 'lingotek-translation' ),
390
  'options' => $resources['projects'],
391
  'description' => __( 'Changes will affect new entities only', 'lingotek-translation' ),
392
  ),
393
+ 'workflow_id' => array(
394
+ 'label' => $defaults ? __( 'Default Workflow', 'lingotek-translation' ) : __( 'Workflow', 'lingotek-translation' ),
395
  'options' => $resources['workflows'],
396
  'description' => __( 'Changes will affect new entities only', 'lingotek-translation' ),
397
  ),
398
+ 'primary_filter_id' => array(
399
  'label' => $defaults ? __( 'Primary Filter', 'lingotek-translation' ) : __( 'Primary Filter', 'lingotek-translation' ),
400
  'options' => $resources['filters'],
401
  'description' => __( 'Changes will affect new entities only', 'lingotek-translation' ),
430
  $profiles[ $content_types[ $type ]['profile'] ]['usage'] += 1;
431
  } elseif ( 'post' === $type ) {
432
  $profiles['automatic']['usage'] += 1;
433
+ } else {
434
+ $profiles['manual']['usage'] += 1;
435
  }
436
 
437
  if ( isset( $content_types[ $type ]['sources'] ) ) {
452
  * @param bool $update_first_project_callback boolean flag.
453
  */
454
  public function set_community_resources( $community_id, $update_first_project_callback = false ) {
455
+ $client = new Lingotek_API();
456
  $refresh_success = array(
457
+ 'projects' => false,
458
  'workflows' => false,
459
  );
460
 
469
  $client->update_callback_url( $project->properties->id );
470
  }
471
  }
472
+ // Order by title (case-insensitive).
473
+ natcasesort( $projects );
474
  $refresh_success['projects'] = true;
475
  }
476
 
477
+ $api_data = $client->get_workflows( $community_id );
478
  $default_workflows = array(
479
  'c675bd20-0688-11e2-892e-0800200c9a66' => 'Machine Translation',
480
  'ddf6e3c0-0688-11e2-892e-0800200c9a66' => 'Machine Translation + Post-Edit',
484
  '2210b148-0c44-4ae2-91d0-ca2ee47c069e' => 'Translation + 3 reviews',
485
  '7993b4d7-4ada-46d0-93d5-858db46c4c7d' => 'Translation Only',
486
  );
487
+ $workflows = array();
488
  if ( $api_data ) {
489
  foreach ( $api_data->entities as $workflow ) {
490
  $workflows[ $workflow->properties->id ] = $workflow->properties->title;
495
  'c675bd20-0688-11e2-892e-0800200c9a66' => 'Machine Translation',
496
  );
497
  }
498
+ // Order by title (case-insensitive).
499
+ natcasesort( $workflows );
500
+ if ( Lingotek_Professional_Translation_Workflow::is_allowed_user() ) {
501
  $workflows['ltk-professional-translation'] = 'Lingotek Professional Translation';
502
  }
503
+ $workflows = array_merge( array( 'project-default' => 'Use Project Default' ), $workflows );
504
  $refresh_success['workflows'] = true;
505
  }
506
+
507
  $api_data = $client->get_filters();
508
+ $filters = array();
509
  if ( $api_data && $api_data->properties->total > 0 ) {
510
  foreach ( $api_data->entities as $filter ) {
511
  if ( ! $filter->properties->is_public ) {
515
  $filters[ $filter->properties->id ] = $filter->properties->title;
516
  }
517
  }
518
+ $primary_filter_id = array_search( 'okf_json@with-html-subfilter.fprm', $filters, true );
519
  $secondary_filter_id = array_search( 'okf_html@wordpress.fprm', $filters, true );
520
+ $defaults = get_option( 'lingotek_defaults', array() );
521
+ if ( empty( $defaults ) ) {
522
+ $defaults['primary_filter_id'] = $primary_filter_id;
523
  $defaults['secondary_filter_id'] = $secondary_filter_id;
524
  update_option( 'lingotek_defaults', $defaults );
525
  }
526
  }
527
 
528
  $resources = array(
529
+ 'projects' => $projects,
530
  'workflows' => $workflows,
531
+ 'filters' => $filters,
532
  );
533
 
534
  if ( true === $refresh_success['projects'] || true === $refresh_success['workflows'] ) {
542
  * Ensures valid defaults.
543
  */
544
  public function ensure_valid_defaults() {
545
+ $resources = get_option( 'lingotek_community_resources' );
546
+ $defaults = get_option( 'lingotek_defaults', array() );
547
  $valid_default = array();
548
  foreach ( $resources as $resource_key => $options ) {
549
+ $key = substr( $resource_key, 0, strlen( $resource_key ) - 1 ) . '_id';
550
  $valid_default[ $key ] = 0;
551
+ if ( empty( $defaults ) ) {
552
  continue;
553
  }
554
  foreach ( $options as $option_key => $option_val ) {
562
  }
563
  }
564
  foreach ( $valid_default as $key => $valid ) {
565
+ $resource_key = substr( $key, 0, strpos( $key, '_' ) ) . 's';
566
  if ( $valid ) {
567
  continue;
568
  } else {
572
  $num_valid_defaults = array_sum( $valid_default );
573
 
574
  if ( $num_valid_defaults < count( $valid_default ) ) {
575
+ /* translators: %s: Admin url for Lingotek translation settings. */
576
  add_settings_error( 'lingotek_defaults', 'community-selected', sprintf( __( 'Your <a href="%s"><i>Defaults</i></a> have been updated to valid options for this community.', 'lingotek-translation' ), admin_url( 'admin.php?page=lingotek-translation_settings&sm=defaults' ) ), 'updated' );
577
  }
578
  unset( $defaults['filter_id'] );
592
  */
593
  ob_start();
594
  if ( self::has_token_details() ) {
595
+ include LINGOTEK_ADMIN_INC . '/view-manage.php';
596
  } else {
597
  $this->display_settings_page();
598
  }
605
  * @since 0.2
606
  */
607
  public function load_manage_page() {
608
+ add_screen_option(
609
+ 'per_page',
610
+ array(
611
+ 'label' => __( 'Strings groups', 'lingotek-translation' ),
612
+ 'default' => 10,
613
+ 'option' => 'lingotek_strings_per_page',
614
+ )
615
+ );
616
  }
617
 
618
  /**
640
  $token_details = self::has_token_details();
641
  if ( $token_details ) {
642
  $community_id = get_option( 'lingotek_community' );
643
+ $defaults = get_option( 'lingotek_defaults', array() );
644
+ $user = wp_get_current_user();
645
 
646
  // The data that will be passed to the Lingotek GMC dashboard.
647
  $cms_data = array(
648
+ // lingotek.
649
+ 'community_id' => $community_id,
650
+ 'external_id' => $token_details['login_id'],
651
+ 'workflow_id' => $defaults['workflow_id'],
652
+ 'project_id' => $defaults['project_id'],
653
+ 'first_name' => $user->display_name,
654
+ 'last_name' => '',
655
+ 'email' => get_bloginfo( 'admin_email' ),
656
+ // cms.
657
+ 'cms_site_id' => site_url(),
658
+ 'cms_site_key' => site_url(),
659
+ 'cms_site_name' => get_bloginfo( 'name' ),
660
+ 'cms_type' => 'Wordpress',
661
+ 'cms_version' => get_bloginfo( 'version' ),
662
+ 'cms_tag' => LINGOTEK_PLUGIN_SLUG,
663
+ 'locale' => pll_current_language( 'lingotek_locale' ),
664
+ 'module_version' => LINGOTEK_VERSION,
665
+ 'endpoint_url' => $this->get_dashboard_endpoint(),
666
  );
667
+ include LINGOTEK_ADMIN_INC . '/view-dashboard.php';
668
  } else {
669
  $this->display_settings_page();
670
+ }//end if
671
  }
672
 
673
  /**
677
  */
678
  public static function has_token_details() {
679
  $token_details = get_option( 'lingotek_token' );
680
+ $has_token = false;
681
  if ( false !== $token_details && key_exists( 'access_token', $token_details ) && key_exists( 'login_id', $token_details ) && strlen( $token_details['access_token'] ) && strlen( $token_details['login_id'] ) ) {
682
  $has_token = true;
683
  return $token_details;
690
  */
691
  public function display_network_settings_page() {
692
  if ( is_multisite() && self::has_token_details() ) {
693
+ include LINGOTEK_ADMIN_INC . '/view-network.php';
694
  } else {
695
  $this->display_settings_page();
696
  }
710
  */
711
  public function display_tutorial_page() {
712
  if ( self::has_token_details() ) {
713
+ include LINGOTEK_ADMIN_INC . '/view-tutorial.php';
714
  } else {
715
  $this->display_settings_page();
716
  }
722
  public function display_import_page() {
723
  if ( self::has_token_details() ) {
724
  settings_errors();
725
+ include LINGOTEK_ADMIN_INC . '/import.php';
726
  } else {
727
  $this->display_settings_page();
728
  }
729
  }
730
 
731
+ private function get_if_exists( $array, $key ) {
732
+ return is_array( $array ) && array_key_exists( $key, $array ) ? $array[ $key ] : null;
733
  }
734
 
735
  }
admin/content-table.php CHANGED
@@ -1,7 +1,8 @@
1
  <?php
2
 
3
  if ( ! class_exists( 'WP_List_Table' ) ) {
4
- require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' ); // since WP 3.1.
 
5
  }
6
 
7
  /**
@@ -27,13 +28,16 @@ class Lingotek_Content_Table extends WP_List_Table {
27
  * @param array $content_types array of content types.
28
  * @since 0.2
29
  */
30
- function __construct( $content_types ) {
31
- parent::__construct(array(
32
- 'plural' => 'lingotek-content', // do not translate (used for css class).
33
- 'ajax' => false,
34
- ));
 
 
 
35
 
36
- $this->profiles = Lingotek::get_profiles();
37
  $this->content_types = $content_types;
38
  }
39
 
@@ -44,14 +48,15 @@ class Lingotek_Content_Table extends WP_List_Table {
44
  *
45
  * @param array $item items.
46
  */
47
- function column_name( $item ) {
48
  global $polylang;
49
 
50
  printf( '<span class="content-type-name">%s</span>', esc_html( $item['name'] ) );
51
 
52
  // the source language for strings is always the default language.
53
  if ( 'string' !== $item['type'] ) {
54
- printf('<a id="id[%s]" class="dashicons dashicons-arrow-right" onclick="%s" href="#"></a>',
 
55
  esc_attr( $item['type'] ),
56
  "
57
  d1 = document.getElementById('sources-name[" . esc_html( $item['type'] ) . "]');
@@ -71,10 +76,11 @@ class Lingotek_Content_Table extends WP_List_Table {
71
 
72
  printf( '<ul class="sources-name" id="sources-name[%s]" style="display:none;">', esc_html( $item['type'] ) );
73
  foreach ( $polylang->model->get_languages_list() as $language ) {
 
74
  printf( '<li>%s</li>', sprintf( esc_html( __( '%s source', 'lingotek-translation' ) ), esc_html( $language->name ) ) );
75
  }
76
  echo '</ul>';
77
- }
78
  }
79
 
80
  /**
@@ -84,12 +90,12 @@ class Lingotek_Content_Table extends WP_List_Table {
84
  *
85
  * @param array $item item.
86
  */
87
- function column_profile( $item ) {
88
  global $polylang;
89
 
90
  printf( '<select class="content-type-profile" name="%1$s" id="%1$s">', esc_html( $item['type'] ) . '[profile]' );
91
  foreach ( $this->profiles as $key => $profile ) {
92
- $selected = (isset( $item['profile'] ) && $key === $item['profile']) ? 'selected="selected"' : '';
93
  echo "\n\t<option value='" . esc_attr( $key ) . "' " . esc_html( $selected ) . '>' . esc_html( $profile['name'] ) . '</option>';
94
  }
95
  echo '</select>';
@@ -102,7 +108,7 @@ class Lingotek_Content_Table extends WP_List_Table {
102
  foreach ( $polylang->model->get_languages_list() as $language ) {
103
  printf( '<li><select name="%1$s" id="%1$s">', esc_html( $item['type'] ) . '[sources][' . esc_html( $language->slug ) . ']' );
104
  foreach ( $options as $key => $profile ) {
105
- $selected = (isset( $item['sources'][ $language->slug ] ) && $key === $item['sources'][ $language->slug ]) ? 'selected="selected"' : '';
106
  echo "\n\t<option value='" . esc_attr( $key ) . "' " . esc_html( $selected ) . '>' . esc_html( $profile['name'] ) . '</option>';
107
  }
108
  echo '</select></li>';
@@ -124,7 +130,7 @@ class Lingotek_Content_Table extends WP_List_Table {
124
  protected function display_fields( $labels, $values, $name ) {
125
  foreach ( $labels as $key => $str ) {
126
  if ( is_array( $str ) ) {
127
- if ( 'metas' === $key ) {
128
  continue;
129
  }
130
  $this->display_fields( $str, isset( $values[ $key ] ) ? $values[ $key ] : array(), $name . "[$key]" );
@@ -146,10 +152,10 @@ class Lingotek_Content_Table extends WP_List_Table {
146
  *
147
  * @param array $item item.
148
  */
149
- function column_fields( $item ) {
150
  if ( ! empty( $item['fields'] ) ) {
151
  echo '<ul class="content-type-fields">';
152
- $this->display_fields( $item['fields']['label'], isset( $item['fields']['value'] ) ? $item['fields']['value'] : array() , $item['type'] . '[fields]' );
153
  echo '</ul>';
154
  }
155
  }
@@ -161,7 +167,7 @@ class Lingotek_Content_Table extends WP_List_Table {
161
  *
162
  * @return array the list of column titles
163
  */
164
- function get_columns() {
165
  return array(
166
  'name' => __( 'Content Type', 'lingotek-translation' ),
167
  'profile' => __( 'Profile', 'lingotek-translation' ),
@@ -176,7 +182,7 @@ class Lingotek_Content_Table extends WP_List_Table {
176
  *
177
  * @return array
178
  */
179
- function get_sortable_columns() {
180
  return array(
181
  'name' => array( 'name', false ),
182
  );
@@ -189,8 +195,8 @@ class Lingotek_Content_Table extends WP_List_Table {
189
  *
190
  * @param array $data data.
191
  */
192
- function prepare_items( $data = array() ) {
193
- $per_page = $this->get_items_per_page( 'lingotek_content_per_page' );
194
  $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() );
195
 
196
  /**
@@ -201,23 +207,28 @@ class Lingotek_Content_Table extends WP_List_Table {
201
  * @return int sort direction.
202
  */
203
  function usort_reorder( $a, $b ) {
204
- $order = filter_input( INPUT_GET, 'order' );
205
  $orderby = filter_input( INPUT_GET, 'orderby' );
206
- $result = strcmp( $a[ $orderby ], $b[ $orderby ] ); // determine sort order.
207
- return (empty( $order ) || $order === 'asc') ? $result : -$result; // send final sort direction to usort.
 
 
208
  };
209
 
210
- if ( ! empty( $orderby ) ) { // no sort by default.
 
211
  usort( $data, 'usort_reorder' );
212
  }
213
 
214
  $total_items = count( $data );
215
- $this->items = array_slice( $data, ($this->get_pagenum() - 1) * $per_page, $per_page );
216
-
217
- $this->set_pagination_args(array(
218
- 'total_items' => $total_items,
219
- 'per_page' => $per_page,
220
- 'total_pages' => ceil( $total_items / $per_page ),
221
- ));
 
 
222
  }
223
  }
1
  <?php
2
 
3
  if ( ! class_exists( 'WP_List_Table' ) ) {
4
+ // Since WP 3.1.
5
+ require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
6
  }
7
 
8
  /**
28
  * @param array $content_types array of content types.
29
  * @since 0.2
30
  */
31
+ public function __construct( $content_types ) {
32
+ parent::__construct(
33
+ array(
34
+ // Do not translate (used for css class).
35
+ 'plural' => 'lingotek-content',
36
+ 'ajax' => false,
37
+ )
38
+ );
39
 
40
+ $this->profiles = Lingotek::get_profiles();
41
  $this->content_types = $content_types;
42
  }
43
 
48
  *
49
  * @param array $item items.
50
  */
51
+ protected function column_name( $item ) {
52
  global $polylang;
53
 
54
  printf( '<span class="content-type-name">%s</span>', esc_html( $item['name'] ) );
55
 
56
  // the source language for strings is always the default language.
57
  if ( 'string' !== $item['type'] ) {
58
+ printf(
59
+ '<a id="id[%s]" class="dashicons dashicons-arrow-right" onclick="%s" href="#"></a>',
60
  esc_attr( $item['type'] ),
61
  "
62
  d1 = document.getElementById('sources-name[" . esc_html( $item['type'] ) . "]');
76
 
77
  printf( '<ul class="sources-name" id="sources-name[%s]" style="display:none;">', esc_html( $item['type'] ) );
78
  foreach ( $polylang->model->get_languages_list() as $language ) {
79
+ /* translators: %s: The language name. */
80
  printf( '<li>%s</li>', sprintf( esc_html( __( '%s source', 'lingotek-translation' ) ), esc_html( $language->name ) ) );
81
  }
82
  echo '</ul>';
83
+ }//end if
84
  }
85
 
86
  /**
90
  *
91
  * @param array $item item.
92
  */
93
+ protected function column_profile( $item ) {
94
  global $polylang;
95
 
96
  printf( '<select class="content-type-profile" name="%1$s" id="%1$s">', esc_html( $item['type'] ) . '[profile]' );
97
  foreach ( $this->profiles as $key => $profile ) {
98
+ $selected = ( isset( $item['profile'] ) && $key === $item['profile'] ) ? 'selected="selected"' : '';
99
  echo "\n\t<option value='" . esc_attr( $key ) . "' " . esc_html( $selected ) . '>' . esc_html( $profile['name'] ) . '</option>';
100
  }
101
  echo '</select>';
108
  foreach ( $polylang->model->get_languages_list() as $language ) {
109
  printf( '<li><select name="%1$s" id="%1$s">', esc_html( $item['type'] ) . '[sources][' . esc_html( $language->slug ) . ']' );
110
  foreach ( $options as $key => $profile ) {
111
+ $selected = ( isset( $item['sources'][ $language->slug ] ) && $key === $item['sources'][ $language->slug ] ) ? 'selected="selected"' : '';
112
  echo "\n\t<option value='" . esc_attr( $key ) . "' " . esc_html( $selected ) . '>' . esc_html( $profile['name'] ) . '</option>';
113
  }
114
  echo '</select></li>';
130
  protected function display_fields( $labels, $values, $name ) {
131
  foreach ( $labels as $key => $str ) {
132
  if ( is_array( $str ) ) {
133
+ if ( 'metas' === $key ) {
134
  continue;
135
  }
136
  $this->display_fields( $str, isset( $values[ $key ] ) ? $values[ $key ] : array(), $name . "[$key]" );
152
  *
153
  * @param array $item item.
154
  */
155
+ protected function column_fields( $item ) {
156
  if ( ! empty( $item['fields'] ) ) {
157
  echo '<ul class="content-type-fields">';
158
+ $this->display_fields( $item['fields']['label'], isset( $item['fields']['value'] ) ? $item['fields']['value'] : array(), $item['type'] . '[fields]' );
159
  echo '</ul>';
160
  }
161
  }
167
  *
168
  * @return array the list of column titles
169
  */
170
+ public function get_columns() {
171
  return array(
172
  'name' => __( 'Content Type', 'lingotek-translation' ),
173
  'profile' => __( 'Profile', 'lingotek-translation' ),
182
  *
183
  * @return array
184
  */
185
+ public function get_sortable_columns() {
186
  return array(
187
  'name' => array( 'name', false ),
188
  );
195
  *
196
  * @param array $data data.
197
  */
198
+ public function prepare_items( $data = array() ) {
199
+ $per_page = $this->get_items_per_page( 'lingotek_content_per_page' );
200
  $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() );
201
 
202
  /**
207
  * @return int sort direction.
208
  */
209
  function usort_reorder( $a, $b ) {
210
+ $order = filter_input( INPUT_GET, 'order' );
211
  $orderby = filter_input( INPUT_GET, 'orderby' );
212
+ // Determine sort order.
213
+ $result = strcmp( $a[ $orderby ], $b[ $orderby ] );
214
+ // Send final sort direction to usort.
215
+ return ( empty( $order ) || 'asc' === $order ) ? $result : -$result;
216
  };
217
 
218
+ // No sort by default.
219
+ if ( ! empty( $orderby ) ) {
220
  usort( $data, 'usort_reorder' );
221
  }
222
 
223
  $total_items = count( $data );
224
+ $this->items = array_slice( $data, ( $this->get_pagenum() - 1 ) * $per_page, $per_page );
225
+
226
+ $this->set_pagination_args(
227
+ array(
228
+ 'total_items' => $total_items,
229
+ 'per_page' => $per_page,
230
+ 'total_pages' => ceil( $total_items / $per_page ),
231
+ )
232
+ );
233
  }
234
  }
admin/custom-fields-table.php CHANGED
@@ -1,7 +1,8 @@
1
  <?php
2
 
3
  if ( ! class_exists( 'WP_List_Table' ) ) {
4
- require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' ); // since WP 3.1.
 
5
  }
6
 
7
  /**
@@ -26,11 +27,14 @@ class Lingotek_Custom_Fields_Table extends WP_List_Table {
26
  *
27
  * @since 0.2
28
  */
29
- function __construct() {
30
- parent::__construct(array(
31
- 'plural' => 'lingotek-custom-fields', // do not translate (used for css class).
32
- 'ajax' => false,
33
- ));
 
 
 
34
  }
35
 
36
  /**
@@ -40,10 +44,11 @@ class Lingotek_Custom_Fields_Table extends WP_List_Table {
40
  *
41
  * @param array $item item.
42
  * @return string
 
 
43
  */
44
- function column_meta_key( $item ) {
45
- // var_dump($item);
46
- printf('<input type="checkbox" onClick="show(this);" class="boxes" name="%s" value="value1" > ',$item['meta_key'] );
47
  return isset( $item['meta_key'] ) ? esc_html( $item['meta_key'] ) : '';
48
  }
49
 
@@ -53,12 +58,12 @@ class Lingotek_Custom_Fields_Table extends WP_List_Table {
53
  * @since 0.2
54
  *
55
  * @param array $item item.
 
 
56
  */
57
- function column_setting( $item ) {
58
- //var_dump($item);
59
- $settings = array( 'translate', 'copy', 'ignore' );
60
  $custom_field_choices = get_option( 'lingotek_custom_fields', array() );
61
- //var_dump($custom_field_choices);
62
  printf( '<select class="custom-field-setting" name="%1$s" id="%1$s">', 'settings[' . esc_html( $item['meta_key'] ) . ']' );
63
 
64
  // select the option from the lingotek_custom_fields option.
@@ -80,11 +85,11 @@ class Lingotek_Custom_Fields_Table extends WP_List_Table {
80
  *
81
  * @return array the list of column titles
82
  */
83
- function get_columns() {
84
  return array(
85
-
86
- 'meta_key' => __( '<input type="checkbox" id="master" onClick="toggle(this);" value="value2" > Custom Field Key', 'lingotek-translation' ),
87
- 'setting' => __( 'Action', 'lingotek-translation' ),
88
  );
89
  }
90
 
@@ -95,9 +100,10 @@ class Lingotek_Custom_Fields_Table extends WP_List_Table {
95
  *
96
  * @return array
97
  */
98
- function get_sortable_columns() {
99
  return array(
100
- 'meta_key' => array( 'meta_key', false ),
 
101
  );
102
  }
103
 
@@ -108,7 +114,7 @@ class Lingotek_Custom_Fields_Table extends WP_List_Table {
108
  *
109
  * @param array $data data.
110
  */
111
- function prepare_items( $data = array() ) {
112
  $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() );
113
 
114
  /**
@@ -119,22 +125,27 @@ class Lingotek_Custom_Fields_Table extends WP_List_Table {
119
  * @return int sort direction.
120
  */
121
  function usort_reorder( $a, $b ) {
122
- $order = filter_input( INPUT_GET, 'order' );
123
  $orderby = filter_input( INPUT_GET, 'orderby' );
124
- $result = strcmp( $a[ $orderby ], $b[ $orderby ] ); // determine sort order.
125
- return (empty( $order ) || 'asc' === $order ) ? $result : -$result; // send final sort direction to usort.
 
 
126
  };
127
 
128
- if ( ! empty( $orderby ) ) { // no sort by default.
 
129
  usort( $data, 'usort_reorder' );
130
  }
131
 
132
  $total_items = count( $data );
133
  $this->items = $data;
134
 
135
- $this->set_pagination_args(array(
136
- 'total_items' => $total_items,
137
- 'per_page' => count( $data ),
138
- ));
 
 
139
  }
140
  }
1
  <?php
2
 
3
  if ( ! class_exists( 'WP_List_Table' ) ) {
4
+ // Since WP 3.1.
5
+ require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
6
  }
7
 
8
  /**
27
  *
28
  * @since 0.2
29
  */
30
+ public function __construct() {
31
+ parent::__construct(
32
+ array(
33
+ // Do not translate (used for css class).
34
+ 'plural' => 'lingotek-custom-fields',
35
+ 'ajax' => false,
36
+ )
37
+ );
38
  }
39
 
40
  /**
44
  *
45
  * @param array $item item.
46
  * @return string
47
+ *
48
+ * @deprecated Unused?
49
  */
50
+ protected function column_meta_key( $item ) {
51
+ printf( '<input type="checkbox" onClick="show(this);" class="boxes" name="%s" value="value1" > ', esc_html( $item['meta_key'] ) );
 
52
  return isset( $item['meta_key'] ) ? esc_html( $item['meta_key'] ) : '';
53
  }
54
 
58
  * @since 0.2
59
  *
60
  * @param array $item item.
61
+ *
62
+ * @deprecated Unused?
63
  */
64
+ protected function column_setting( $item ) {
65
+ $settings = array( 'translate', 'copy', 'ignore' );
 
66
  $custom_field_choices = get_option( 'lingotek_custom_fields', array() );
 
67
  printf( '<select class="custom-field-setting" name="%1$s" id="%1$s">', 'settings[' . esc_html( $item['meta_key'] ) . ']' );
68
 
69
  // select the option from the lingotek_custom_fields option.
85
  *
86
  * @return array the list of column titles
87
  */
88
+ public function get_columns() {
89
  return array(
90
+ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
91
+ 'meta_key' => __( '<input type="checkbox" id="master" onClick="toggle(this);" value="value2" > Custom Field Key', 'lingotek-translation' ),
92
+ 'setting' => __( 'Action', 'lingotek-translation' ),
93
  );
94
  }
95
 
100
  *
101
  * @return array
102
  */
103
+ public function get_sortable_columns() {
104
  return array(
105
+ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
106
+ 'meta_key' => array( 'meta_key', false ),
107
  );
108
  }
109
 
114
  *
115
  * @param array $data data.
116
  */
117
+ public function prepare_items( $data = array() ) {
118
  $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() );
119
 
120
  /**
125
  * @return int sort direction.
126
  */
127
  function usort_reorder( $a, $b ) {
128
+ $order = filter_input( INPUT_GET, 'order' );
129
  $orderby = filter_input( INPUT_GET, 'orderby' );
130
+ // Determine sort order.
131
+ $result = strcmp( $a[ $orderby ], $b[ $orderby ] );
132
+ // Send final sort direction to usort.
133
+ return ( empty( $order ) || 'asc' === $order ) ? $result : -$result;
134
  };
135
 
136
+ // No sort by default.
137
+ if ( ! empty( $orderby ) ) {
138
  usort( $data, 'usort_reorder' );
139
  }
140
 
141
  $total_items = count( $data );
142
  $this->items = $data;
143
 
144
+ $this->set_pagination_args(
145
+ array(
146
+ 'total_items' => $total_items,
147
+ 'per_page' => count( $data ),
148
+ )
149
+ );
150
  }
151
  }
admin/filters-columns.php CHANGED
@@ -42,14 +42,15 @@ class Lingotek_Filters_Columns extends PLL_Admin_Filters_Columns {
42
  protected function add_column( $columns, $before ) {
43
  $n = array_search( $before, array_keys( $columns ), true );
44
  if ( $n ) {
45
- $end = array_slice( $columns, $n );
46
  $columns = array_slice( $columns, 0, $n );
47
  }
48
  $this->print_patch_error();
49
  $this->print_cancel_error();
50
  foreach ( $this->model->get_languages_list() as $language ) {
51
  $columns[ 'language_' . $language->locale ] = $language->flag ? $language->flag :
52
- sprintf('<a href="" title="%s">%s</a>',
 
53
  esc_html( "$language->name ($language->locale)" ),
54
  esc_html( $language->slug )
55
  );
@@ -59,41 +60,53 @@ class Lingotek_Filters_Columns extends PLL_Admin_Filters_Columns {
59
  }
60
 
61
  private function print_cancel_error() {
62
- $lingotek_log_errors = get_option('lingotek_log_errors');
63
- $message = isset($lingotek_log_errors['disassociate_document_error']) ? $lingotek_log_errors['disassociate_document_error'] : '';
64
- if (get_option('disassociate_source_failed', FALSE)) {
65
- $message = str_replace('cancel', 'delete', $message);
66
- printf('<div class="notice notice-warning is-dismissible">
 
67
  <p>%s</p>
68
- </div>', $message);
69
- update_option('disassociate_source_failed', FALSE);
70
- } elseif (get_option('disassociate_target_failed', FALSE)) {
71
- $message = str_replace('cancel', 'delete', $message);
72
- printf('<div class="notice notice-warning is-dismissible">
 
 
 
73
  <p>%s</p>
74
- </div>', $message);
75
- update_option('disassociate_target_failed', FALSE);
76
- } elseif (get_option('cancel_source_failed', FALSE)) {
77
- printf('<div class="notice notice-warning is-dismissible">
 
 
 
78
  <p>%s</p>
79
- </div>', $message);
80
- update_option('cancel_source_failed', FALSE);
81
- } elseif (get_option('cancel_target_failed', FALSE)) {
82
- printf('<div class="notice notice-warning is-dismissible">
 
 
 
83
  <p>%s</p>
84
- </div>', $message);
85
- update_option('cancel_target_failed', FALSE);
86
- }
 
 
87
  }
88
 
89
  private function print_patch_error() {
90
- $lingotek_log_errors = get_option('lingotek_log_errors');
91
- if (empty($lingotek_log_errors['patch_document_error'])) {
92
  return;
93
  }
94
- printf('<div class="notice notice-error is-dismissible"><p>%s</p></div>', $lingotek_log_errors['patch_document_error']);
95
- unset($lingotek_log_errors['patch_document_error']);
96
- update_option('lingotek_log_errors', $lingotek_log_errors, false);
97
  }
98
 
99
  /**
@@ -108,11 +121,11 @@ class Lingotek_Filters_Columns extends PLL_Admin_Filters_Columns {
108
  * @param item $custom_data data.
109
  */
110
  protected function _column( $type, $column, $object_id, $custom_data = null ) {
111
- $action = 'post' === $type ? 'inline-save' : 'inline-save-tax';
112
- $get_action = filter_input( INPUT_GET, 'action' );
113
  $inline_lang_choice = filter_input( INPUT_POST, 'inline_lang_choice' );
114
- $inline = defined( 'DOING_AJAX' ) && $get_action === $action && ! empty( $inline_lang_choice );
115
- $lang = $inline ? $this->model->get_language( $inline_lang_choice ) : ('post' === $type ? PLL()->model->post->get_language( $object_id ) : PLL()->model->term->get_language( $object_id ));
116
 
117
  if ( false === strpos( $column, 'language_' ) || ! $lang ) {
118
  if ( $custom_data ) {
@@ -132,91 +145,82 @@ class Lingotek_Filters_Columns extends PLL_Admin_Filters_Columns {
132
  printf( '<div class="hidden" id="lang_%d">%s</div>', esc_attr( $object_id ), esc_html( $lang->slug ) );
133
  }
134
 
135
- $id = (($inline && $lang->slug !== $this->model->get_language( filter_input( INPUT_POST, 'old_lang' ) )->slug) ?
136
- ($language->slug === $lang->slug ? $object_id : 0) :
137
- 'post' === $type) ? PLL()->model->post->get( $object_id, $language ) : PLL()->model->term->get( $object_id, $language );
138
 
139
  $document = $this->lgtm->get_group( $type, $object_id );
140
  if ( isset( $document->source ) ) {
141
  $source_language = 'post' === $type ? PLL()->model->post->get_language( $document->source ) : PLL()->model->term->get_language( $document->source );
142
- $source_profile = Lingotek_Model::get_profile( $this->content_type, $source_language, $document->source );
143
  } else {
144
  $source_language = $lang;
145
  }
146
 
147
  // FIXME not very clean.
148
- $actions = 'post' === $type ? $GLOBALS['wp_lingotek']->post_actions : $GLOBALS['wp_lingotek']->term_actions;
149
- $profile = Lingotek_Model::get_profile( $this->content_type, $language, $object_id );
150
- $cancelled = isset($document->status) ? $document->status === 'cancelled': false;
151
- $disabled = 'disabled' === $profile['profile'] || !Lingotek::is_allowed_tms_locale($language->lingotek_locale);
152
  // post ready for upload.
153
- if (!$cancelled && $this->lgtm->can_upload( $type, $object_id ) && $object_id === $id ) {
154
- return $disabled ? ('post' === $type ? parent::post_column( $column, $object_id ) : parent::term_column( '', $column, $object_id ))
155
- : ($document && (count( $document->desc_array ) >= 3) ? $actions->upload_icon( $object_id, true ) : $actions->upload_icon( $object_id ));
156
- } // if language is set to copy and profile is manual.
157
- elseif (('post' === $type || 'term' === $type) && ((isset( $source_profile['targets'][ $language->slug ] ) &&
158
- 'copy' === $source_profile['targets'][ $language->slug ]) || (isset( $profile['targets'][ $language->slug ] ) &&
159
- 'copy' === $profile['targets'][ $language->slug ] ) && isset( $document->source ))) {
160
- if (isset( $document->desc_array[ $language->slug ])) {
161
- return ('post' === $type) ? parent::post_column( $column, $object_id ) : parent::term_column( '', $column, $object_id );
162
- }
163
- else {
164
- if ( $document ) {
165
- return $actions->copy_icon( $document->source, $language->slug );
166
  }
167
- else {
168
- return $actions->copy_icon( $object_id, $language->slug );
169
- }
170
- }
171
- } // translation disabled.
172
- elseif (( isset( $document->source ) && $document->is_disabled_target( $source_language, $language ) &&
173
- ! isset( $document->translations[ $language->locale ] ) ) || !Lingotek::is_allowed_tms_locale($language->lingotek_locale) ) {
174
  return 'post' === $type ? parent::post_column( $column, $object_id ) : parent::term_column( '', $column, $object_id );
175
- } // source post is uploaded.
176
- elseif ( !$cancelled && isset( $document->source ) && $document->source === $id ) {
177
- // source ready for upload.
178
- // TODO: We don't need that anymore
179
- delete_option( $document->source );
180
- if ( $this->lgtm->can_upload( $type, $id ) ) {
181
- return $actions->upload_icon( $id );
182
  }
183
- // importing source.
184
- if ( $id === $object_id && 'importing' === $document->status ) {
185
  return Lingotek_Actions::importing_icon( $document );
186
  }
187
  // source failed
188
- if ($id === $object_id && 'failed' === $document->status) {
189
- return $actions->failed_import_icon($document->status, $object_id);
190
  }
191
- return 'post' === $type ? Lingotek_Post_actions::uploaded_icon( $id ) : Lingotek_Term_actions::uploaded_icon( $id );
192
- } // translations.
193
- elseif ( isset( $document->translations[ $language->locale ] ) || (isset( $document->source ) && 'current' === $document->status) ) {
194
  return Lingotek_Actions::translation_icon( $document, $language );
195
- }
196
- elseif ( ( 'term' === $type && ! isset( $document->translations[ $language->locale ] ) && $document->source !== $object_id ) || !Lingotek::is_allowed_tms_locale($language->lingotek_locale) ) {
197
  return parent::term_column( '', $column, $object_id );
198
- } // translations exist but are not managed by Lingotek TMS.
199
- elseif ( empty( $document->source ) ) {
200
- return $object_id === $id && ! $disabled ? $actions->upload_icon( $object_id, true ) : ('post' === $type ? parent::post_column( $column, $object_id ) : parent::term_column( '', $column, $object_id ));
201
- }
202
- elseif ($document->status == 'failed') {
203
- return $actions->failed_import_icon($document->status, $object_id);
204
- }
205
- elseif ($this->lgtm->can_upload( $type, $id ) && $document->status === 'cancelled') {
206
- return $disabled ? ('post' === $type ? parent::post_column( $column, $object_id ) : parent::term_column( '', $column, $object_id ))
207
- : ($document && (count( $document->desc_array ) >= 3) ? $actions->cancelled_icon( $object_id, false, true ) : $actions->cancelled_icon( $object_id ));
208
- }
209
- // no translation.
210
- else {
211
  /**
212
  * There is no record of a translation, but the entire document has been cancelled
213
  * so we just mark all locales as cancelled since the user will have to re upload the document
214
  */
215
- if ($document->status === 'cancelled') {
216
- return $actions->cancelled_icon($object_id, true);
217
  }
218
  return '<div class="lingotek-color dashicons dashicons-no"></div>';
219
- }
220
  }
221
 
222
  /**
@@ -229,39 +233,40 @@ class Lingotek_Filters_Columns extends PLL_Admin_Filters_Columns {
229
  * @param int $post_id post id.
230
  */
231
  public function post_column( $column, $post_id ) {
232
- if ( false === strpos( $column, 'language_' )) {
233
  return;
234
  }
235
  $this->content_type = get_post_type( $post_id );
236
 
237
  $allowed_html = array(
238
- 'a' => array(
239
- 'href' => array(),
240
- 'class' => array(),
241
- 'title' => array(),
242
- 'target' => array()
243
  ),
244
  'div' => array(
245
  'title' => array(),
246
  'class' => array(),
247
  ),
248
  'img' => array(
249
- 'src' => array()
250
- )
251
  );
252
  echo wp_kses( $this->_column( 'post', $column, $post_id ), $allowed_html );
253
 
254
  /**
255
- * Setup workflow specific logic for posts.
256
  */
257
- $post = get_post( $post_id );
258
  $source_language = PLL()->model->post->get_language( $post_id );
259
  $target_language = $this->model->get_language( substr( $column, 9 ) );
260
- if (is_object($source_language) && is_object($target_language)) {
261
  $workflow_id = Lingotek_Model::get_profile_option( 'workflow_id', $post->post_type, $source_language, $target_language, $post_id );
262
- $workflow = Lingotek_Workflow_Factory::get_workflow_instance( $workflow_id );
263
  // $workflow->override_events( $workflow_id ); // Loads appropriate .js file.
264
- $workflow->echo_posts_modal( $post_id, $target_language->locale ); // adds modal html to page.
 
265
  }
266
 
267
  // checking for api errors.
@@ -285,39 +290,40 @@ class Lingotek_Filters_Columns extends PLL_Admin_Filters_Columns {
285
  * @param int $term_id term id.
286
  */
287
  public function term_column( $custom_data, $column, $term_id ) {
288
- if ( false === strpos( $column, 'language_' )) {
289
  return;
290
  }
291
- $allowed_html = array(
292
- 'a' => array(
293
- 'href' => array(),
294
- 'class' => array(),
295
- 'title' => array(),
296
- 'target' => array()
297
  ),
298
- 'div' => array(
299
  'title' => array(),
300
  'class' => array(),
301
  ),
302
  'span' => array(
303
  'class' => array(),
304
  ),
305
- 'img' => array(
306
- 'src' => array()
307
- )
308
  );
309
  $this->content_type = $GLOBALS['taxonomy'];
310
 
311
  /**
312
- * Setup workflow specific logic for terms.
313
  */
314
  $source_language = PLL()->model->term->get_language( $term_id );
315
  $target_language = $this->model->get_language( substr( $column, 9 ) );
316
- if (is_object($source_language) && is_object($target_language)) {
317
  $workflow_id = Lingotek_Model::get_profile_option( 'workflow_id', $this->content_type, $source_language, $target_language );
318
- $workflow = Lingotek_Workflow_Factory::get_workflow_instance( $workflow_id );
319
  // $workflow->override_events( $workflow_id ); // Loads appropriate .js file.
320
- $workflow->echo_terms_modal( $term_id, $target_language->locale); // adds modal html to page.
 
321
  }
322
 
323
  if ( ! $custom_data ) {
@@ -340,19 +346,19 @@ class Lingotek_Filters_Columns extends PLL_Admin_Filters_Columns {
340
  */
341
  protected function error_icon_html( $column, $object_id, $source_locale = null ) {
342
  // checking for api errors.
343
- $source_column = substr( $column, 9 );
344
  $column_language_only = substr( $column, 0, 11 );
345
- $errors = get_option( 'lingotek_log_errors' );
346
 
347
  if ( $source_column === $source_locale ) {
348
  if ( isset( $errors[ $object_id ] ) ) {
349
- $api_error = Lingotek_Actions::retrieve_api_error( $errors[ $object_id ] );
350
  $allowed_html = array(
351
  'a' => array(
352
- 'href' => array(),
353
- 'class' => array(),
354
- 'title' => array(),
355
- 'target' => array()
356
  ),
357
  );
358
  echo wp_kses( Lingotek_Actions::display_error_icon( 'error', $api_error ), $allowed_html );
42
  protected function add_column( $columns, $before ) {
43
  $n = array_search( $before, array_keys( $columns ), true );
44
  if ( $n ) {
45
+ $end = array_slice( $columns, $n );
46
  $columns = array_slice( $columns, 0, $n );
47
  }
48
  $this->print_patch_error();
49
  $this->print_cancel_error();
50
  foreach ( $this->model->get_languages_list() as $language ) {
51
  $columns[ 'language_' . $language->locale ] = $language->flag ? $language->flag :
52
+ sprintf(
53
+ '<a href="" title="%s">%s</a>',
54
  esc_html( "$language->name ($language->locale)" ),
55
  esc_html( $language->slug )
56
  );
60
  }
61
 
62
  private function print_cancel_error() {
63
+ $lingotek_log_errors = get_option( 'lingotek_log_errors' );
64
+ $message = isset( $lingotek_log_errors['disassociate_document_error'] ) ? $lingotek_log_errors['disassociate_document_error'] : '';
65
+ if ( get_option( 'disassociate_source_failed', false ) ) {
66
+ $message = str_replace( 'cancel', 'delete', $message );
67
+ printf(
68
+ '<div class="notice notice-warning is-dismissible">
69
  <p>%s</p>
70
+ </div>',
71
+ esc_html( $message )
72
+ );
73
+ update_option( 'disassociate_source_failed', false );
74
+ } elseif ( get_option( 'disassociate_target_failed', false ) ) {
75
+ $message = str_replace( 'cancel', 'delete', $message );
76
+ printf(
77
+ '<div class="notice notice-warning is-dismissible">
78
  <p>%s</p>
79
+ </div>',
80
+ esc_html( $message )
81
+ );
82
+ update_option( 'disassociate_target_failed', false );
83
+ } elseif ( get_option( 'cancel_source_failed', false ) ) {
84
+ printf(
85
+ '<div class="notice notice-warning is-dismissible">
86
  <p>%s</p>
87
+ </div>',
88
+ esc_html( $message )
89
+ );
90
+ update_option( 'cancel_source_failed', false );
91
+ } elseif ( get_option( 'cancel_target_failed', false ) ) {
92
+ printf(
93
+ '<div class="notice notice-warning is-dismissible">
94
  <p>%s</p>
95
+ </div>',
96
+ esc_html( $message )
97
+ );
98
+ update_option( 'cancel_target_failed', false );
99
+ }//end if
100
  }
101
 
102
  private function print_patch_error() {
103
+ $lingotek_log_errors = get_option( 'lingotek_log_errors' );
104
+ if ( empty( $lingotek_log_errors['patch_document_error'] ) ) {
105
  return;
106
  }
107
+ printf( '<div class="notice notice-error is-dismissible"><p>%s</p></div>', esc_html( $lingotek_log_errors['patch_document_error'] ) );
108
+ unset( $lingotek_log_errors['patch_document_error'] );
109
+ update_option( 'lingotek_log_errors', $lingotek_log_errors, false );
110
  }
111
 
112
  /**
121
  * @param item $custom_data data.
122
  */
123
  protected function _column( $type, $column, $object_id, $custom_data = null ) {
124
+ $action = 'post' === $type ? 'inline-save' : 'inline-save-tax';
125
+ $get_action = filter_input( INPUT_GET, 'action' );
126
  $inline_lang_choice = filter_input( INPUT_POST, 'inline_lang_choice' );
127
+ $inline = defined( 'DOING_AJAX' ) && $get_action === $action && ! empty( $inline_lang_choice );
128
+ $lang = $inline ? $this->model->get_language( $inline_lang_choice ) : ( 'post' === $type ? PLL()->model->post->get_language( $object_id ) : PLL()->model->term->get_language( $object_id ) );
129
 
130
  if ( false === strpos( $column, 'language_' ) || ! $lang ) {
131
  if ( $custom_data ) {
145
  printf( '<div class="hidden" id="lang_%d">%s</div>', esc_attr( $object_id ), esc_html( $lang->slug ) );
146
  }
147
 
148
+ $id = ( ( $inline && $lang->slug !== $this->model->get_language( filter_input( INPUT_POST, 'old_lang' ) )->slug ) ?
149
+ ( $language->slug === $lang->slug ? $object_id : 0 ) :
150
+ 'post' === $type ) ? PLL()->model->post->get( $object_id, $language ) : PLL()->model->term->get( $object_id, $language );
151
 
152
  $document = $this->lgtm->get_group( $type, $object_id );
153
  if ( isset( $document->source ) ) {
154
  $source_language = 'post' === $type ? PLL()->model->post->get_language( $document->source ) : PLL()->model->term->get_language( $document->source );
155
+ $source_profile = Lingotek_Model::get_profile( $this->content_type, $source_language, $document->source );
156
  } else {
157
  $source_language = $lang;
158
  }
159
 
160
  // FIXME not very clean.
161
+ $actions = 'post' === $type ? $GLOBALS['wp_lingotek']->post_actions : $GLOBALS['wp_lingotek']->term_actions;
162
+ $profile = Lingotek_Model::get_profile( $this->content_type, $language, $object_id );
163
+ $cancelled = isset( $document->status ) ? 'cancelled' === $document->status : false;
164
+ $disabled = 'disabled' === $profile['profile'] || ! Lingotek::is_allowed_tms_locale( $language->lingotek_locale );
165
  // post ready for upload.
166
+ if ( ! $cancelled && $this->lgtm->can_upload( $type, $object_id ) && $object_id === $id ) {
167
+ return $disabled ? ( 'post' === $type ? parent::post_column( $column, $object_id ) : parent::term_column( '', $column, $object_id ) )
168
+ : ( $document && ( count( $document->desc_array ) >= 3 ) ? $actions->upload_icon( $object_id, true ) : $actions->upload_icon( $object_id ) );
169
+ } elseif ( ( 'post' === $type || 'term' === $type ) && ( ( isset( $source_profile['targets'][ $language->slug ] ) &&
170
+ 'copy' === $source_profile['targets'][ $language->slug ] ) || ( isset( $profile['targets'][ $language->slug ] ) &&
171
+ 'copy' === $profile['targets'][ $language->slug ] ) && isset( $document->source ) ) ) {
172
+ if ( isset( $document->desc_array[ $language->slug ] ) ) {
173
+ return ( 'post' === $type ) ? parent::post_column( $column, $object_id ) : parent::term_column( '', $column, $object_id );
174
+ } else {
175
+ if ( $document ) {
176
+ return $actions->copy_icon( $document->source, $language->slug );
177
+ } else {
178
+ return $actions->copy_icon( $object_id, $language->slug );
179
  }
180
+ }
181
+ } elseif ( ( isset( $document->source ) && $document->is_disabled_target( $source_language, $language ) &&
182
+ ! isset( $document->translations[ $language->locale ] ) ) || ! Lingotek::is_allowed_tms_locale( $language->lingotek_locale ) ) {
183
+ // translation disabled.
 
 
 
184
  return 'post' === $type ? parent::post_column( $column, $object_id ) : parent::term_column( '', $column, $object_id );
185
+ } elseif ( ! $cancelled && isset( $document->source ) && $document->source === $id ) {
186
+ // Source post is uploaded.
187
+ // Source is ready for upload.
188
+ if ( $this->lgtm->can_upload( $type, $id ) ) {
189
+ return $actions->upload_icon( $id );
 
 
190
  }
191
+ // importing source.
192
+ if ( $id === $object_id && 'importing' === $document->status ) {
193
  return Lingotek_Actions::importing_icon( $document );
194
  }
195
  // source failed
196
+ if ( $id === $object_id && 'failed' === $document->status ) {
197
+ return $actions->failed_import_icon( $document->status, $object_id );
198
  }
199
+ return 'post' === $type ? Lingotek_Post_Actions::uploaded_icon( $id ) : Lingotek_Term_actions::uploaded_icon( $id );
200
+ } elseif ( isset( $document->translations[ $language->locale ] ) || ( isset( $document->source ) && 'current' === $document->status ) ) {
201
+ // translations.
202
  return Lingotek_Actions::translation_icon( $document, $language );
203
+ } elseif ( ( 'term' === $type && ! isset( $document->translations[ $language->locale ] ) && $document->source !== $object_id ) || ! Lingotek::is_allowed_tms_locale( $language->lingotek_locale ) ) {
 
204
  return parent::term_column( '', $column, $object_id );
205
+ } elseif ( empty( $document->source ) ) {
206
+ // translations exist but are not managed by Lingotek TMS.
207
+ return $object_id === $id && ! $disabled ? $actions->upload_icon( $object_id, true ) : ( 'post' === $type ? parent::post_column( $column, $object_id ) : parent::term_column( '', $column, $object_id ) );
208
+ } elseif ( 'failed' === $document->status ) {
209
+ return $actions->failed_import_icon( $document->status, $object_id );
210
+ } elseif ( $this->lgtm->can_upload( $type, $id ) && 'cancelled' === $document->status ) {
211
+ return $disabled ? ( 'post' === $type ? parent::post_column( $column, $object_id ) : parent::term_column( '', $column, $object_id ) )
212
+ : ( $document && ( count( $document->desc_array ) >= 3 ) ? $actions->cancelled_icon( $object_id, false, true ) : $actions->cancelled_icon( $object_id ) );
213
+ } else {
214
+ // no translation.
 
 
 
215
  /**
216
  * There is no record of a translation, but the entire document has been cancelled
217
  * so we just mark all locales as cancelled since the user will have to re upload the document
218
  */
219
+ if ( 'cancelled' === $document->status ) {
220
+ return $actions->cancelled_icon( $object_id, true );
221
  }
222
  return '<div class="lingotek-color dashicons dashicons-no"></div>';
223
+ }//end if
224
  }
225
 
226
  /**
233
  * @param int $post_id post id.
234
  */
235
  public function post_column( $column, $post_id ) {
236
+ if ( false === strpos( $column, 'language_' ) ) {
237
  return;
238
  }
239
  $this->content_type = get_post_type( $post_id );
240
 
241
  $allowed_html = array(
242
+ 'a' => array(
243
+ 'href' => array(),
244
+ 'class' => array(),
245
+ 'title' => array(),
246
+ 'target' => array(),
247
  ),
248
  'div' => array(
249
  'title' => array(),
250
  'class' => array(),
251
  ),
252
  'img' => array(
253
+ 'src' => array(),
254
+ ),
255
  );
256
  echo wp_kses( $this->_column( 'post', $column, $post_id ), $allowed_html );
257
 
258
  /**
259
+ * Setup workflow specific logic for posts.
260
  */
261
+ $post = get_post( $post_id );
262
  $source_language = PLL()->model->post->get_language( $post_id );
263
  $target_language = $this->model->get_language( substr( $column, 9 ) );
264
+ if ( is_object( $source_language ) && is_object( $target_language ) ) {
265
  $workflow_id = Lingotek_Model::get_profile_option( 'workflow_id', $post->post_type, $source_language, $target_language, $post_id );
266
+ $workflow = Lingotek_Workflow_Factory::get_workflow_instance( $workflow_id );
267
  // $workflow->override_events( $workflow_id ); // Loads appropriate .js file.
268
+ // Adds modal html to page.
269
+ $workflow->echo_posts_modal( $post_id, $target_language->locale );
270
  }
271
 
272
  // checking for api errors.
290
  * @param int $term_id term id.
291
  */
292
  public function term_column( $custom_data, $column, $term_id ) {
293
+ if ( false === strpos( $column, 'language_' ) ) {
294
  return;
295
  }
296
+ $allowed_html = array(
297
+ 'a' => array(
298
+ 'href' => array(),
299
+ 'class' => array(),
300
+ 'title' => array(),
301
+ 'target' => array(),
302
  ),
303
+ 'div' => array(
304
  'title' => array(),
305
  'class' => array(),
306
  ),
307
  'span' => array(
308
  'class' => array(),
309
  ),
310
+ 'img' => array(
311
+ 'src' => array(),
312
+ ),
313
  );
314
  $this->content_type = $GLOBALS['taxonomy'];
315
 
316
  /**
317
+ * Setup workflow specific logic for terms.
318
  */
319
  $source_language = PLL()->model->term->get_language( $term_id );
320
  $target_language = $this->model->get_language( substr( $column, 9 ) );
321
+ if ( is_object( $source_language ) && is_object( $target_language ) ) {
322
  $workflow_id = Lingotek_Model::get_profile_option( 'workflow_id', $this->content_type, $source_language, $target_language );
323
+ $workflow = Lingotek_Workflow_Factory::get_workflow_instance( $workflow_id );
324
  // $workflow->override_events( $workflow_id ); // Loads appropriate .js file.
325
+ // Adds modal html to page.
326
+ $workflow->echo_terms_modal( $term_id, $target_language->locale );
327
  }
328
 
329
  if ( ! $custom_data ) {
346
  */
347
  protected function error_icon_html( $column, $object_id, $source_locale = null ) {
348
  // checking for api errors.
349
+ $source_column = substr( $column, 9 );
350
  $column_language_only = substr( $column, 0, 11 );
351
+ $errors = get_option( 'lingotek_log_errors' );
352
 
353
  if ( $source_column === $source_locale ) {
354
  if ( isset( $errors[ $object_id ] ) ) {
355
+ $api_error = Lingotek_Actions::retrieve_api_error( $errors[ $object_id ] );
356
  $allowed_html = array(
357
  'a' => array(
358
+ 'href' => array(),
359
+ 'class' => array(),
360
+ 'title' => array(),
361
+ 'target' => array(),
362
  ),
363
  );
364
  echo wp_kses( Lingotek_Actions::display_error_icon( 'error', $api_error ), $allowed_html );
admin/filters-media.php CHANGED
@@ -25,7 +25,8 @@ class Lingotek_Filters_Media extends PLL_Admin_Filters_Media {
25
  $this->lgtm = &$GLOBALS['wp_lingotek']->model;
26
 
27
  add_action( 'edit_attachment', array( &$this, 'edit_attachment' ) );
28
- add_action( 'add_attachment', array( &$this, 'add_attachment' ), 11 ); // after Polylang.
 
29
  }
30
 
31
  /**
25
  $this->lgtm = &$GLOBALS['wp_lingotek']->model;
26
 
27
  add_action( 'edit_attachment', array( &$this, 'edit_attachment' ) );
28
+ // After Polylang.
29
+ add_action( 'add_attachment', array( &$this, 'add_attachment' ), 11 );
30
  }
31
 
32
  /**
admin/filters-post.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
 
3
- /*
4
  * Modifies Polylang filters
5
  * Manages automatic upload
6
  * Manages delete / trash sync
@@ -8,234 +8,247 @@
8
  * @since 0.1
9
  */
10
  class Lingotek_Filters_Post extends PLL_CRUD_Posts {
11
- public $lgtm; // Lingotek model
 
 
 
 
 
 
 
 
 
 
 
 
12
  public $pllm;
 
 
 
 
 
 
13
  public $lingotek_prefs;
14
 
15
- /*
16
  * Constructor
17
  *
18
  * @since 0.1
19
  */
20
- public function __construct(&$polylang) {
21
- parent::__construct($polylang);
22
 
23
- $this->lgtm = &$GLOBALS['wp_lingotek']->model;
24
- $this->pllm = &$GLOBALS['polylang']->model;
25
  $this->lingotek_prefs = Lingotek_Model::get_prefs();
26
- $pll_filter = new PLL_Admin_Filters_Post($polylang);
27
 
28
  // automatic upload
29
- add_action('post_updated', array(&$this, 'post_updated'), 10, 3);
30
 
31
  // trash sync
32
- add_action('trashed_post', array(&$this, 'trash_post'));
33
- add_action('untrashed_post', array(&$this, 'untrash_post'));
34
 
35
- add_filter('manage_posts_columns', array(&$this, 'add_profile_column'));
36
- add_action('manage_posts_custom_column', array(&$this, 'add_profile_column_data'), 10, 3);
37
 
38
- add_filter('manage_pages_columns', array(&$this, 'add_profile_column'));
39
- add_action('manage_pages_custom_column', array(&$this, 'add_profile_column_data'), 10, 3);
40
 
41
  //apply language filter to preserve Polylang behavior of only showing documents of the current language
42
- add_action('parse_query', array($pll_filter, 'parse_query'));
43
  }
44
 
45
- /*
46
  * controls whether to display the language metabox or not
47
  *
48
  * @since 0.1
49
  */
50
- public function add_meta_boxes($post_type, $post = null) {
51
  global $post_ID;
52
- if ($this->model->is_translated_post_type($post_type)) {
53
- $document = $this->lgtm->get_group('post', $post_ID);
54
- if (empty($document->source)) {
55
- parent::add_meta_boxes($post_type, $document);
56
- }
57
- else {
58
  add_action( 'edit_form_top', array( &$this, 'edit_form_top' ) );
59
  }
60
  }
61
  }
62
 
63
- /*
64
  * adds a column to display the post or page translation profile
65
  *
66
  * @since 1.1
67
  */
68
- public function add_profile_column($columns) {
69
- $n = array_search('date', array_keys($columns));
70
- if ($n) {
71
- $end = array_slice($columns, $n);
72
- $columns = array_slice($columns, 0, $n);
73
  }
74
 
75
  $columns['profile'] = 'Profile';
76
- return isset($end) ? array_merge($columns, $end) : $columns;
77
  }
78
 
79
- /*
80
  * finds the translation profile for a post or page and if not set then displays the content type default profile
81
  *
82
  * @since 1.1
83
  */
84
- public function add_profile_column_data($column_name, $post_id) {
85
- if ($column_name == 'profile') {
86
- $document = $this->lgtm->get_group('post', $post_id);
87
- if (isset($document->source)) {
88
  $post_id = $document->source;
89
  }
90
- $profiles = Lingotek::get_profiles();
91
- $content_profiles = get_option('lingotek_content_type');
92
- $post_profile = Lingotek_Post_actions::get_post_profile($post_id);
93
- $post_language = PLL()->model->post->get_language($post_id);
94
- $post_type = 'post';
95
- if (isset($_REQUEST['post_type'])) {
96
- $post_type = $_REQUEST['post_type'];
97
  }
98
 
99
- if ($post_profile) {
100
- echo $profiles[$post_profile->description]['name'] . sprintf('<a title="%s">%s</a>', __('Not set to the content default profile', 'lingotek-translation'), '*');
101
- }
102
- else if ($post_language && isset($content_profiles[$post_type]['sources'][$post_language->slug])) {
103
- $profile = $content_profiles[$post_type]['sources'][$post_language->slug];
104
- echo $profiles[$profile]['name'];
105
- }
106
- else if (!empty($content_profiles) && (!isset($content_profiles[$post_type]) || !isset($profiles[$content_profiles[$post_type]['profile']]['name'])))
107
- {
108
- echo esc_html( __('Disabled', 'lingotek-translation') );
109
- }
110
- else if (!empty($content_profiles)) {
111
- echo $profiles[$content_profiles[$post_type]['profile']]['name'];
112
  }
113
- else {
114
- _e('Manual', 'lingotek-translation');
115
- }
116
- }
117
  }
118
 
119
- /*
120
- * outputs hidden fields so that Polylang get correct information when its metabox is removed
121
  *
122
  * @since 1.10
123
  */
124
  public function edit_form_top() {
125
  global $post_ID;
126
- printf( '<input type="hidden" id="post_lang_choice" name="post_lang_choice" value="%s" />', pll_get_post_language( $post_ID ) );
127
- wp_nonce_field('pll_language', '_pll_nonce');
128
  }
129
 
130
- /*
131
- * uploads a post when saved for the first time
132
  *
133
  * @since 0.2
134
 
135
- * @param int $post_id
136
  * @param object $post
137
- * @param bool $update whether it is an update or not
138
  */
139
- public function save_post($post_id, $post) {
140
-
141
- $document = $this->lgtm->get_group('post', $post_id);
142
- if ($document) {
143
- $language = PLL()->model->post->get_language($post_id);
144
- $document->pre_save_post($post_id, 'post', $language);
145
  }
146
- if ($this->can_save_post_data($post_id, $post, true)) {
147
  // updated post
148
- if ($document &&
149
- $post_id == $document->source &&
150
- $this->post_hash_has_changed($post) &&
151
- $this->is_post_valid_for_upload_by_custom_terms($post_id, false)) {
 
152
  $document->source_edited();
153
- if ($document->is_automatic_upload() && Lingotek_Group_Post::is_valid_auto_upload_post_status($post->post_status)) {
154
- $this->lgtm->upload_post($post_id);
155
  }
156
  }
157
  // Ensures languages are updated, even when no other element on the page has been changed.
158
- if (isset($_POST['post_tr_lang'])) {
159
- PLL()->model->post->save_translations($post_id, $_POST['post_tr_lang']);
160
  }
161
  }
162
 
163
- if (!$this->model->is_translated_post_type($post->post_type))
164
  return;
 
165
  // new post
166
- if (!isset($_REQUEST['import'])) {
167
- parent::save_post($post_id, $post);
168
- if (!$document &&
169
- !wp_is_post_revision($post_id) &&
170
- 'auto-draft' != $post->post_status &&
171
- 'automatic' == Lingotek_Model::get_profile_option('upload', $post->post_type, PLL()->model->post->get_language($post_id), false, $post_id) &&
172
- Lingotek_Group_Post::is_valid_auto_upload_post_status($post->post_status) &&
173
- !(isset($_POST['action']) && 'heartbeat' == $_POST['action']) &&
174
- $this->lgtm->can_upload('post', $post_id) &&
175
- $this->is_post_valid_for_upload_by_custom_terms($post_id, true)) {
176
-
177
- $this->lgtm->upload_post($post_id);
178
  }
179
  }
180
  }
181
 
182
- /*
183
  * Allows the customer to interrupt the post upload by applying filter.
184
  * By using This filter we are allowing users to implement custom logic on the post upload and check if it is valid
185
  * for upload
186
  *
187
  * @since 1.3.1
188
- *
189
  * @author Soluto
190
  *
191
- * @param int $post_id
192
  * @param bool $is_new_post
193
  * @return bool
194
  */
195
- protected function is_post_valid_for_upload_by_custom_terms($post_id, $is_new_post) {
196
  $defaults = array();
197
- $results = apply_filters('lingotek_is_post_valid_for_upload', $defaults, $post_id, $is_new_post );
198
- return !(in_array(false, $results));
199
  }
200
 
201
- /*
202
  * checks if we can act when saving a post
203
  *
204
  * @since 0.1
205
  *
206
- * @param int $post_id
207
  * @param object $post
208
- * @param bool $update whether it is an update or not
209
  * @return bool
210
  */
211
- protected function can_save_post_data($post_id, $post, $update) {
212
  // does nothing except on post types which are filterable
213
  // also don't act on revisions
214
- if (!$this->model->is_translated_post_type($post->post_type) || wp_is_post_revision($post_id))
215
  return false;
 
216
 
217
  // capability check
218
  // as 'wp_insert_post' can be called from outside WP admin
219
- $post_type_object = get_post_type_object($post->post_type);
220
- if (($update && !current_user_can($post_type_object->cap->edit_post, $post_id)) || (!$update && !current_user_can($post_type_object->cap->create_posts)))
221
  return false;
 
222
 
223
  return true;
224
  }
225
 
226
- /*
227
  * marks the post as edited if needed
228
  *
229
  * @since 0.1
230
  *
231
- * @param int $post_id
232
  * @param object $post_after
233
  * @param object $post_before
234
  */
235
- public function post_updated($post_id, $post_after, $post_before) {
236
  }
237
 
238
- /*
239
  * get translations ids to sync for delete / trash / untrash
240
  * since we can't sync all translations as we get conflicts when attempting to act two times on the same
241
  *
@@ -244,105 +257,105 @@ class Lingotek_Filters_Post extends PLL_CRUD_Posts {
244
  * @param int $post_id
245
  * @return array
246
  */
247
- protected function get_translations_to_sync($post_id) {
248
  // don't synchronize disassociated posts
249
- $group = $this->lgtm->get_group('post', $post_id);
250
- if (empty($group->source))
251
- return [$post_id];
 
252
 
253
- if (isset($_REQUEST['media']) && is_array($_REQUEST['media']))
254
- $post_ids = array_map('intval', $_REQUEST['media']);
255
- elseif (!empty($_REQUEST['post']) && is_array($_REQUEST['post']))
256
- $post_ids = array_map('intval', $_REQUEST['post']);
 
257
 
258
  $post_ids[] = $post_id;
259
- return array_diff(PLL()->model->post->get_translations($post_id), $post_ids);
260
  }
261
 
262
- /*
263
  * sync trash
264
  *
265
  * @since 0.1
266
  *
267
  * @param int $post_id
268
  */
269
- public function trash_post($post_id) {
270
- if (get_option("ignore_delete_pref", FALSE)) {
271
  return;
272
  }
273
- $group = $this->lgtm->get_group('post', $post_id);
274
 
275
- if (isset($this->lingotek_prefs['trash_linked_content']['enabled'])) {
276
- foreach ($this->get_translations_to_sync($post_id) as $tr_id)
277
- wp_trash_post($tr_id);
278
- if(isset($group->source)){
279
- $group->cancel();
280
- }
281
- }
282
- else {
283
- wp_trash_post($post_id);
284
- if(isset($group->source)){
285
- $this->lgtm->cancel_post($post_id);
286
  }
287
  }
288
-
289
  }
290
 
291
- /*
292
  * sync untrash
293
  *
294
  * @since 0.1
295
  *
296
  * @param int $post_id
297
  */
298
- public function untrash_post($post_id) {
299
- foreach ($this->get_translations_to_sync($post_id) as $tr_id)
300
- wp_untrash_post($tr_id);
 
301
  }
302
 
303
- /*
304
  * checks stored hash against current hash to report change
305
  *
306
  * @since 1.0
307
  *
308
  * @param wp_post $post_after
309
  */
310
- protected function post_hash_has_changed($post_after) {
311
- if ($post_after->post_status === 'trash') {
312
  return false;
313
  }
314
  $document_id = 'lingotek_hash_' . $post_after->ID;
315
- $new_hash = md5(Lingotek_Group_Post::get_content($post_after));
316
- $old_term = $this->get_post_hash($post_after->ID);
317
- $old_hash = $old_term->description;
318
 
319
  // new or updated page
320
- if ($old_hash === null || strcmp($new_hash, $old_hash)) {
321
- if (empty($old_term)) {
322
- wp_insert_term($document_id, 'lingotek_hash', array('description' => $new_hash));
323
  }
324
- wp_set_object_terms($post_after->ID, $document_id, 'lingotek_hash');
325
  return true;
326
- }
327
- else {
328
  return false;
329
  }
330
  }
331
 
332
- /*
333
- * returns a lingotek post hash if it exists
334
  *
335
  * @since 1.0
336
  *
337
  * @param int $post_id
338
  */
339
- protected function get_post_hash($post_id) {
340
- if (taxonomy_exists('lingotek_hash')) {
341
- $terms = wp_get_object_terms($post_id, 'lingotek_hash');
342
- $term = array_pop($terms);
343
  return $term;
344
- }
345
- else {
346
  return null;
347
  }
348
  }
1
  <?php
2
 
3
+ /**
4
  * Modifies Polylang filters
5
  * Manages automatic upload
6
  * Manages delete / trash sync
8
  * @since 0.1
9
  */
10
  class Lingotek_Filters_Post extends PLL_CRUD_Posts {
11
+
12
+ /**
13
+ * Lingotek model.
14
+ *
15
+ * @var $lgtm
16
+ */
17
+ public $lgtm;
18
+
19
+ /**
20
+ * Polylang model.
21
+ *
22
+ * @var $pllm
23
+ */
24
  public $pllm;
25
+
26
+ /**
27
+ * Lingotek preferences.
28
+ *
29
+ * @var $lingotek_prefs
30
+ */
31
  public $lingotek_prefs;
32
 
33
+ /**
34
  * Constructor
35
  *
36
  * @since 0.1
37
  */
38
+ public function __construct( &$polylang ) {
39
+ parent::__construct( $polylang );
40
 
41
+ $this->lgtm = &$GLOBALS['wp_lingotek']->model;
42
+ $this->pllm = &$GLOBALS['polylang']->model;
43
  $this->lingotek_prefs = Lingotek_Model::get_prefs();
44
+ $pll_filter = new PLL_Admin_Filters_Post( $polylang );
45
 
46
  // automatic upload
47
+ add_action( 'post_updated', array( &$this, 'post_updated' ), 10, 3 );
48
 
49
  // trash sync
50
+ add_action( 'trashed_post', array( &$this, 'trash_post' ) );
51
+ add_action( 'untrashed_post', array( &$this, 'untrash_post' ) );
52
 
53
+ add_filter( 'manage_posts_columns', array( &$this, 'add_profile_column' ) );
54
+ add_action( 'manage_posts_custom_column', array( &$this, 'add_profile_column_data' ), 10, 3 );
55
 
56
+ add_filter( 'manage_pages_columns', array( &$this, 'add_profile_column' ) );
57
+ add_action( 'manage_pages_custom_column', array( &$this, 'add_profile_column_data' ), 10, 3 );
58
 
59
  //apply language filter to preserve Polylang behavior of only showing documents of the current language
60
+ add_action( 'parse_query', array( $pll_filter, 'parse_query' ) );
61
  }
62
 
63
+ /**
64
  * controls whether to display the language metabox or not
65
  *
66
  * @since 0.1
67
  */
68
+ public function add_meta_boxes( $post_type, $post = null ) {
69
  global $post_ID;
70
+ if ( $this->model->is_translated_post_type( $post_type ) ) {
71
+ $document = $this->lgtm->get_group( 'post', $post_ID );
72
+ if ( empty( $document->source ) ) {
73
+ parent::add_meta_boxes( $post_type, $document );
74
+ } else {
 
75
  add_action( 'edit_form_top', array( &$this, 'edit_form_top' ) );
76
  }
77
  }
78
  }
79
 
80
+ /**
81
  * adds a column to display the post or page translation profile
82
  *
83
  * @since 1.1
84
  */
85
+ public function add_profile_column( $columns ) {
86
+ $n = array_search( 'date', array_keys( $columns ), true );
87
+ if ( $n ) {
88
+ $end = array_slice( $columns, $n );
89
+ $columns = array_slice( $columns, 0, $n );
90
  }
91
 
92
  $columns['profile'] = 'Profile';
93
+ return isset( $end ) ? array_merge( $columns, $end ) : $columns;
94
  }
95
 
96
+ /**
97
  * finds the translation profile for a post or page and if not set then displays the content type default profile
98
  *
99
  * @since 1.1
100
  */
101
+ public function add_profile_column_data( $column_name, $post_id ) {
102
+ if ( 'profile' === $column_name ) {
103
+ $document = $this->lgtm->get_group( 'post', $post_id );
104
+ if ( isset( $document->source ) ) {
105
  $post_id = $document->source;
106
  }
107
+ $profiles = Lingotek::get_profiles();
108
+ $content_profiles = get_option( 'lingotek_content_type' );
109
+ $post_profile = Lingotek_Post_Actions::get_post_profile( $post_id );
110
+ $post_language = PLL()->model->post->get_language( $post_id );
111
+ $post_type = 'post';
112
+ if ( isset( $_REQUEST['post_type'] ) ) {
113
+ $post_type = sanitize_text_field( wp_unslash( $_REQUEST['post_type'] ) );
114
  }
115
 
116
+ if ( $post_profile ) {
117
+ echo esc_html( $profiles[ $post_profile->description ]['name'] ) . sprintf( '<a title="%s">%s</a>', esc_attr__( 'Not set to the content default profile', 'lingotek-translation' ), '*' );
118
+ } elseif ( $post_language && isset( $content_profiles[ $post_type ]['sources'][ $post_language->slug ] ) ) {
119
+ $profile = $content_profiles[ $post_type ]['sources'][ $post_language->slug ];
120
+ echo esc_html( $profiles[ $profile ]['name'] );
121
+ } elseif ( ! empty( $content_profiles ) && ( ! isset( $content_profiles[ $post_type ] ) || ! isset( $profiles[ $content_profiles[ $post_type ]['profile'] ]['name'] ) ) ) {
122
+ echo esc_html__( 'Disabled', 'lingotek-translation' );
123
+ } elseif ( ! empty( $content_profiles ) ) {
124
+ echo esc_html( $profiles[ $content_profiles[ $post_type ]['profile'] ]['name'] );
125
+ } else {
126
+ esc_html_e( 'Manual', 'lingotek-translation' );
 
 
127
  }
128
+ }//end if
 
 
 
129
  }
130
 
131
+ /**
132
+ * Outputs hidden fields so that Polylang get correct information when its metabox is removed.
133
  *
134
  * @since 1.10
135
  */
136
  public function edit_form_top() {
137
  global $post_ID;
138
+ printf( '<input type="hidden" id="post_lang_choice" name="post_lang_choice" value="%s" />', esc_attr( pll_get_post_language( $post_ID ) ) );
139
+ wp_nonce_field( 'pll_language', '_pll_nonce' );
140
  }
141
 
142
+ /**
143
+ * Uploads a post when saved for the first time
144
  *
145
  * @since 0.2
146
 
147
+ * @param int $post_id
148
  * @param object $post
 
149
  */
150
+ public function save_post( $post_id, $post ) {
151
+ $document = $this->lgtm->get_group( 'post', $post_id );
152
+ if ( $document ) {
153
+ $language = PLL()->model->post->get_language( $post_id );
154
+ $document->pre_save_post( $post_id, 'post', $language );
 
155
  }
156
+ if ( $this->can_save_post_data( $post_id, $post, true ) ) {
157
  // updated post
158
+ if ( $document &&
159
+ // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
160
+ $post_id == $document->source &&
161
+ $this->post_hash_has_changed( $post ) &&
162
+ $this->is_post_valid_for_upload_by_custom_terms( $post_id, false ) ) {
163
  $document->source_edited();
164
+ if ( $document->is_automatic_upload() && Lingotek_Group_Post::is_valid_auto_upload_post_status( $post->post_status ) ) {
165
+ $this->lgtm->upload_post( $post_id );
166
  }
167
  }
168
  // Ensures languages are updated, even when no other element on the page has been changed.
169
+ if ( isset( $_POST['post_tr_lang'] ) ) {
170
+ PLL()->model->post->save_translations( $post_id, sanitize_text_field( wp_unslash( $_POST['post_tr_lang'] ) ) );
171
  }
172
  }
173
 
174
+ if ( ! $this->model->is_translated_post_type( $post->post_type ) ) {
175
  return;
176
+ }
177
  // new post
178
+ if ( ! isset( $_REQUEST['import'] ) ) {
179
+ parent::save_post( $post_id, $post );
180
+ if ( ! $document &&
181
+ ! wp_is_post_revision( $post_id ) &&
182
+ 'auto-draft' !== $post->post_status &&
183
+ 'automatic' === Lingotek_Model::get_profile_option( 'upload', $post->post_type, PLL()->model->post->get_language( $post_id ), false, $post_id ) &&
184
+ Lingotek_Group_Post::is_valid_auto_upload_post_status( $post->post_status ) &&
185
+ ! ( isset( $_POST['action'] ) && 'heartbeat' === $_POST['action'] ) &&
186
+ $this->lgtm->can_upload( 'post', $post_id ) &&
187
+ $this->is_post_valid_for_upload_by_custom_terms( $post_id, true ) ) {
188
+ $this->lgtm->upload_post( $post_id );
 
189
  }
190
  }
191
  }
192
 
193
+ /**
194
  * Allows the customer to interrupt the post upload by applying filter.
195
  * By using This filter we are allowing users to implement custom logic on the post upload and check if it is valid
196
  * for upload
197
  *
198
  * @since 1.3.1
199
+ *
200
  * @author Soluto
201
  *
202
+ * @param int $post_id
203
  * @param bool $is_new_post
204
  * @return bool
205
  */
206
+ protected function is_post_valid_for_upload_by_custom_terms( $post_id, $is_new_post ) {
207
  $defaults = array();
208
+ $results = apply_filters( 'lingotek_is_post_valid_for_upload', $defaults, $post_id, $is_new_post );
209
+ return ! ( in_array( false, $results, true ) );
210
  }
211
 
212
+ /**
213
  * checks if we can act when saving a post
214
  *
215
  * @since 0.1
216
  *
217
+ * @param int $post_id
218
  * @param object $post
219
+ * @param bool $update Whether it is an update or not.
220
  * @return bool
221
  */
222
+ protected function can_save_post_data( $post_id, $post, $update ) {
223
  // does nothing except on post types which are filterable
224
  // also don't act on revisions
225
+ if ( ! $this->model->is_translated_post_type( $post->post_type ) || wp_is_post_revision( $post_id ) ) {
226
  return false;
227
+ }
228
 
229
  // capability check
230
  // as 'wp_insert_post' can be called from outside WP admin
231
+ $post_type_object = get_post_type_object( $post->post_type );
232
+ if ( ( $update && ! current_user_can( $post_type_object->cap->edit_post, $post_id ) ) || ( ! $update && ! current_user_can( $post_type_object->cap->create_posts ) ) ) {
233
  return false;
234
+ }
235
 
236
  return true;
237
  }
238
 
239
+ /**
240
  * marks the post as edited if needed
241
  *
242
  * @since 0.1
243
  *
244
+ * @param int $post_id
245
  * @param object $post_after
246
  * @param object $post_before
247
  */
248
+ public function post_updated( $post_id, $post_after, $post_before ) {
249
  }
250
 
251
+ /**
252
  * get translations ids to sync for delete / trash / untrash
253
  * since we can't sync all translations as we get conflicts when attempting to act two times on the same
254
  *
257
  * @param int $post_id
258
  * @return array
259
  */
260
+ protected function get_translations_to_sync( $post_id ) {
261
  // don't synchronize disassociated posts
262
+ $group = $this->lgtm->get_group( 'post', $post_id );
263
+ if ( empty( $group->source ) ) {
264
+ return array( $post_id );
265
+ }
266
 
267
+ if ( isset( $_REQUEST['media'] ) && is_array( $_REQUEST['media'] ) ) {
268
+ $post_ids = array_map( 'intval', $_REQUEST['media'] );
269
+ } elseif ( ! empty( $_REQUEST['post'] ) && is_array( $_REQUEST['post'] ) ) {
270
+ $post_ids = array_map( 'intval', $_REQUEST['post'] );
271
+ }
272
 
273
  $post_ids[] = $post_id;
274
+ return array_diff( PLL()->model->post->get_translations( $post_id ), $post_ids );
275
  }
276
 
277
+ /**
278
  * sync trash
279
  *
280
  * @since 0.1
281
  *
282
  * @param int $post_id
283
  */
284
+ public function trash_post( $post_id ) {
285
+ if ( get_option( 'ignore_delete_pref', false ) ) {
286
  return;
287
  }
288
+ $group = $this->lgtm->get_group( 'post', $post_id );
289
 
290
+ if ( isset( $this->lingotek_prefs['trash_linked_content']['enabled'] ) ) {
291
+ foreach ( $this->get_translations_to_sync( $post_id ) as $tr_id ) {
292
+ wp_trash_post( $tr_id );
293
+ }
294
+ if ( isset( $group->source ) ) {
295
+ $group->cancel();
296
+ }
297
+ } else {
298
+ wp_trash_post( $post_id );
299
+ if ( isset( $group->source ) ) {
300
+ $this->lgtm->cancel_post( $post_id );
301
  }
302
  }
 
303
  }
304
 
305
+ /**
306
  * sync untrash
307
  *
308
  * @since 0.1
309
  *
310
  * @param int $post_id
311
  */
312
+ public function untrash_post( $post_id ) {
313
+ foreach ( $this->get_translations_to_sync( $post_id ) as $tr_id ) {
314
+ wp_untrash_post( $tr_id );
315
+ }
316
  }
317
 
318
+ /**
319
  * checks stored hash against current hash to report change
320
  *
321
  * @since 1.0
322
  *
323
  * @param wp_post $post_after
324
  */
325
+ protected function post_hash_has_changed( $post_after ) {
326
+ if ( 'trash' === $post_after->post_status ) {
327
  return false;
328
  }
329
  $document_id = 'lingotek_hash_' . $post_after->ID;
330
+ $new_hash = md5( Lingotek_Group_Post::get_content( $post_after ) );
331
+ $old_term = $this->get_post_hash( $post_after->ID );
332
+ $old_hash = $old_term->description;
333
 
334
  // new or updated page
335
+ if ( null === $old_hash || strcmp( $new_hash, $old_hash ) ) {
336
+ if ( empty( $old_term ) ) {
337
+ wp_insert_term( $document_id, 'lingotek_hash', array( 'description' => $new_hash ) );
338
  }
339
+ wp_set_object_terms( $post_after->ID, $document_id, 'lingotek_hash' );
340
  return true;
341
+ } else {
 
342
  return false;
343
  }
344
  }
345
 
346
+ /**
347
+ * Returns a lingotek post hash if it exists.
348
  *
349
  * @since 1.0
350
  *
351
  * @param int $post_id
352
  */
353
+ protected function get_post_hash( $post_id ) {
354
+ if ( taxonomy_exists( 'lingotek_hash' ) ) {
355
+ $terms = wp_get_object_terms( $post_id, 'lingotek_hash' );
356
+ $term = array_pop( $terms );
357
  return $term;
358
+ } else {
 
359
  return null;
360
  }
361
  }
admin/filters-term.php CHANGED
@@ -60,17 +60,16 @@ class Lingotek_Filters_Term extends PLL_Admin_Filters_Term {
60
  * @param string $taxonomy taxonomy.
61
  */
62
  public function save_term( $term_id, $tt_id, $taxonomy ) {
63
- $document = $this->lgtm->get_group('term', $term_id);
64
- if ($document) {
65
- $document->pre_save_terms($term_id, $taxonomy, PLL()->model->term->get_language( $term_id ));
66
  }
67
 
68
-
69
  if ( ! $this->model->is_translated_taxonomy( $taxonomy ) ) {
70
  return;
71
  }
72
 
73
- $import_get = filter_input( INPUT_GET, 'import' );
74
  $import_post = filter_input( INPUT_POST, 'import' );
75
  if ( empty( $import ) && empty( $import_post ) ) {
76
  parent::save_term( $term_id, $tt_id, $taxonomy );
@@ -135,8 +134,8 @@ class Lingotek_Filters_Term extends PLL_Admin_Filters_Term {
135
  return array();
136
  }
137
 
138
- $delete_tags = null;
139
- $delete_tags_get = filter_input( INPUT_GET, 'delete_tags' );
140
  $delete_tags_post = filter_input( INPUT_POST, 'delete_tags' );
141
  if ( ! empty( $delete_tags_get ) ) {
142
  $delete_tags = filter_input( INPUT_GET, 'delete_tags' );
@@ -162,16 +161,17 @@ class Lingotek_Filters_Term extends PLL_Admin_Filters_Term {
162
  public function delete_term( $term_id ) {
163
  $taxonomy = substr( current_filter(), 7 );
164
  foreach ( $this->get_translations_to_sync( $term_id ) as $tr_id ) {
165
- wp_delete_term( $tr_id, $taxonomy ); // forces deletion for the translations which are not already in the list.
 
166
  }
167
  $this->lgtm->delete_term( $term_id );
168
  }
169
 
170
- public function cancel_term($term_id){
171
- $taxonomy = substr(current_filter(), 7);
172
- foreach($this->get_translations_to_sync($term_id) as $tr_id) {
173
- wp_delete_term($tr_id, $taxonomy);
174
  }
175
- $this->lgtm->cancel_term($term_id);
176
  }
177
  }
60
  * @param string $taxonomy taxonomy.
61
  */
62
  public function save_term( $term_id, $tt_id, $taxonomy ) {
63
+ $document = $this->lgtm->get_group( 'term', $term_id );
64
+ if ( $document ) {
65
+ $document->pre_save_terms( $term_id, $taxonomy, PLL()->model->term->get_language( $term_id ) );
66
  }
67
 
 
68
  if ( ! $this->model->is_translated_taxonomy( $taxonomy ) ) {
69
  return;
70
  }
71
 
72
+ $import_get = filter_input( INPUT_GET, 'import' );
73
  $import_post = filter_input( INPUT_POST, 'import' );
74
  if ( empty( $import ) && empty( $import_post ) ) {
75
  parent::save_term( $term_id, $tt_id, $taxonomy );
134
  return array();
135
  }
136
 
137
+ $delete_tags = null;
138
+ $delete_tags_get = filter_input( INPUT_GET, 'delete_tags' );
139
  $delete_tags_post = filter_input( INPUT_POST, 'delete_tags' );
140
  if ( ! empty( $delete_tags_get ) ) {
141
  $delete_tags = filter_input( INPUT_GET, 'delete_tags' );
161
  public function delete_term( $term_id ) {
162
  $taxonomy = substr( current_filter(), 7 );
163
  foreach ( $this->get_translations_to_sync( $term_id ) as $tr_id ) {
164
+ // Forces deletion for the translations which are not already in the list.
165
+ wp_delete_term( $tr_id, $taxonomy );
166
  }
167
  $this->lgtm->delete_term( $term_id );
168
  }
169
 
170
+ public function cancel_term( $term_id ) {
171
+ $taxonomy = substr( current_filter(), 7 );
172
+ foreach ( $this->get_translations_to_sync( $term_id ) as $tr_id ) {
173
+ wp_delete_term( $tr_id, $taxonomy );
174
  }
175
+ $this->lgtm->cancel_term( $term_id );
176
  }
177
  }
admin/import.php CHANGED
@@ -1,44 +1,58 @@
 
 
 
 
 
 
 
 
 
1
  <div class="wrap">
2
- <h2><?php _e('Import', 'wp-lingotek'); ?></h2>
3
- <p class="description"><?php printf(__('Import your posts from another wordpress blog through Lingotek', 'wp-lingotek'), 'admin.php?page=wp-lingotek_import'); ?></p>
4
 
5
 
6
- <?php
7
- $menu_items = array(
8
- 'content' => __('Content', 'wp-lingotek'),
9
- 'settings' => __('Settings', 'wp-lingotek')
10
- );
11
- ?>
12
 
13
- <h3 class="nav-tab-wrapper">
14
- <?php
15
- $menu_item_index = 0;
16
- foreach ($menu_items as $menu_item_key => $menu_item_label) {
17
- $use_as_default = ($menu_item_index === 0 && !isset($_GET['sm'])) ? TRUE : FALSE;
18
- $alias = NULL;
19
- // custom sub sub-menus
20
- if(isset($_GET['sm']) && $_GET['sm'] == "edit-profile") {
21
- $alias = "profiles";
22
- }
23
- ?>
24
 
25
- <a class="nav-tab <?php if ($use_as_default || (isset($_GET['sm']) && $_GET['sm'] == $menu_item_key) || $alias == $menu_item_key): ?> nav-tab-active<?php endif; ?>"
26
- href="admin.php?page=<?php echo $_GET['page']; ?>&amp;sm=<?php echo $menu_item_key; ?>"><?php echo $menu_item_label; ?></a>
27
- <?php
28
- $menu_item_index++;
29
- }
30
- ?>
31
- </h3>
 
 
 
 
32
 
33
- <?php
34
- settings_errors();
35
- $submenu = isset($_GET['sm']) ? $_GET['sm'] : 'content';
36
- $dir = dirname(__FILE__) . '/import/';
37
- $filename = $dir . 'view-' . $submenu . ".php";
38
- if (file_exists($filename))
39
- include $filename;
40
- else
41
- echo "TO-DO: create <i>" . 'import/view-' . $submenu . ".php</i>";
42
- ?>
 
43
 
44
  </div>
1
+ <?php
2
+ /**
3
+ * I think this file is not used, and probably should be removed.
4
+ *
5
+ * @package lingotek-translation
6
+ */
7
+
8
+ // phpcs:disable
9
+ ?>
10
  <div class="wrap">
11
+ <h2><?php esc_html_e( 'Import', 'lingotek-translation' ); ?></h2>
12
+ <p class="description"><?php printf(__( 'Import your posts from another WordPress blog through Lingotek', 'lingotek-translation' ), 'admin.php?page=lingotek-translation_import' ); ?></p>
13
 
14
 
15
+ <?php
16
+ $menu_items = array(
17
+ 'content' => __( 'Content', 'wp-lingotek' ),
18
+ 'settings' => __( 'Settings', 'wp-lingotek' ),
19
+ );
20
+ ?>
21
 
22
+ <h3 class="nav-tab-wrapper">
23
+ <?php
24
+ $menu_item_index = 0;
25
+ foreach ( $menu_items as $menu_item_key => $menu_item_label ) {
26
+ $use_as_default = ( $menu_item_index === 0 && ! isset( $_GET['sm'] ) ) ? true : false;
27
+ $alias = null;
28
+ // custom sub sub-menus
29
+ if ( isset( $_GET['sm'] ) && $_GET['sm'] == 'edit-profile' ) {
30
+ $alias = 'profiles';
31
+ }
32
+ ?>
33
 
34
+ <a class="nav-tab
35
+ <?php
36
+ if ( $use_as_default || ( isset( $_GET['sm'] ) && $_GET['sm'] == $menu_item_key ) || $alias == $menu_item_key ) :
37
+ ?>
38
+ nav-tab-active<?php endif; ?>"
39
+ href="admin.php?page=<?php echo esc_url( $_GET['page'] ); ?>&amp;sm=<?php echo esc_url( $menu_item_key ); ?>"><?php echo $menu_item_label; ?></a>
40
+ <?php
41
+ $menu_item_index++;
42
+ }
43
+ ?>
44
+ </h3>
45
 
46
+ <?php
47
+ settings_errors();
48
+ $submenu = isset( $_GET['sm'] ) ? $_GET['sm'] : 'content';
49
+ $dir = dirname( __FILE__ ) . '/import/';
50
+ $filename = $dir . 'view-' . $submenu . '.php';
51
+ if ( file_exists( $filename ) ) {
52
+ require $filename;
53
+ } else {
54
+ echo 'TO-DO: create <i>' . 'import/view-' . $submenu . '.php</i>';
55
+ }
56
+ ?>
57
 
58
  </div>
admin/import/FormatConverter.php CHANGED
@@ -1,237 +1,261 @@
1
  <?php
 
 
 
 
 
2
 
 
3
  require_once 'StandardImportObject.php';
4
 
5
  /**
6
- *This class exists to convert other content (e.g. JSON--Drupal 7, Drupal 8, Middleware--
7
- *HTML, XML, Text, Plaintext) into content compatible with WP
8
- *
9
- *@author Unkown
10
- *@uses StandardImportObject.php|StandardImportObject
11
- *@return StandardImportObject returns an object that is in the format and has the
12
- *content to be imported into WordPress
13
  *
 
 
 
 
14
  */
15
- class FormatConverter
16
- { /**
17
- *The document that is used to determine information about the import. It is
18
- *the source document that can be accessed.
19
- */
20
- private $source_doc;
21
- /**
22
- *The content is the bulk of the information without format, source, etc. This
23
- *is what is converted into the title and body of the wp import.
24
- */
25
- private $content;
26
- /**
27
- *The format is the format of the source upload document so that it can be handled
28
- *by the right conversion function (e.g. JSON, HTML, TXT, etc.)
29
- */
30
- private $format;
31
-
32
- /**
33
- *Constructor
34
- *Sets up the FormatConverter object so it can be converted
35
- *
36
- *@author Unkown
37
- *
38
- *@param object $source_doc The document that needs to be converted and then imported
39
- *@param string $content The content portion of the document -- This is what becomes
40
- * the body of the WP post/page
41
- *@param string $format The format of the file. The extension of the document
42
- * is used to choose the right function to convert to standard
43
- *@return void This builds an object that is then converted to wp import
44
- */
45
- function __construct($source_doc, $content, $format)
46
- {
47
- $this->source_doc = $source_doc;
48
- $this->content = $content;
49
- $this->format = $format;
50
- }
51
-
52
-
53
- /**
54
- *This function determines which converter function is needed. If there is not
55
- *a converter function for the selected document then it defaults to
56
- *JSON (in the else statement) and attempts the conversion with the assumption
57
- *of working with a JSON file.
58
- *
59
- *@author Unkown
60
- *@return StandardImportObject $importObject An object that can be imported into WP
61
- */
62
- public function convert_to_standard(){
63
- if (method_exists($this, $this->format.'_to_standard')){
64
- $importObject = call_user_func(array($this, $this->format.'_to_standard'), $this->source_doc, $this->content);
65
- return $importObject;
66
- }
67
- else {
68
- $importObject = call_user_func(array($this,'json_to_standard'), $this->source_doc, $this->content);
69
- return $importObject;
70
- }
71
- }
72
-
73
-
74
- /**
75
- *Converts source JSON into a StandardImportObject that can be imported into WP
76
- *@author Unkown
77
- *@param object $source_doc source document
78
- *@param string $content JSON string that is then parsed to get the relevant
79
- *information for the title and body
80
- *@return StandardImportObject That can be imported into WP
81
- */
82
- public function json_to_standard($source_doc, $content){
83
-
84
- /**
85
- *These string replaces are to make it so that we can access the json objects
86
- *with these titles. They were being imported with @ before the key and that
87
- *made them inaccessible. This is specific to Middleware json strings.
88
- *@author Matt Smith and TJ Murphy
89
- */
90
- $content = str_replace('"@title"','"title"',$content);
91
- $content = str_replace('"@type"','"type"',$content);
92
-
93
- $decoded_json = json_decode($content);
94
-
95
- $content = __('We could not parse the data from this document.
96
- Are you sure that it is in a recognizable format, such as JSON, XML, HTML, or plain text?', 'wp-lingotek');
97
- $title = __('No title found', 'wp-lingotek');
98
- $error = false;
99
-
100
-
101
- /**
102
- *An if statement to check for the different json patterns to find the content
103
- *that will be the body of the WP imported post/page
104
- *@author Unkown and TJ Murphy
105
- *@return string $content is set -- if nothing matches then $content remains
106
- *with a warning
107
- *@see $content
108
- */
109
- if (isset($decoded_json->post->post_content)){ // Drupal 7
 
 
 
 
110
  $content = $decoded_json->post->post_content;
111
  }
112
- else if (isset($decoded_json->body[0]->value)){ // Drupal 8
 
113
  $content = $decoded_json->body[0]->value;
114
- }
115
- else if (isset($decoded_json->args->description)){
116
  $content = $decoded_json->args->description;
117
  }
118
- else if (isset($decoded_json->content->body)){ // Middleware - MindTouch
 
119
  $content = $decoded_json->content->body;
120
  }
121
- else if (isset($decoded_json->body)){ // Middleware - Zendesk and HubSpot
 
122
  $content = $decoded_json->body;
123
  }
124
- else if (isset($decoded_json->email_body)){ // Middleware - Email HubSpot
 
125
  $content = $decoded_json->email_body;
126
  }
127
- else if (isset($decoded_json->post_summary)){ // Middleware
 
128
  $content = $decoded_json->post_summary;
129
  }
130
- else if (isset($decoded_json->description)){ // Middleware
 
131
  $content = $decoded_json->description;
 
 
132
  }
133
- else {
134
- $error = true;
135
- }
136
-
137
- /**
138
- *An if statement to check for the different json patterns to find the title
139
- *that will be the title of the WP imported post/page
140
- *@author Unkown and TJ Murphy
141
- *@return string $title is set -- if nothing matches then $error is set to TRUE
142
- *@see $title
143
- */
144
- if (isset($decoded_json->title[0]->value)){ // Drupal 8
145
  $title = $decoded_json->title[0]->value;
146
  }
147
- else if (isset($decoded_json->post->post_title)){ // Drupal 7
 
148
  $title = $decoded_json->post->post_title;
149
  }
150
- else if (isset($decoded_json->content->title)){ // Middleware - MindTouch
 
151
  $title = $decoded_json->content->title;
152
  }
153
- else if (isset($decoded_json->title)){ // Middleware - Zendesk and HubSpot
 
154
  $title = $decoded_json->title;
155
  }
156
- else if (isset($decoded_json->name)){ // Middleware - Email HubSpot
 
157
  $title = $decoded_json->name;
158
- }
159
- else {
160
  $error = true;
161
  }
162
 
163
- return new StandardImportObject($title, $content, $error);
164
  }
165
 
166
- /**
167
- *Converts source XML into a StandardImportObject that can be imported into WP
168
- *@author Unkown
169
- *@param object $source_doc source document
170
- *@param string $xml_string XML string that is then parsed to get the relevant
171
- *information for the title and body
172
- *@return StandardImportObject That can be imported into WP
173
- */
174
- public function xml_to_standard($source_doc, $xml_string){
175
- $content = __('We could not parse the data from this document.
176
- Are you sure that it is in a recognizable format, such as JSON, XML, HTML, or plain text?', 'wp-lingotek');
177
- $title = __('No title found', 'wp-lingotek');
178
- $error_message_xml = __('Failed to load XML', 'wp-lingotek');
179
- $error = false;
180
- $xml = new SimpleXMLElement($xml_string);
181
- if ($xml === false){
 
 
 
 
182
  echo $error_message_xml;
183
  $error = true;
184
  }
185
 
186
- $found_content = (array) $xml->xpath('//element');
187
- if ($found_content){
188
  $content = (string) $found_content[0];
189
- $title = (string) $source_doc->properties->title;
190
- }
191
- else {
192
  $error = true;
193
  }
194
 
195
- return new StandardImportObject($title, $content, $error);
196
  }
197
 
198
- /**
199
- *Converts source TXT into a StandardImportObject that can be imported into WP
200
- *@author Unkown
201
- *@param object $source_doc source document
202
- *@param string $content TXT string that is then parsed to get the relevant
203
- *information for the title and body
204
- *@return StandardImportObject That can be imported into WP
205
- */
206
- public function txt_to_standard($source_doc, $content){
 
207
  $title = $source_doc->properties->title;
208
- return new StandardImportObject($title, $content);
209
  }
210
 
211
- /**
212
- *Converts source PLAINTEXT into a StandardImportObject that can be imported into WP
213
- *@author Unkown
214
- *@param object $source_doc source document
215
- *@param string $content PLAINTEXT string that is then parsed to get the relevant
216
- *information for the title and body
217
- *@return StandardImportObject That can be imported into WP
218
- */
219
- public function plaintext_to_standard($source_doc, $content){
 
220
  $title = $source_doc->properties->title;
221
- return new StandardImportObject($title, $content);
222
  }
223
 
224
- /**
225
- *Converts source HTML into a StandardImportObject that can be imported into WP
226
- *@author Unkown
227
- *@param object $source_doc source document
228
- *@param string $content HTML string that is then parsed to get the relevant
229
- *information for the title and body
230
- *@return StandardImportObject That can be imported into WP
231
- */
232
- public function html_to_standard($source_doc, $content){
 
233
  $title = $source_doc->properties->title;
234
- return new StandardImportObject($title, $content);
235
  }
236
  }
237
- ?>
1
  <?php
2
+ /**
3
+ * I think this file is not used, and probably should be removed.
4
+ *
5
+ * @package lingotek-translation
6
+ */
7
 
8
+ // phpcs:disable
9
  require_once 'StandardImportObject.php';
10
 
11
  /**
12
+ * This class exists to convert other content (e.g. JSON--Drupal 7, Drupal 8, Middleware--
13
+ * HTML, XML, Text, Plaintext) into content compatible with WP
 
 
 
 
 
14
  *
15
+ * @author Unkown
16
+ * @uses StandardImportObject.php|StandardImportObject
17
+ * @return StandardImportObject returns an object that is in the format and has the
18
+ * content to be imported into WordPress
19
  */
20
+ class FormatConverter {
21
+ /**
22
+ * The document that is used to determine information about the import. It is
23
+ * the source document that can be accessed.
24
+ */
25
+ private $source_doc;
26
+ /**
27
+ * The content is the bulk of the information without format, source, etc. This
28
+ * is what is converted into the title and body of the wp import.
29
+ */
30
+ private $content;
31
+ /**
32
+ * The format is the format of the source upload document so that it can be handled
33
+ * by the right conversion function (e.g. JSON, HTML, TXT, etc.)
34
+ */
35
+ private $format;
36
+
37
+ /**
38
+ * Constructor
39
+ * Sets up the FormatConverter object so it can be converted
40
+ *
41
+ * @author Unkown
42
+ *
43
+ * @param object $source_doc The document that needs to be converted and then imported
44
+ * @param string $content The content portion of the document -- This is what becomes
45
+ * the body of the WP post/page
46
+ * @param string $format The format of the file. The extension of the document
47
+ * is used to choose the right function to convert to standard
48
+ * @return void This builds an object that is then converted to wp import
49
+ */
50
+ function __construct( $source_doc, $content, $format ) {
51
+ $this->source_doc = $source_doc;
52
+ $this->content = $content;
53
+ $this->format = $format;
54
+ }
55
+
56
+
57
+ /**
58
+ * This function determines which converter function is needed. If there is not
59
+ * a converter function for the selected document then it defaults to
60
+ * JSON (in the else statement) and attempts the conversion with the assumption
61
+ * of working with a JSON file.
62
+ *
63
+ * @author Unkown
64
+ * @return StandardImportObject $importObject An object that can be imported into WP
65
+ */
66
+ public function convert_to_standard() {
67
+ if ( method_exists( $this, $this->format . '_to_standard' ) ) {
68
+ $importObject = call_user_func( array( $this, $this->format . '_to_standard' ), $this->source_doc, $this->content );
69
+ return $importObject;
70
+ } else {
71
+ $importObject = call_user_func( array( $this, 'json_to_standard' ), $this->source_doc, $this->content );
72
+ return $importObject;
73
+ }
74
+ }
75
+
76
+
77
+ /**
78
+ * Converts source JSON into a StandardImportObject that can be imported into WP
79
+ *
80
+ * @author Unkown
81
+ * @param object $source_doc source document
82
+ * @param string $content JSON string that is then parsed to get the relevant
83
+ * information for the title and body
84
+ * @return StandardImportObject That can be imported into WP
85
+ */
86
+ public function json_to_standard( $source_doc, $content ) {
87
+
88
+ /**
89
+ *These string replaces are to make it so that we can access the json objects
90
+ *with these titles. They were being imported with @ before the key and that
91
+ *made them inaccessible. This is specific to Middleware json strings.
92
+ *
93
+ *@author Matt Smith and TJ Murphy
94
+ */
95
+ $content = str_replace( '"@title"', '"title"', $content );
96
+ $content = str_replace( '"@type"', '"type"', $content );
97
+
98
+ $decoded_json = json_decode( $content );
99
+
100
+ $content = __(
101
+ 'We could not parse the data from this document.
102
+ Are you sure that it is in a recognizable format, such as JSON, XML, HTML, or plain text?',
103
+ 'wp-lingotek'
104
+ );
105
+ $title = __( 'No title found', 'wp-lingotek' );
106
+ $error = false;
107
+
108
+ /**
109
+ *An if statement to check for the different json patterns to find the content
110
+ *that will be the body of the WP imported post/page
111
+ *
112
+ *@author Unkown and TJ Murphy
113
+ *@return string $content is set -- if nothing matches then $content remains
114
+ *with a warning
115
+ *@see $content
116
+ */
117
+ // Drupal 7
118
+ if ( isset( $decoded_json->post->post_content ) ) {
119
  $content = $decoded_json->post->post_content;
120
  }
121
+ // Drupal 8
122
+ elseif ( isset( $decoded_json->body[0]->value ) ) {
123
  $content = $decoded_json->body[0]->value;
124
+ } elseif ( isset( $decoded_json->args->description ) ) {
 
125
  $content = $decoded_json->args->description;
126
  }
127
+ // Middleware - MindTouch
128
+ elseif ( isset( $decoded_json->content->body ) ) {
129
  $content = $decoded_json->content->body;
130
  }
131
+ // Middleware - Zendesk and HubSpot
132
+ elseif ( isset( $decoded_json->body ) ) {
133
  $content = $decoded_json->body;
134
  }
135
+ // Middleware - Email HubSpot
136
+ elseif ( isset( $decoded_json->email_body ) ) {
137
  $content = $decoded_json->email_body;
138
  }
139
+ // Middleware
140
+ elseif ( isset( $decoded_json->post_summary ) ) {
141
  $content = $decoded_json->post_summary;
142
  }
143
+ // Middleware
144
+ elseif ( isset( $decoded_json->description ) ) {
145
  $content = $decoded_json->description;
146
+ } else {
147
+ $error = true;
148
  }
149
+
150
+ /**
151
+ *An if statement to check for the different json patterns to find the title
152
+ *that will be the title of the WP imported post/page
153
+ *
154
+ *@author Unkown and TJ Murphy
155
+ *@return string $title is set -- if nothing matches then $error is set to TRUE
156
+ *@see $title
157
+ */
158
+ // Drupal 8
159
+ if ( isset( $decoded_json->title[0]->value ) ) {
 
160
  $title = $decoded_json->title[0]->value;
161
  }
162
+ // Drupal 7
163
+ elseif ( isset( $decoded_json->post->post_title ) ) {
164
  $title = $decoded_json->post->post_title;
165
  }
166
+ // Middleware - MindTouch
167
+ elseif ( isset( $decoded_json->content->title ) ) {
168
  $title = $decoded_json->content->title;
169
  }
170
+ // Middleware - Zendesk and HubSpot
171
+ elseif ( isset( $decoded_json->title ) ) {
172
  $title = $decoded_json->title;
173
  }
174
+ // Middleware - Email HubSpot
175
+ elseif ( isset( $decoded_json->name ) ) {
176
  $title = $decoded_json->name;
177
+ } else {
 
178
  $error = true;
179
  }
180
 
181
+ return new StandardImportObject( $title, $content, $error );
182
  }
183
 
184
+ /**
185
+ * Converts source XML into a StandardImportObject that can be imported into WP
186
+ *
187
+ * @author Unkown
188
+ * @param object $source_doc source document
189
+ * @param string $xml_string XML string that is then parsed to get the relevant
190
+ * information for the title and body
191
+ * @return StandardImportObject That can be imported into WP
192
+ */
193
+ public function xml_to_standard( $source_doc, $xml_string ) {
194
+ $content = __(
195
+ 'We could not parse the data from this document.
196
+ Are you sure that it is in a recognizable format, such as JSON, XML, HTML, or plain text?',
197
+ 'wp-lingotek'
198
+ );
199
+ $title = __( 'No title found', 'wp-lingotek' );
200
+ $error_message_xml = __( 'Failed to load XML', 'wp-lingotek' );
201
+ $error = false;
202
+ $xml = new SimpleXMLElement( $xml_string );
203
+ if ( $xml === false ) {
204
  echo $error_message_xml;
205
  $error = true;
206
  }
207
 
208
+ $found_content = (array) $xml->xpath( '//element' );
209
+ if ( $found_content ) {
210
  $content = (string) $found_content[0];
211
+ $title = (string) $source_doc->properties->title;
212
+ } else {
 
213
  $error = true;
214
  }
215
 
216
+ return new StandardImportObject( $title, $content, $error );
217
  }
218
 
219
+ /**
220
+ * Converts source TXT into a StandardImportObject that can be imported into WP
221
+ *
222
+ * @author Unkown
223
+ * @param object $source_doc source document
224
+ * @param string $content TXT string that is then parsed to get the relevant
225
+ * information for the title and body
226
+ * @return StandardImportObject That can be imported into WP
227
+ */
228
+ public function txt_to_standard( $source_doc, $content ) {
229
  $title = $source_doc->properties->title;
230
+ return new StandardImportObject( $title, $content );
231
  }
232
 
233
+ /**
234
+ * Converts source PLAINTEXT into a StandardImportObject that can be imported into WP
235
+ *
236
+ * @author Unkown
237
+ * @param object $source_doc source document
238
+ * @param string $content PLAINTEXT string that is then parsed to get the relevant
239
+ * information for the title and body
240
+ * @return StandardImportObject That can be imported into WP
241
+ */
242
+ public function plaintext_to_standard( $source_doc, $content ) {
243
  $title = $source_doc->properties->title;
244
+ return new StandardImportObject( $title, $content );
245
  }
246
 
247
+ /**
248
+ * Converts source HTML into a StandardImportObject that can be imported into WP
249
+ *
250
+ * @author Unkown
251
+ * @param object $source_doc source document
252
+ * @param string $content HTML string that is then parsed to get the relevant
253
+ * information for the title and body
254
+ * @return StandardImportObject That can be imported into WP
255
+ */
256
+ public function html_to_standard( $source_doc, $content ) {
257
  $title = $source_doc->properties->title;
258
+ return new StandardImportObject( $title, $content );
259
  }
260
  }
261
+
admin/import/StandardImportObject.php CHANGED
@@ -1,95 +1,104 @@
1
  <?php
 
 
 
 
 
2
 
 
3
  /**
4
  * Used to hold all important information about a post or page to be imported
5
- *@author Unknown
 
6
  */
7
- class StandardImportObject
8
- {
9
- private $title;
10
- private $content;
11
- private $error;
12
 
13
- /**
14
- *Constructor
15
- *@author Unknown
16
- *@param string $title This is what will become the title of the post/page
17
- *when the document is imported into WP
18
- *@param string $content This is what will become the body of the post/page
19
- *when the document is imported into WP
20
- *@param bool $error captures if there was an error in preparing the document
21
- *@return void just sets the variables
22
- */
23
- function __construct($title, $content, $error = false)
24
- {
25
- $this->title = $title;
26
- $this->content = $content;
27
- $this->error = $error;
28
- }
29
 
30
- /**
31
- *Gets the title of the object
32
- *@author Unknown
33
- *@return string $this->title
34
- */
35
- public function getTitle()
36
- {
37
- return $this->title;
38
- }
 
 
 
 
 
 
 
39
 
40
- /**
41
- *Sets the title of the object
42
- *@author Unknown
43
- *@param string $title What the title of the import should be
44
- *@return self
45
- */
46
- public function setTitle($title)
47
- {
48
- $this->title = $title;
49
- return $this;
50
- }
51
 
52
- /**
53
- *Gets the Content of the object
54
- *@author Unknown
55
- *@return string $this->content
56
- */
57
- public function getContent()
58
- {
59
- return $this->content;
60
- }
 
 
61
 
62
- /**
63
- *Sets the content of the object
64
- *@author Unknown
65
- *@param string $content What the body of the import should be
66
- *@return self
67
- */
68
- public function setContent($content)
69
- {
70
- $this->content = $content;
71
- return $this;
72
- }
73
 
74
- /**
75
- *Sets the error for the object
76
- *@author Unknown
77
- *@param bool $trueOrFalse TRUE means there was an error, FALSE means there
78
- *was not.
79
- *@return void
80
- */
81
- public function setError($trueOrFalse){
82
- $this->error = $trueOrFalse;
83
- }
 
84
 
85
- /**
86
- *Checks to see if the object has an error.
87
- *@author Unknown
88
- *@return bool $this->error
89
- */
90
- public function hasError(){
91
- return $this->error;
92
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
93
 
94
  }
95
- ?>
1
  <?php
2
+ /**
3
+ * I think this file is not used, and probably should be removed.
4
+ *
5
+ * @package lingotek-translation
6
+ */
7
 
8
+ // phpcs:disable
9
  /**
10
  * Used to hold all important information about a post or page to be imported
11
+ *
12
+ * @author Unknown
13
  */
14
+ class StandardImportObject {
 
 
 
 
15
 
16
+ private $title;
17
+ private $content;
18
+ private $error;
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
+ /**
21
+ * Constructor
22
+ *
23
+ * @author Unknown
24
+ * @param string $title This is what will become the title of the post/page
25
+ * when the document is imported into WP
26
+ * @param string $content This is what will become the body of the post/page
27
+ * when the document is imported into WP
28
+ * @param bool $error captures if there was an error in preparing the document
29
+ * @return void just sets the variables
30
+ */
31
+ function __construct( $title, $content, $error = false ) {
32
+ $this->title = $title;
33
+ $this->content = $content;
34
+ $this->error = $error;
35
+ }
36
 
37
+ /**
38
+ * Gets the title of the object
39
+ *
40
+ * @author Unknown
41
+ * @return string $this->title
42
+ */
43
+ public function getTitle() {
44
+ return $this->title;
45
+ }
 
 
46
 
47
+ /**
48
+ * Sets the title of the object
49
+ *
50
+ * @author Unknown
51
+ * @param string $title What the title of the import should be
52
+ * @return self
53
+ */
54
+ public function setTitle( $title ) {
55
+ $this->title = $title;
56
+ return $this;
57
+ }
58
 
59
+ /**
60
+ * Gets the Content of the object
61
+ *
62
+ * @author Unknown
63
+ * @return string $this->content
64
+ */
65
+ public function getContent() {
66
+ return $this->content;
67
+ }
 
 
68
 
69
+ /**
70
+ * Sets the content of the object
71
+ *
72
+ * @author Unknown
73
+ * @param string $content What the body of the import should be
74
+ * @return self
75
+ */
76
+ public function setContent( $content ) {
77
+ $this->content = $content;
78
+ return $this;
79
+ }
80
 
81
+ /**
82
+ * Sets the error for the object
83
+ *
84
+ * @author Unknown
85
+ * @param bool $trueOrFalse TRUE means there was an error, FALSE means there
86
+ * was not.
87
+ * @return void
88
+ */
89
+ public function setError( $trueOrFalse ) {
90
+ $this->error = $trueOrFalse;
91
+ }
92
+
93
+ /**
94
+ * Checks to see if the object has an error.
95
+ *
96
+ * @author Unknown
97
+ * @return bool $this->error
98
+ */
99
+ public function hasError() {
100
+ return $this->error;
101
+ }
102
 
103
  }
104
+
admin/import/import-table.php CHANGED
@@ -1,523 +1,576 @@
1
  <?php
2
-
3
- if (!class_exists('WP_List_Table')) {
4
- require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' ); // since WP 3.1
 
 
 
 
 
 
 
5
  }
6
 
7
  /**
8
  *Requires and evaluates the FormatConverter.php before continuing. If it is not
9
  *found then a fatal error is thrown
 
10
  *@author Unkown
11
  *@link http://php.net/manual/en/function.include.php
12
  *@see FormatConverter.php
13
- *
14
  */
15
  require_once 'FormatConverter.php';
16
  settings_errors();
17
 
18
  /**
19
- *$client is an API call for the client logged in. This gives the end-user the ability
20
- *to manipulate their documents
21
- *@uses wp-lingotek/include/api.php/Lingotek_API
22
- *@deprecated since 24 May 2016 This was making an extra API call and making load
23
- *time very slow.
24
- */
 
25
  //$client = new Lingotek_API();
26
  //$docs = $client->get_documents(array('limit'=>5000));
27
  //$communities = $client->get_communities();
28
 
29
 
30
  /**
31
- *This class is used to prepare the import table that is displayed when users go
32
- *to the import tab.
33
- *@author Unkown
34
- *
35
- */
36
  class Lingotek_Import_Table extends WP_List_Table {
37
 
38
- var $client = null;
39
- var $doc_data = array();
40
- var $projects = array();
41
- var $import_status = null;
42
- var $supported_extentions = array('json', 'xml');
43
- var $document_count = 0;
44
- /**
45
- *Used to mark the number of successful imports on a bulk import
46
- *@author TJ Murphy
47
- */
48
- var $import_success_count = 0;
49
- /**
50
- *Used to mark the number of failed imports on a bulk import
51
- *@author TJ Murphy
52
- */
53
- var $import_failure_count = 0;
54
- /**
55
- *Used to gather the doc ids for documents that did not import as expected
56
- *@author TJ Murphy
57
- */
58
- var $unsuccessful_imports = array();
59
-
60
- /**
61
- *Constructor
62
- *@author Unkown and TJ Murphy
63
- *@uses wp-lingotek/include/api.php/Lingotek_API
64
- *@see Lingotek_Import_Table::get_docs()
65
- *@see Lingotek_Import_Table::format_docs()
66
- */
 
 
 
 
67
  function __construct() {
68
  $this->client = new Lingotek_API();
69
 
70
- $this->projects = $this->get_projects($this->client->get_communities());
71
  $this->document_count = $this->client->get_document_count();
72
- /**
73
- *Sets $import_success_count to ZERO
74
- *@author TJ Murphy
75
- */
76
- $this->import_success_count = 0;
77
- /**
78
- *Sets $import_failure_count to ZERO
79
- *@author TJ Murphy
80
- */
81
- $this->import_failure_count = 0;
82
- /**
83
- *Sets $unsuccessful_imports to a blank array
84
- *@author TJ Murphy
85
- */
86
- $this->unsuccessful_imports = array();
87
- /**
88
- *This will get ALL docs for the client
89
- *@author TJ Murphy
90
- *@see Lingotek_Import_Table::get_docs()
91
- *@see Lingotek_Import_Table::format_docs()
92
- */
93
- $docs = $this->get_docs($this->client, $this->document_count);
94
- $this->doc_data = $this->format_docs($docs);
 
 
 
 
95
 
96
  global $status, $page;
97
- parent::__construct(array(
98
- 'singular' => 'post',
99
- 'plural' => 'posts',
100
- 'ajax' => false
101
- ));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  }
103
- /**
104
- *This function is to access the count of successful imports. It is used for both
105
- *bulk and single imports. This is used for a few checks and a few messages that
106
- *get displayed to the end-user after imports occur
107
- *
108
- *@author TJ Murphy
109
- *@uses Lingotek_Import_Table::$import_success_count
110
- *@return void
111
- *
112
- */
113
- function add_one_import_success_count(){
114
- $this->import_success_count++;
115
- }
116
-
117
- /**
118
- *This function is to add the doc ids of the failed imports to an array so that
119
- *they can be displayed to the end-user. This just gives them more information
120
- *about the errors they may encounter. It also handles the counts for failed imports.
121
- *
122
- *@author TJ Murphy
123
- *@param string $doc_id
124
- *@return void
125
- */
126
- function add_doc_id_to_unsuccessful_imports($doc_id){
127
- array_push($this->unsuccessful_imports,$doc_id);
128
- $this->import_failure_count++;
129
- }
130
-
131
- /**
132
- *This function is to list the captured doc ids in a string separated by commas
133
- *so it can be displayed for the end-user in a message.
134
- *
135
- *@author TJ Murphy
136
- *@uses Lingotek_Import_Table::$unsuccessful_imports
137
- *@return string $unsuccessful_imports_string this creates an HTML string that
138
- *creates an unordered list of doc ids that failed to import
139
- */
140
- function to_string_unsuccessful_imports(){
141
- $unsuccessful_imports_string = '<div><ul>';
142
- foreach ($this->unsuccessful_imports as $doc_id){
143
- $unsuccessful_imports_string = $unsuccessful_imports_string.'<li>'.(string)$doc_id.'</li>';
144
- }
145
- $unsuccessful_imports_string = $unsuccessful_imports_string.'</ul></div>';
146
- return $unsuccessful_imports_string;
147
- }
148
-
149
- /**
150
- *Calls the API to get all the projects from the TMS and show them for the end-user
151
- *@author Unkown
152
- *@uses wp-lingotek/include/api.php/Lingotek_API::get_projects()
153
- *@param $communitites
154
- *@return array $new_projects an array of projects with key/value of (project id, project title)
155
- */
156
- function get_projects($communities){
157
  $new_projects = array();
158
- foreach ($communities->entities as $community){
159
- $projects = $this->client->get_projects($community->properties->id)->entities;
160
- foreach ($projects as $project){
161
- $new_projects[$project->properties->id] = $project->properties->title;
162
  }
163
  }
164
 
165
  return $new_projects;
166
  }
167
 
168
- /**
169
- *Get a list of projects or use id to get the corresponding project
170
- *extract doc data and insert into correct structure for rendering
171
- *@author Unkown
172
- *@uses Lingotek_Import_Table::get_option()
173
- *@param object $docs list of files that need to be properly formatted to show
174
- *in the table
175
- *@return array $result an array of properly formatted objects to be put into
176
- *the table
177
- */
178
- function format_docs($docs) {
179
- $result = array();
180
- $count = 1;
181
- $resources = get_option('lingotek_community_resources');
 
182
  $projectInfoArray = $resources['projects'];
183
 
184
- foreach ($docs as $doc) {
185
- /**
186
- *Convert date from unix time and properly format it
187
- *@author Unkown
188
- */
 
189
  $unix_upload_time = $doc->properties->upload_date / 1000;
190
- $upload_date_str = gmdate("m/j/Y", $unix_upload_time);
191
 
192
  $project_name = $doc->properties->project_id;
193
- if (array_key_exists($doc->properties->project_id, $this->projects)){
194
- $project_name = $this->projects[$doc->properties->project_id];
195
  }
196
 
197
- $doc_properties = array('ID' => $count, 'title' => $doc->properties->title, 'extension' => $doc->properties->extension,
198
- 'locale' => "<a title=". $doc->entities[0]->properties->language.">".$doc->entities[0]->properties->code.'</a>',
199
- 'upload_date' => $upload_date_str, 'project_name'=> $project_name, 'id' => $doc->properties->id);
200
- $result[] = $doc_properties;
 
 
 
 
 
 
201
  $count++;
202
- }
203
  return $result;
204
  }
205
 
206
- /**
207
- *This function makes a query to get the documents
208
- *@author Unkown
209
- *@uses wp-lingotek/include/api.php/Lingotek_API::get_documents()
210
- *@param Lingotek_API $client used to make the API calls to get the docs
211
- *@param int $per_page default = 10 limits the query to 10 results
212
- *@param int $page_number default = 1 helps to determine the offset
213
- *(so we get the right x amount of documents presented on the current page)
214
- *@return array $docs list of documents returned from the API call get_documents()
215
- */
216
- function get_docs($client, $per_page = 10, $page_number = 1){
217
-
218
  $limit = $per_page;
219
- $docs = $client->get_documents(array('limit'=>$limit, 'offset'=>(($page_number - 1) * $per_page )));
 
 
 
 
 
220
  return $docs;
221
  }
222
 
223
- /**
224
- * Gets the columns for the table to be displayed properly
225
- *@author Unkown
226
- *@return array $columns the appropriate columns i18n ready
227
- */
 
228
  function get_columns() {
229
  $columns = array(
230
- 'cb' => '<input type="checkbox" />',
231
- 'title' => __('Title', 'wp-lingotek'),
232
- 'extension'=> __('Extension', 'wp-lingotek'),
233
- 'locale' => __('Locale', 'wp-lingotek'),
234
- 'upload_date' => __('Upload Date', 'wp-lingotek'),
235
- 'project_name' => __('Project Name', 'wp-lingotek'),
236
- 'id' => __('ID', 'wp-lingotek'),
237
  );
238
  return $columns;
239
  }
240
 
241
- /**
242
- *This function prepares all the items to be displayed. It calls the get_columns()
243
- *and other supporting funcitons.
244
- *@author Unkown and TJ Murphy
245
- *@uses Lingotek_Import_Table::get_columns()
246
- *@uses Lingotek_Import_Table::process_actions()
247
- *@uses Lingotek_Import_Table::get_sortable_columns()
248
- *@uses Lingotek_Import_Table::usort_reorder()
249
- *@see wp-admin/includes/class-wp-list-table.php/WP_List_Table::get_items_per_page()
250
- *@see wp-admin/includes/class-wp-list-table.php/WP_List_Table::get_pagenum()
251
- *@see wp-admin/includes/class-wp-list-table.php/WP_List_Table::set_pagination_args()
252
- *@return void This just sets some variables within the object
253
- */
 
254
  function prepare_items() {
255
 
256
- /**
257
- *Constant to define how many items per page will show up.
258
- *@author TJ Murphy
259
- */
260
- define('ITEMS_PER_PAGE', 10);
 
261
 
262
  $columns = $this->get_columns();
263
  $this->process_actions();
264
  $hidden = array();
265
 
266
- $sortable = $this->get_sortable_columns();
267
- $this->_column_headers = array($columns, $hidden, $sortable);
268
-
269
- /**
270
- *Sets the total_items (total number of documents calculated by us) and
271
- *the per_page (how many documents appear on a page dtermined by us)
272
- *@see wp-admin/includes/class-wp-list-table.php/WP_List_Table::set_pagination_args()
273
- */
274
- $this->set_pagination_args( [
275
- 'total_items' => $this->document_count,
276
- 'per_page' => ITEMS_PER_PAGE
277
- ] );
278
-
279
- usort($this->doc_data, array(&$this, 'usort_reorder'));
280
-
281
- /**
282
- *This slices the documents for the client and only shows the appropriate number
283
- *of documents based on the constant ITEMS_PER_PAGE. array_slice takes three
284
- *parameters ($array, $offset, $length)
285
- *@author TJ Murphy
286
- *@link http://php.net/manual/en/function.array-slice.php
287
- */
288
- $this->items = array_slice($this->doc_data,((ITEMS_PER_PAGE*$this->get_pagenum())-ITEMS_PER_PAGE),ITEMS_PER_PAGE);
 
 
 
 
289
  }
290
 
291
- /**
292
- *This sets the column default. The default for the switch statement shows the
293
- *whole array for troubleshooting purposes
294
- *@author Unkown
295
- *@param array $item
296
- *@param string $column_name
297
- *@return string $item[$column_name]
298
- */
299
- function column_default($item, $column_name) {
300
- switch ($column_name) {
 
301
  case 'title':
302
  case 'extension':
303
  case 'locale':
304
  case 'upload_date':
305
  case 'project_name':
306
  case 'id':
307
- return $item[$column_name];
308
  default:
309
- return print_r($item, true);
310
  }
311
  }
312
 
313
- /**
314
- *Gets the sortable columns and returns the list
315
- *@author Unkown
316
- *@return array $sortable_columns
317
- */
 
318
  function get_sortable_columns() {
319
  $sortable_columns = array(
320
- 'title' => array('title', false),
321
- 'extension'=>array('extension', false),
322
- 'locale' => array('locale', false),
323
- 'upload_date' => array('upload_date', false),
324
- 'project_name' => array('project_name', false),
325
- 'id' => array('id', false)
326
  );
327
  return $sortable_columns;
328
  }
329
 
330
- /**
331
- *Sorts the documents by one of the columns. The default sort is with the Title
332
- *and ascending order. The date sort has its own method to sort, but all other
333
- *columns are sorted the same way.
334
- *@author Unknown
335
- *@return int $result direction of sort
336
- *@todo it would be great to make the query that gets the documents do an Order By
337
- *and then this would not even be necessary. It appears this is a limitation in
338
- *the API.
339
- */
340
- function usort_reorder($a, $b) {
341
- $orderby = (!empty($_GET['orderby']) ) ? $_GET['orderby'] : 'title';
342
- $order = (!empty($_GET['order']) ) ? $_GET['order'] : 'asc';
343
- $result = 0;
344
- if ($orderby == 'upload_date'){
345
- $date_a = strtotime($a['upload_date']);
346
- $date_b = strtotime($b['upload_date']);
 
347
  $result = $date_a - $date_b;
348
- }
349
- else {
350
- $result = strcmp($a[$orderby], $b[$orderby]);
351
  }
352
 
353
  return ( $order === 'asc' ) ? $result : -$result;
354
  }
355
 
356
- /**
357
- *Sets the column Title to have the right information in that column. This includes
358
- *the popup link to import the file.
359
- *@author Unknown
360
- *@see wp-lingotek/admin/string-actions.php/Lingotek_String_actions::row_actions()
361
- *@return string to be put in the column when displayed
362
- */
363
- function column_title($item) {
 
364
  $actions = array(
365
- 'import' => sprintf('<a href="?page=%s&action=%s&post=%s&count=%s&paged=%s">Import</a>',
366
- $_REQUEST['page'], 'import', $item['id'], $this->importedCount, $this->get_pagenum()),
 
 
 
 
 
 
367
  );
368
- return sprintf('%1$s %2$s', $item['title'], $this->row_actions($actions));
369
  }
370
 
371
- /**
372
- *This just gets the actions that are available for bulk actions
373
- *@author Unknown
374
- *@return array $actions available actions to be done on a bulk level
375
- */
 
376
  function get_bulk_actions() {
377
  $actions = array(
378
- 'import' => 'Import'
379
  );
380
  return $actions;
381
  }
382
 
383
- /**
384
- *This function processes any actions (currently the only action is import).
385
- *This includes bulk imports and individual imports. Then it sets the import as
386
- *successful or unsuccessful.
387
- *@author Unknown
388
- *@uses Lingotek_Import_Table::add_one_import_success_count()
389
- *@uses Lingotek_Import_Table::add_doc_id_to_unsuccessful_imports()
390
- *@uses Lingotek_Import_Table::import()
391
- *@uses Lingotek_Import_Table::$import_success_count
392
- *@uses Lingotek_Import_Table::$import_status
393
- *@return void this just sets certain variables in the object.
394
- */
 
395
  public function process_actions() {
396
  $result = null;
397
- if( 'import' === $this->current_action() ) {
398
- if (isset($_POST['post'])){ // bulk action
399
- foreach($_POST['post'] as $doc_id){
400
- $result = $this->import($doc_id);
401
- if ($result != 0){
402
- $this->add_one_import_success_count();
403
- }
404
- else {
405
- $this->add_doc_id_to_unsuccessful_imports($doc_id);
406
- }
407
  }
408
- }
409
- else {
410
- if (isset($_GET['action']) && $_GET['action'] == 'import'){ //single action
411
  $doc_id = $_GET['post'];
412
- $result = $this->import($doc_id);
413
- if ($result != 0){
414
- $this->add_one_import_success_count();
415
- }
416
- else {
417
- $this->add_doc_id_to_unsuccessful_imports($doc_id);
418
- }
419
  }
420
- }
421
-
422
- /**
423
- *This checks the import_success_count to determine if the import status
424
- *wassuccessful or not. It used to just check if the $result was 0 or not.
425
- *This led to the last bulk import to determine the import status. Now if
426
- *any imports are successful it will mark the import status as successful.
427
- *@author TJ Murphy
428
- *@uses Lingotek_Import_Table::$import_success_count
429
- *@uses Lingotek_Import_Table::$import_status
430
- */
431
- if ($this->import_success_count > 0){
 
432
  $this->import_status = 'success';
433
- }
434
- else {
435
  $this->import_status = 'failure';
436
  }
437
- }
438
  }
439
 
440
- /**
441
- *This converts the many objects and strings that are documents into a format
442
- *that can be imported into WP. If $post_status is not set it gets set to draft.
443
- *If the $post_type is not set then it gets set to post.
444
- *@author Unknown
445
- *@uses wp-lingotek/admin/import/StandardImportObject.php/StandardImportObject
446
- *@uses wp-lingotek/admin/import/StandardImportObject.php/StandardImportObject::getTitle()
447
- *@uses wp-lingotek/admin/import/StandardImportObject.php/StandardImportObject::getContent()
448
- *@see wp-admin/includes/class-wp-screen.php/WP_Screen::get_option()
449
- *@link https://developer.wordpress.org/reference/functions/wp_insert_post/
450
- *@param StandardImportObject $object a document that needs to be converted to
451
- *a standard object that can be imported into WP
452
- *@return int|bool $result 0 or 1 to show if it was successful or not
453
- */
454
- public function import_standard_object(StandardImportObject $object){
455
- if ($object->hasError()){
 
456
  return 0;
457
  }
458
 
459
- $post_status = get_option('lingotek_import_prefs')['import_post_status'];
460
- $post_type = get_option('lingotek_import_prefs')['import_type'];
461
- if (!isset($post_status) ){
462
  $post_status = 'draft';
463
  }
464
- if (!isset($post_type) ){
465
  $post_type = 'post';
466
  }
467
 
468
- $post_to_import = array(
469
- 'post_title' => $object->getTitle(),
470
- 'post_content' => $object->getContent(),
471
- 'post_status' => $post_status, // draft, published, etc.
472
- 'post_type' => $post_type, // page or post?
473
- 'post_category' => array(8,39)
474
- );
475
- /**
476
- *@link https://developer.wordpress.org/reference/functions/wp_insert_post/
477
- */
 
 
478
  $result = wp_insert_post( $post_to_import );
479
  return $result;
480
- }
481
 
482
- /**
483
- *This function makes the API calls that send a query and get the documents
484
- *@author Unknown
485
- *@uses Lingotek_Import_Table::$client
486
- *@uses wp-lingotek/admin/import/FormatConverter.php/FormatConverter
487
- *@uses wp-lingotek/admin/import/FormatConverter.php/FormatConverter::convert_to_standard()
488
- *@uses wp-lingotek/admin/import/FormatConverter.php/FormatConverter::import_standard_object()
489
- */
490
- public function import($doc_id){
491
-
492
- $source_doc = $this->client->get_document($doc_id);
493
-
494
- $content =$this->client->get_document_content($doc_id);
495
- if ($content == null){
496
- $content == __('There is no content to display', 'wp-lingotek');
497
  }
498
 
499
- $format = $source_doc->properties->extension;
500
- $formatConverter = new FormatConverter($source_doc, $content, $format);
501
- $importObject = $formatConverter->convert_to_standard();
502
- $response = $this->import_standard_object($importObject);
503
  return $response;
504
  }
505
 
506
- /**
507
- *Prints the Column Checkbox
508
- *@author Unknown
509
- *@return string the HTML necessary to show the Checkbox
510
- */
511
- function column_cb($item) {
512
- return sprintf('<input type="checkbox" name="post[]" value="%s" />', $item['id']);
 
513
  }
514
 
515
- /**
516
- *This gets the import status
517
- *@author Unknown
518
- *@return string $this->import_status
519
- */
520
- function get_import_status(){
 
521
  return $this->import_status;
522
  }
523
  }
1
  <?php
2
+ /**
3
+ * I think this file is not used, and probably should be removed.
4
+ *
5
+ * @package lingotek-translation
6
+ */
7
+
8
+ // phpcs:disable
9
+ if ( ! class_exists( 'WP_List_Table' ) ) {
10
+ // since WP 3.1
11
+ require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
12
  }
13
 
14
  /**
15
  *Requires and evaluates the FormatConverter.php before continuing. If it is not
16
  *found then a fatal error is thrown
17
+ *
18
  *@author Unkown
19
  *@link http://php.net/manual/en/function.include.php
20
  *@see FormatConverter.php
 
21
  */
22
  require_once 'FormatConverter.php';
23
  settings_errors();
24
 
25
  /**
26
+ * $client is an API call for the client logged in. This gives the end-user the ability
27
+ * to manipulate their documents
28
+ *
29
+ * @uses wp-lingotek/include/api.php/Lingotek_API
30
+ * @deprecated since 24 May 2016 This was making an extra API call and making load
31
+ * time very slow.
32
+ */
33
  //$client = new Lingotek_API();
34
  //$docs = $client->get_documents(array('limit'=>5000));
35
  //$communities = $client->get_communities();
36
 
37
 
38
  /**
39
+ * This class is used to prepare the import table that is displayed when users go
40
+ * to the import tab.
41
+ *
42
+ * @author Unkown
43
+ */
44
  class Lingotek_Import_Table extends WP_List_Table {
45
 
46
+ var $client = null;
47
+ var $doc_data = array();
48
+ var $projects = array();
49
+ var $import_status = null;
50
+ var $supported_extentions = array( 'json', 'xml' );
51
+ var $document_count = 0;
52
+ /**
53
+ * Used to mark the number of successful imports on a bulk import
54
+ *
55
+ * @author TJ Murphy
56
+ */
57
+ var $import_success_count = 0;
58
+ /**
59
+ * Used to mark the number of failed imports on a bulk import
60
+ *
61
+ * @author TJ Murphy
62
+ */
63
+ var $import_failure_count = 0;
64
+ /**
65
+ * Used to gather the doc ids for documents that did not import as expected
66
+ *
67
+ * @author TJ Murphy
68
+ */
69
+ var $unsuccessful_imports = array();
70
+
71
+ /**
72
+ * Constructor
73
+ *
74
+ * @author Unkown and TJ Murphy
75
+ * @uses wp-lingotek/include/api.php/Lingotek_API
76
+ * @see Lingotek_Import_Table::get_docs()
77
+ * @see Lingotek_Import_Table::format_docs()
78
+ */
79
  function __construct() {
80
  $this->client = new Lingotek_API();
81
 
82
+ $this->projects = $this->get_projects( $this->client->get_communities() );
83
  $this->document_count = $this->client->get_document_count();
84
+ /**
85
+ *Sets $import_success_count to ZERO
86
+ *
87
+ *@author TJ Murphy
88
+ */
89
+ $this->import_success_count = 0;
90
+ /**
91
+ *Sets $import_failure_count to ZERO
92
+ *
93
+ *@author TJ Murphy
94
+ */
95
+ $this->import_failure_count = 0;
96
+ /**
97
+ *Sets $unsuccessful_imports to a blank array
98
+ *
99
+ *@author TJ Murphy
100
+ */
101
+ $this->unsuccessful_imports = array();
102
+ /**
103
+ *This will get ALL docs for the client
104
+ *
105
+ *@author TJ Murphy
106
+ *@see Lingotek_Import_Table::get_docs()
107
+ *@see Lingotek_Import_Table::format_docs()
108
+ */
109
+ $docs = $this->get_docs( $this->client, $this->document_count );
110
+ $this->doc_data = $this->format_docs( $docs );
111
 
112
  global $status, $page;
113
+ parent::__construct(
114
+ array(
115
+ 'singular' => 'post',
116
+ 'plural' => 'posts',
117
+ 'ajax' => false,
118
+ )
119
+ );
120
+ }
121
+ /**
122
+ * This function is to access the count of successful imports. It is used for both
123
+ * bulk and single imports. This is used for a few checks and a few messages that
124
+ * get displayed to the end-user after imports occur
125
+ *
126
+ * @author TJ Murphy
127
+ * @uses Lingotek_Import_Table::$import_success_count
128
+ * @return void
129
+ */
130
+ function add_one_import_success_count() {
131
+ $this->import_success_count++;
132
  }
133
+
134
+ /**
135
+ * This function is to add the doc ids of the failed imports to an array so that
136
+ * they can be displayed to the end-user. This just gives them more information
137
+ * about the errors they may encounter. It also handles the counts for failed imports.
138
+ *
139
+ * @author TJ Murphy
140
+ * @param string $doc_id
141
+ * @return void
142
+ */
143
+ function add_doc_id_to_unsuccessful_imports( $doc_id ) {
144
+ array_push( $this->unsuccessful_imports, $doc_id );
145
+ $this->import_failure_count++;
146
+ }
147
+
148
+ /**
149
+ * This function is to list the captured doc ids in a string separated by commas
150
+ * so it can be displayed for the end-user in a message.
151
+ *
152
+ * @author TJ Murphy
153
+ * @uses Lingotek_Import_Table::$unsuccessful_imports
154
+ * @return string $unsuccessful_imports_string this creates an HTML string that
155
+ * creates an unordered list of doc ids that failed to import
156
+ */
157
+ function to_string_unsuccessful_imports() {
158
+ $unsuccessful_imports_string = '<div><ul>';
159
+ foreach ( $this->unsuccessful_imports as $doc_id ) {
160
+ $unsuccessful_imports_string = $unsuccessful_imports_string . '<li>' . (string) $doc_id . '</li>';
161
+ }
162
+ $unsuccessful_imports_string = $unsuccessful_imports_string . '</ul></div>';
163
+ return $unsuccessful_imports_string;
164
+ }
165
+
166
+ /**
167
+ * Calls the API to get all the projects from the TMS and show them for the end-user
168
+ *
169
+ * @author Unkown
170
+ * @uses wp-lingotek/include/api.php/Lingotek_API::get_projects()
171
+ * @param $communitites
172
+ * @return array $new_projects an array of projects with key/value of (project id, project title)
173
+ */
174
+ function get_projects( $communities ) {
 
 
 
 
 
 
 
 
 
 
 
 
175
  $new_projects = array();
176
+ foreach ( $communities->entities as $community ) {
177
+ $projects = $this->client->get_projects( $community->properties->id )->entities;
178
+ foreach ( $projects as $project ) {
179
+ $new_projects[ $project->properties->id ] = $project->properties->title;
180
  }
181
  }
182
 
183
  return $new_projects;
184
  }
185
 
186
+ /**
187
+ * Get a list of projects or use id to get the corresponding project
188
+ * extract doc data and insert into correct structure for rendering
189
+ *
190
+ * @author Unkown
191
+ * @uses Lingotek_Import_Table::get_option()
192
+ * @param object $docs list of files that need to be properly formatted to show
193
+ * in the table
194
+ * @return array $result an array of properly formatted objects to be put into
195
+ * the table
196
+ */
197
+ function format_docs( $docs ) {
198
+ $result = array();
199
+ $count = 1;
200
+ $resources = get_option( 'lingotek_community_resources' );
201
  $projectInfoArray = $resources['projects'];
202
 
203
+ foreach ( $docs as $doc ) {
204
+ /**
205
+ *Convert date from unix time and properly format it
206
+ *
207
+ *@author Unkown
208
+ */
209
  $unix_upload_time = $doc->properties->upload_date / 1000;
210
+ $upload_date_str = gmdate( 'm/j/Y', $unix_upload_time );
211
 
212
  $project_name = $doc->properties->project_id;
213
+ if ( array_key_exists( $doc->properties->project_id, $this->projects ) ) {
214
+ $project_name = $this->projects[ $doc->properties->project_id ];
215
  }
216
 
217
+ $doc_properties = array(
218
+ 'ID' => $count,
219
+ 'title' => $doc->properties->title,
220
+ 'extension' => $doc->properties->extension,
221
+ 'locale' => '<a title=' . $doc->entities[0]->properties->language . '>' . $doc->entities[0]->properties->code . '</a>',
222
+ 'upload_date' => $upload_date_str,
223
+ 'project_name' => $project_name,
224
+ 'id' => $doc->properties->id,
225
+ );
226
+ $result[] = $doc_properties;
227
  $count++;
228
+ }//end foreach
229
  return $result;
230
  }
231
 
232
+ /**
233
+ * This function makes a query to get the documents
234
+ *
235
+ * @author Unkown
236
+ * @uses wp-lingotek/include/api.php/Lingotek_API::get_documents()
237
+ * @param Lingotek_API $client used to make the API calls to get the docs
238
+ * @param int $per_page default = 10 limits the query to 10 results
239
+ * @param int $page_number default = 1 helps to determine the offset
240
+ * (so we get the right x amount of documents presented on the current page)
241
+ * @return array $docs list of documents returned from the API call get_documents()
242
+ */
243
+ function get_docs( $client, $per_page = 10, $page_number = 1 ) {
244
  $limit = $per_page;
245
+ $docs = $client->get_documents(
246
+ array(
247
+ 'limit' => $limit,
248
+ 'offset' => ( ( $page_number - 1 ) * $per_page ),
249
+ )
250
+ );
251
  return $docs;
252
  }
253
 
254
+ /**
255
+ * Gets the columns for the table to be displayed properly
256
+ *
257
+ * @author Unkown
258
+ * @return array $columns the appropriate columns i18n ready
259
+ */
260
  function get_columns() {
261
  $columns = array(
262
+ 'cb' => '<input type="checkbox" />',
263
+ 'title' => __( 'Title', 'wp-lingotek' ),
264
+ 'extension' => __( 'Extension', 'wp-lingotek' ),
265
+ 'locale' => __( 'Locale', 'wp-lingotek' ),
266
+ 'upload_date' => __( 'Upload Date', 'wp-lingotek' ),
267
+ 'project_name' => __( 'Project Name', 'wp-lingotek' ),
268
+ 'id' => __( 'ID', 'wp-lingotek' ),
269
  );
270
  return $columns;
271
  }
272
 
273
+ /**
274
+ * This function prepares all the items to be displayed. It calls the get_columns()
275
+ * and other supporting funcitons.
276
+ *
277
+ * @author Unkown and TJ Murphy
278
+ * @uses Lingotek_Import_Table::get_columns()
279
+ * @uses Lingotek_Import_Table::process_actions()
280
+ * @uses Lingotek_Import_Table::get_sortable_columns()
281
+ * @uses Lingotek_Import_Table::usort_reorder()
282
+ * @see wp-admin/includes/class-wp-list-table.php/WP_List_Table::get_items_per_page()
283
+ * @see wp-admin/includes/class-wp-list-table.php/WP_List_Table::get_pagenum()
284
+ * @see wp-admin/includes/class-wp-list-table.php/WP_List_Table::set_pagination_args()
285
+ * @return void This just sets some variables within the object
286
+ */
287
  function prepare_items() {
288
 
289
+ /**
290
+ *Constant to define how many items per page will show up.
291
+ *
292
+ *@author TJ Murphy
293
+ */
294
+ define( 'ITEMS_PER_PAGE', 10 );
295
 
296
  $columns = $this->get_columns();
297
  $this->process_actions();
298
  $hidden = array();
299
 
300
+ $sortable = $this->get_sortable_columns();
301
+ $this->_column_headers = array( $columns, $hidden, $sortable );
302
+
303
+ /**
304
+ *Sets the total_items (total number of documents calculated by us) and
305
+ *the per_page (how many documents appear on a page dtermined by us)
306
+ *
307
+ *@see wp-admin/includes/class-wp-list-table.php/WP_List_Table::set_pagination_args()
308
+ */
309
+ $this->set_pagination_args(
310
+ array(
311
+ 'total_items' => $this->document_count,
312
+ 'per_page' => ITEMS_PER_PAGE,
313
+ )
314
+ );
315
+
316
+ usort( $this->doc_data, array( &$this, 'usort_reorder' ) );
317
+
318
+ /**
319
+ *This slices the documents for the client and only shows the appropriate number
320
+ *of documents based on the constant ITEMS_PER_PAGE. array_slice takes three
321
+ *parameters ($array, $offset, $length)
322
+ *
323
+ *@author TJ Murphy
324
+ *@link http://php.net/manual/en/function.array-slice.php
325
+ */
326
+ $this->items = array_slice( $this->doc_data, ( ( ITEMS_PER_PAGE * $this->get_pagenum() ) - ITEMS_PER_PAGE ), ITEMS_PER_PAGE );
327
  }
328
 
329
+ /**
330
+ * This sets the column default. The default for the switch statement shows the
331
+ * whole array for troubleshooting purposes
332
+ *
333
+ * @author Unkown
334
+ * @param array $item
335
+ * @param string $column_name
336
+ * @return string $item[$column_name]
337
+ */
338
+ function column_default( $item, $column_name ) {
339
+ switch ( $column_name ) {
340
  case 'title':
341
  case 'extension':
342
  case 'locale':
343
  case 'upload_date':
344
  case 'project_name':
345
  case 'id':
346
+ return $item[ $column_name ];
347
  default:
348
+ return print_r( $item, true );
349
  }
350
  }
351
 
352
+ /**
353
+ * Gets the sortable columns and returns the list
354
+ *
355
+ * @author Unkown
356
+ * @return array $sortable_columns
357
+ */
358
  function get_sortable_columns() {
359
  $sortable_columns = array(
360
+ 'title' => array( 'title', false ),
361
+ 'extension' => array( 'extension', false ),
362
+ 'locale' => array( 'locale', false ),
363
+ 'upload_date' => array( 'upload_date', false ),
364
+ 'project_name' => array( 'project_name', false ),
365
+ 'id' => array( 'id', false ),
366
  );
367
  return $sortable_columns;
368
  }
369
 
370
+ /**
371
+ * Sorts the documents by one of the columns. The default sort is with the Title
372
+ * and ascending order. The date sort has its own method to sort, but all other
373
+ * columns are sorted the same way.
374
+ *
375
+ * @author Unknown
376
+ * @return int $result direction of sort
377
+ * @todo it would be great to make the query that gets the documents do an Order By
378
+ * and then this would not even be necessary. It appears this is a limitation in
379
+ * the API.
380
+ */
381
+ function usort_reorder( $a, $b ) {
382
+ $orderby = ( ! empty( $_GET['orderby'] ) ) ? $_GET['orderby'] : 'title';
383
+ $order = ( ! empty( $_GET['order'] ) ) ? $_GET['order'] : 'asc';
384
+ $result = 0;
385
+ if ( $orderby == 'upload_date' ) {
386
+ $date_a = strtotime( $a['upload_date'] );
387
+ $date_b = strtotime( $b['upload_date'] );
388
  $result = $date_a - $date_b;
389
+ } else {
390
+ $result = strcmp( $a[ $orderby ], $b[ $orderby ] );
 
391
  }
392
 
393
  return ( $order === 'asc' ) ? $result : -$result;
394
  }
395
 
396
+ /**
397
+ * Sets the column Title to have the right information in that column. This includes
398
+ * the popup link to import the file.
399
+ *
400
+ * @author Unknown
401
+ * @see wp-lingotek/admin/string-actions.php/Lingotek_String_actions::row_actions()
402
+ * @return string to be put in the column when displayed
403
+ */
404
+ function column_title( $item ) {
405
  $actions = array(
406
+ 'import' => sprintf(
407
+ '<a href="?page=%s&action=%s&post=%s&count=%s&paged=%s">Import</a>',
408
+ $_REQUEST['page'],
409
+ 'import',
410
+ $item['id'],
411
+ $this->importedCount,
412
+ $this->get_pagenum()
413
+ ),
414
  );
415
+ return sprintf( '%1$s %2$s', $item['title'], $this->row_actions( $actions ) );
416
  }
417
 
418
+ /**
419
+ * This just gets the actions that are available for bulk actions
420
+ *
421
+ * @author Unknown
422
+ * @return array $actions available actions to be done on a bulk level
423
+ */
424
  function get_bulk_actions() {
425
  $actions = array(
426
+ 'import' => 'Import',
427
  );
428
  return $actions;
429
  }
430
 
431
+ /**
432
+ * This function processes any actions (currently the only action is import).
433
+ * This includes bulk imports and individual imports. Then it sets the import as
434
+ * successful or unsuccessful.
435
+ *
436
+ * @author Unknown
437
+ * @uses Lingotek_Import_Table::add_one_import_success_count()
438
+ * @uses Lingotek_Import_Table::add_doc_id_to_unsuccessful_imports()
439
+ * @uses Lingotek_Import_Table::import()
440
+ * @uses Lingotek_Import_Table::$import_success_count
441
+ * @uses Lingotek_Import_Table::$import_status
442
+ * @return void this just sets certain variables in the object.
443
+ */
444
  public function process_actions() {
445
  $result = null;
446
+ if ( 'import' === $this->current_action() ) {
447
+ // Bulk action.
448
+ if ( isset( $_POST['post'] ) ) {
449
+ foreach ( $_POST['post'] as $doc_id ) {
450
+ $result = $this->import( $doc_id );
451
+ if ( $result != 0 ) {
452
+ $this->add_one_import_success_count();
453
+ } else {
454
+ $this->add_doc_id_to_unsuccessful_imports( $doc_id );
455
+ }
456
  }
457
+ } else {
458
+ // Single action.
459
+ if ( isset( $_GET['action'] ) && $_GET['action'] == 'import' ) {
460
  $doc_id = $_GET['post'];
461
+ $result = $this->import( $doc_id );
462
+ if ( $result != 0 ) {
463
+ $this->add_one_import_success_count();
464
+ } else {
465
+ $this->add_doc_id_to_unsuccessful_imports( $doc_id );
466
+ }
 
467
  }
468
+ }//end if
469
+
470
+ /**
471
+ *This checks the import_success_count to determine if the import status
472
+ *wassuccessful or not. It used to just check if the $result was 0 or not.
473
+ *This led to the last bulk import to determine the import status. Now if
474
+ *any imports are successful it will mark the import status as successful.
475
+ *
476
+ *@author TJ Murphy
477
+ *@uses Lingotek_Import_Table::$import_success_count
478
+ *@uses Lingotek_Import_Table::$import_status
479
+ */
480
+ if ( $this->import_success_count > 0 ) {
481
  $this->import_status = 'success';
482
+ } else {
 
483
  $this->import_status = 'failure';
484
  }
485
+ }//end if
486
  }
487
 
488
+ /**
489
+ * This converts the many objects and strings that are documents into a format
490
+ * that can be imported into WP. If $post_status is not set it gets set to draft.
491
+ * If the $post_type is not set then it gets set to post.
492
+ *
493
+ * @author Unknown
494
+ * @uses wp-lingotek/admin/import/StandardImportObject.php/StandardImportObject
495
+ * @uses wp-lingotek/admin/import/StandardImportObject.php/StandardImportObject::getTitle()
496
+ * @uses wp-lingotek/admin/import/StandardImportObject.php/StandardImportObject::getContent()
497
+ * @see wp-admin/includes/class-wp-screen.php/WP_Screen::get_option()
498
+ * @link https://developer.wordpress.org/reference/functions/wp_insert_post/
499
+ * @param StandardImportObject $object a document that needs to be converted to
500
+ * a standard object that can be imported into WP
501
+ * @return int|bool $result 0 or 1 to show if it was successful or not
502
+ */
503
+ public function import_standard_object( StandardImportObject $object ) {
504
+ if ( $object->hasError() ) {
505
  return 0;
506
  }
507
 
508
+ $post_status = get_option( 'lingotek_import_prefs' )['import_post_status'];
509
+ $post_type = get_option( 'lingotek_import_prefs' )['import_type'];
510
+ if ( ! isset( $post_status ) ) {
511
  $post_status = 'draft';
512
  }
513
+ if ( ! isset( $post_type ) ) {
514
  $post_type = 'post';
515
  }
516
 
517
+ $post_to_import = array(
518
+ 'post_title' => $object->getTitle(),
519
+ 'post_content' => $object->getContent(),
520
+ // draft, published, etc.
521
+ 'post_status' => $post_status,
522
+ // page or post?
523
+ 'post_type' => $post_type,
524
+ 'post_category' => array( 8, 39 ),
525
+ );
526
+ /**
527
+ *@link https://developer.wordpress.org/reference/functions/wp_insert_post/
528
+ */
529
  $result = wp_insert_post( $post_to_import );
530
  return $result;
531
+ }
532
 
533
+ /**
534
+ * This function makes the API calls that send a query and get the documents
535
+ *
536
+ * @author Unknown
537
+ * @uses Lingotek_Import_Table::$client
538
+ * @uses wp-lingotek/admin/import/FormatConverter.php/FormatConverter
539
+ * @uses wp-lingotek/admin/import/FormatConverter.php/FormatConverter::convert_to_standard()
540
+ * @uses wp-lingotek/admin/import/FormatConverter.php/FormatConverter::import_standard_object()
541
+ */
542
+ public function import( $doc_id ) {
543
+ $source_doc = $this->client->get_document( $doc_id );
544
+
545
+ $content = $this->client->get_document_content( $doc_id );
546
+ if ( $content == null ) {
547
+ $content == __( 'There is no content to display', 'wp-lingotek' );
548
  }
549
 
550
+ $format = $source_doc->properties->extension;
551
+ $formatConverter = new FormatConverter( $source_doc, $content, $format );
552
+ $importObject = $formatConverter->convert_to_standard();
553
+ $response = $this->import_standard_object( $importObject );
554
  return $response;
555
  }
556
 
557
+ /**
558
+ * Prints the Column Checkbox
559
+ *
560
+ * @author Unknown
561
+ * @return string the HTML necessary to show the Checkbox
562
+ */
563
+ function column_cb( $item ) {
564
+ return sprintf( '<input type="checkbox" name="post[]" value="%s" />', $item['id'] );
565
  }
566
 
567
+ /**
568
+ * This gets the import status
569
+ *
570
+ * @author Unknown
571
+ * @return string $this->import_status
572
+ */
573
+ function get_import_status() {
574
  return $this->import_status;
575
  }
576
  }
admin/import/view-content.php CHANGED
@@ -1,139 +1,152 @@
1
  <?php
2
  /**
3
- *This file actually prepares the content to be viewed and calls the other files
4
- *as needed so that everything appears as expected.
5
- *@author Unknown
 
 
 
 
 
 
 
 
6
  */
7
 
8
 
9
- include_once 'import-table.php';
10
 
11
- $profile = Lingotek_Model::get_profile('string', $this->pllm->get_language($this->pllm->options['default_lang']));
12
 
13
  /**
14
  *Tests to see if the profile is disabled or not.
 
15
  *@author Unknown
16
  */
17
- if ('disabled' == $profile['profile']) {
18
- printf('<div class="error" style="border-left: 4px solid #ffba00;"><p>%s</p></div>',
19
- sprintf(__('The strings translation is disabled in %sContent Type Configuration%s.', 'wp-lingotek'),
20
- '<a href="' . admin_url('admin.php?page=wp-lingotek_settings&sm=content') . '">',
 
 
21
  '</a>'
22
  )
23
  );
24
- }
25
- else {
26
- $table = new Lingotek_Import_Table();
27
 
28
  $table->prepare_items();
29
- //Gets the import type (post or page)
30
- $post_type = get_option('lingotek_import_prefs')['import_type'];
31
- $plural_or_singular = '';
32
 
33
- /**
34
- *This tests to see if the import was successful. If it was it runs the subsequent
35
- *code.
36
- *@author Unknown
37
- */
38
- if ($table->get_import_status() == 'success'){
 
39
  $importedCount = 0;
40
 
41
- /**
42
- *Gets the import count based on if it is POST (Bulk import) or GET (indiviudal import)
43
- *@author Unknown
44
- */
45
- if (isset($_POST['post'])){ // used for bulk import
46
- $importedCount = count($_POST['post']);
 
 
47
  }
48
- else if (isset($_GET['post'])){ // used for single import
49
- $importedCount = count($_GET['post']);
 
50
  }
51
 
52
- /**
53
- *This is to show the correct syntax in the message saying the import was Successful
54
- *or not. It was always showing post even if it was imported as a page. Now it
55
- *will show page if imported as page and post if imported as a post.
56
- *
57
- *@author TJ Murphy
58
- *@uses Lingotek_Import_Table::$import_success_count
59
- *
60
- */
61
- if ($post_type == 'page'){
62
- $plural_or_singular = sprintf( _n( 'Successfully imported %1$s of %2$s page', 'Successfully imported %1$s of %2$s pages', $table->import_success_count, 'wp-lingotek' ), $table->import_success_count, $importedCount );
63
- }
64
- else {
65
- $plural_or_singular = sprintf( _n( 'Successfully imported %1$s of %2$s post', 'Successfully imported %1$s of %2$s posts', $table->import_success_count, 'wp-lingotek' ), $table->import_success_count, $importedCount );
66
- }
67
-
68
- add_settings_error($this->plugin_slug . '_import', '', $plural_or_singular, 'updated');
69
-
70
- /**
71
- *If not all the imports were successful this if statement adds a settings error
72
- *that lists the ids of the documents that did not import
73
- *
74
- *@author TJ Murphy
75
- *@uses Lingotek_Import_Table::$import_success_count
76
- *@uses Lingotek_Import_Table::$import_failure_count
77
- *@uses Lingotek_Import_Table::to_string_unsuccessful_imports()
78
- *
79
- */
80
- if ($table->import_success_count != $importedCount){
81
- $document_plurality = sprintf(_n( 'The following document did not import: %s', 'The following documents did not import: %s', $table->import_failure_count, 'wp-lingotek' ), $table->to_string_unsuccessful_imports());
82
- add_settings_error($this->plugin_slug . '_import', '',$document_plurality, 'error');
83
- }
84
  }
85
 
86
- else if ($table->get_import_status() == 'failure'){
87
- /**
88
- *This determines if any files were attempted to be imported. If Zero were even
89
- *attempted then it shows a message relating that. If >0 were attempted and 0
90
- *passed then it displays an error message saying all imports failed.
91
- *
92
- *@author TJ Murphy
93
- *@uses Lingotek_Import_Table::import_success_count
94
- *@uses Lingotek_Import_Table::import_failure_count
95
- *
96
- */
97
- if ($table->import_success_count == $importedCount && $table->import_failure_count == $importedCount && $importedCount == 0){
98
- add_settings_error(
99
- $this->plugin_slug . '_import',
100
- '',
101
- __('No files were selected to import. Please check the desired documents to import.','wp-lingotek'),
102
- 'error'
103
- );
104
- }
105
- else {
106
- $file_plurality = sprintf( _n( 'There was an error importing your file. We currently only support Wordpress, Drupal, HTML, and Text files.',
107
- 'There was an error importing your files. We currently only support Wordpress, Drupal, HTML, and Text files.',
108
- $table->import_failure_count,
109
- 'wp-lingotek' ),
110
- $table->import_failure_count );
111
- add_settings_error(
112
- $this->plugin_slug . '_import',
113
- '',
114
- $file_plurality,
115
- 'error'
116
- );
117
- }
118
 
119
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  settings_errors();
121
 
122
- $order = (!empty($_GET['order']) ) ? $_GET['order'] : 'asc';
123
- $orderby = (!empty($_GET['orderby']) ) ? '&orderby='.$_GET['orderby'].'&order='.$order : '';
124
 
125
- ?>
126
 
127
  <?php
128
- /**
129
- *This creates the starting form tag for the import page and sets the page and
130
- *action parameters.
131
- *@author Unknown
132
- */
133
- echo sprintf('<form id="lingotek-import" method="post" action="admin.php?page=lingotek-translation_import&action=bulk_import'.(string)$orderby.'"');
134
- /**
135
- *@see wp-admin/includes/class-wp-list-table.php/WP_List_Table::display()
136
- */
137
- $table->display(); ?>
138
- </form><?php
139
- }
 
 
 
1
  <?php
2
  /**
3
+ * I think this file is not used, and probably should be removed.
4
+ *
5
+ * @package lingotek-translation
6
+ */
7
+
8
+ // phpcs:disable
9
+ /**
10
+ * This file actually prepares the content to be viewed and calls the other files
11
+ * as needed so that everything appears as expected.
12
+ *
13
+ * @author Unknown
14
  */
15
 
16
 
17
+ require_once 'import-table.php';
18
 
19
+ $profile = Lingotek_Model::get_profile( 'string', $this->pllm->get_language( $this->pllm->options['default_lang'] ) );
20
 
21
  /**
22
  *Tests to see if the profile is disabled or not.
23
+ *
24
  *@author Unknown
25
  */
26
+ if ( 'disabled' == $profile['profile'] ) {
27
+ printf(
28
+ '<div class="error" style="border-left: 4px solid #ffba00;"><p>%s</p></div>',
29
+ sprintf(
30
+ __( 'The strings translation is disabled in %1$sContent Type Configuration%2$s.', 'wp-lingotek' ),
31
+ '<a href="' . admin_url( 'admin.php?page=wp-lingotek_settings&sm=content' ) . '">',
32
  '</a>'
33
  )
34
  );
35
+ } else {
36
+ $table = new Lingotek_Import_Table();
 
37
 
38
  $table->prepare_items();
39
+ //Gets the import type (post or page)
40
+ $post_type = get_option( 'lingotek_import_prefs' )['import_type'];
41
+ $plural_or_singular = '';
42
 
43
+ /**
44
+ *This tests to see if the import was successful. If it was it runs the subsequent
45
+ *code.
46
+ *
47
+ *@author Unknown
48
+ */
49
+ if ( $table->get_import_status() == 'success' ) {
50
  $importedCount = 0;
51
 
52
+ /**
53
+ *Gets the import count based on if it is POST (Bulk import) or GET (indiviudal import)
54
+ *
55
+ *@author Unknown
56
+ */
57
+ // Used for bulk import.
58
+ if ( isset( $_POST['post'] ) ) {
59
+ $importedCount = count( $_POST['post'] );
60
  }
61
+ // Used for single import.
62
+ elseif ( isset( $_GET['post'] ) ) {
63
+ $importedCount = count( $_GET['post'] );
64
  }
65
 
66
+ /**
67
+ *This is to show the correct syntax in the message saying the import was Successful
68
+ *or not. It was always showing post even if it was imported as a page. Now it
69
+ *will show page if imported as page and post if imported as a post.
70
+ *
71
+ *@author TJ Murphy
72
+ *@uses Lingotek_Import_Table::$import_success_count
73
+ */
74
+ if ( $post_type == 'page' ) {
75
+ $plural_or_singular = sprintf( _n( 'Successfully imported %1$s of %2$s page', 'Successfully imported %1$s of %2$s pages', $table->import_success_count, 'wp-lingotek' ), $table->import_success_count, $importedCount );
76
+ } else {
77
+ $plural_or_singular = sprintf( _n( 'Successfully imported %1$s of %2$s post', 'Successfully imported %1$s of %2$s posts', $table->import_success_count, 'wp-lingotek' ), $table->import_success_count, $importedCount );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  }
79
 
80
+ add_settings_error( $this->plugin_slug . '_import', '', $plural_or_singular, 'updated' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
 
82
+ /**
83
+ *If not all the imports were successful this if statement adds a settings error
84
+ *that lists the ids of the documents that did not import
85
+ *
86
+ *@author TJ Murphy
87
+ *@uses Lingotek_Import_Table::$import_success_count
88
+ *@uses Lingotek_Import_Table::$import_failure_count
89
+ *@uses Lingotek_Import_Table::to_string_unsuccessful_imports()
90
+ */
91
+ if ( $table->import_success_count != $importedCount ) {
92
+ $document_plurality = sprintf( _n( 'The following document did not import: %s', 'The following documents did not import: %s', $table->import_failure_count, 'wp-lingotek' ), $table->to_string_unsuccessful_imports() );
93
+ add_settings_error( $this->plugin_slug . '_import', '', $document_plurality, 'error' );
94
+ }
95
+ } elseif ( $table->get_import_status() == 'failure' ) {
96
+ /**
97
+ *This determines if any files were attempted to be imported. If Zero were even
98
+ *attempted then it shows a message relating that. If >0 were attempted and 0
99
+ *passed then it displays an error message saying all imports failed.
100
+ *
101
+ *@author TJ Murphy
102
+ *@uses Lingotek_Import_Table::import_success_count
103
+ *@uses Lingotek_Import_Table::import_failure_count
104
+ */
105
+ if ( $table->import_success_count == $importedCount && $table->import_failure_count == $importedCount && $importedCount == 0 ) {
106
+ add_settings_error(
107
+ $this->plugin_slug . '_import',
108
+ '',
109
+ __( 'No files were selected to import. Please check the desired documents to import.', 'wp-lingotek' ),
110
+ 'error'
111
+ );
112
+ } else {
113
+ $file_plurality = sprintf(
114
+ _n(
115
+ 'There was an error importing your file. We currently only support WordPress, Drupal, HTML, and Text files.',
116
+ 'There was an error importing your files. We currently only support WordPress, Drupal, HTML, and Text files.',
117
+ $table->import_failure_count,
118
+ 'wp-lingotek'
119
+ ),
120
+ $table->import_failure_count
121
+ );
122
+ add_settings_error(
123
+ $this->plugin_slug . '_import',
124
+ '',
125
+ $file_plurality,
126
+ 'error'
127
+ );
128
+ }//end if
129
+ }//end if
130
  settings_errors();
131
 
132
+ $order = ( ! empty( $_GET['order'] ) ) ? $_GET['order'] : 'asc';
133
+ $orderby = ( ! empty( $_GET['orderby'] ) ) ? '&orderby=' . $_GET['orderby'] . '&order=' . $order : '';
134
 
135
+ ?>
136
 
137
  <?php
138
+ /**
139
+ * This creates the starting form tag for the import page and sets the page and
140
+ * action parameters.
141
+ *
142
+ * @author Unknown
143
+ */
144
+ echo sprintf( '<form id="lingotek-import" method="post" action="admin.php?page=lingotek-translation_import&action=bulk_import' . (string) $orderby . '"' );
145
+ /**
146
+ *@see wp-admin/includes/class-wp-list-table.php/WP_List_Table::display()
147
+ */
148
+ $table->display();
149
+ ?>
150
+ </form>
151
+ <?php
152
+ }//end if
admin/import/view-settings.php CHANGED
@@ -1,30 +1,39 @@
1
  <?php
 
 
 
 
 
2
 
 
3
 
4
  /**
5
- *Sets all of the setting details so they can appropriately be presented.
6
- *@author Unknown
7
- *@var array
 
8
  */
9
  $setting_details = array(
10
- 'import_post_status' => array(
11
- 'type' => 'dropdown',
12
- 'label' => __('Import documents as', 'wp-lingotek'),
13
- 'description' => __('The post status for newly imported documents', 'wp-lingotek'),
14
- 'values' => array(
15
- 'draft' => __('Draft', 'wp-lingotek'),
16
- 'pending' => __('Pending Review', 'wp-lingotek'),
17
- 'publish' => __('Published', 'wp-lingotek'),
18
- 'private' => __('Privately Published', 'wp-lingotek'),
19
- )),
20
- 'import_type' => array(
21
- 'type' => 'dropdown',
22
- 'label' => __('Format', 'wp-lingotek'),
23
- 'description' => __('In which format would you like your imports to be?', 'wp-lingotek'),
24
- 'values' => array(
25
- 'page' => __('Page', 'wp-lingotek'),
26
- 'post' => __('Post', 'wp-lingotek'),
27
- )),
 
 
28
  );
29
 
30
 
@@ -32,60 +41,65 @@ $page_key = $this->plugin_slug . '_import&sm=settings';
32
 
33
  /**
34
  *Sets the options
35
- *@author Unknown
 
36
  */
37
- if (!empty($_POST)) {
38
- $options = array();
39
- foreach ($setting_details as $key => $setting) {
40
- if (isset($_POST[$key])) {
41
- $options[$key] = $_POST[$key];
42
- }
43
- else {
44
- $options[$key] = null;
45
- }
46
- }
47
 
48
 
49
- update_option('lingotek_import_prefs', $options, false);
50
 
51
- add_settings_error('lingotek_prefs', 'prefs', __('Your preferences were successfully updated.', 'wp-lingotek'), 'updated');
52
- settings_errors();
53
  }
54
- $selected_options = get_option('lingotek_import_prefs');
55
  ?>
56
 
57
- <h3><?php _e('Settings', 'wp-lingotek'); ?></h3>
58
 
59
  <form id="lingotek-settings" method="post" action="admin.php?page=<?php echo $page_key; ?>" class="validate">
60
- <?php wp_nonce_field($page_key, '_wpnonce_' . $page_key); ?>
61
 
62
- <table class="form-table"><?php foreach ($setting_details as $key => $setting) { ?>
63
 
64
- <tr>
65
- <th scope="row"><label for="<?php echo $key; ?>"><?php echo $setting['label'] ?></label></th>
66
- <td>
67
- <?php if ($setting['type'] == 'dropdown') { ?>
68
- <select name="<?php echo $key ?>" id="<?php echo $key ?>">
69
- <?php
70
- foreach ($setting['values'] as $id => $title) {
71
- echo "\n\t" . '<option value="' . esc_attr($id) . '" ' . selected($selected_options[$key], $id) . '>' . $title . '</option>';
72
- }
73
- ?>
74
- </select>
75
- <?php } else if ($setting['type'] == 'checkboxes') {
76
- echo '<ul class="pref-statuses">';
77
- foreach ($setting['values'] as $id => $title) {
78
- $cb_name = $key.'['.esc_attr($id) . ']';
79
- $checked = checked('1', (isset($selected_options[$key][$id]) && $selected_options[$key][$id]), false);
80
- echo '<li><input type="checkbox" id="'.$cb_name.'" name="'.$cb_name.'" value="1" ' . $checked. '><label for="'.$cb_name.'">' . $title . '</label></li>';
81
- }
82
- echo '</ul>';
83
- } ?>
84
- <p class="description">
85
- <?php echo $setting['description']; ?>
86
- </p>
87
- </tr><?php } ?>
 
 
 
 
 
88
  </table>
89
 
90
- <?php submit_button(__('Save Changes', 'wp-lingotek'), 'primary', 'submit', false); ?>
91
  </form>
1
  <?php
2
+ /**
3
+ * I think this file is not used, and probably should be removed.
4
+ *
5
+ * @package lingotek-translation
6
+ */
7
 
8
+ // phpcs:disable
9
 
10
  /**
11
+ * Sets all of the setting details so they can appropriately be presented.
12
+ *
13
+ * @author Unknown
14
+ * @var array
15
  */
16
  $setting_details = array(
17
+ 'import_post_status' => array(
18
+ 'type' => 'dropdown',
19
+ 'label' => __( 'Import documents as', 'wp-lingotek' ),
20
+ 'description' => __( 'The post status for newly imported documents', 'wp-lingotek' ),
21
+ 'values' => array(
22
+ 'draft' => __( 'Draft', 'wp-lingotek' ),
23
+ 'pending' => __( 'Pending Review', 'wp-lingotek' ),
24
+ 'publish' => __( 'Published', 'wp-lingotek' ),
25
+ 'private' => __( 'Privately Published', 'wp-lingotek' ),
26
+ ),
27
+ ),
28
+ 'import_type' => array(
29
+ 'type' => 'dropdown',
30
+ 'label' => __( 'Format', 'wp-lingotek' ),
31
+ 'description' => __( 'In which format would you like your imports to be?', 'wp-lingotek' ),
32
+ 'values' => array(
33
+ 'page' => __( 'Page', 'wp-lingotek' ),
34
+ 'post' => __( 'Post', 'wp-lingotek' ),
35
+ ),
36
+ ),
37
  );
38
 
39
 
41
 
42
  /**
43
  *Sets the options
44
+ *
45
+ *@author Unknown
46
  */
47
+ if ( ! empty( $_POST ) ) {
48
+ $options = array();
49
+ foreach ( $setting_details as $key => $setting ) {
50
+ if ( isset( $_POST[ $key ] ) ) {
51
+ $options[ $key ] = $_POST[ $key ];
52
+ } else {
53
+ $options[ $key ] = null;
54
+ }
55
+ }
 
56
 
57
 
58
+ update_option( 'lingotek_import_prefs', $options, false );
59
 
60
+ add_settings_error( 'lingotek_prefs', 'prefs', __( 'Your preferences were successfully updated.', 'wp-lingotek' ), 'updated' );
61
+ settings_errors();
62
  }
63
+ $selected_options = get_option( 'lingotek_import_prefs' );
64
  ?>
65
 
66
+ <h3><?php _e( 'Settings', 'wp-lingotek' ); ?></h3>
67
 
68
  <form id="lingotek-settings" method="post" action="admin.php?page=<?php echo $page_key; ?>" class="validate">
69
+ <?php wp_nonce_field( $page_key, '_wpnonce_' . $page_key ); ?>
70
 
71
+ <table class="form-table"><?php foreach ( $setting_details as $key => $setting ) { ?>
72
 
73
+ <tr>
74
+ <th scope="row"><label for="<?php echo $key; ?>"><?php echo $setting['label']; ?></label></th>
75
+ <td>
76
+ <?php if ( $setting['type'] == 'dropdown' ) { ?>
77
+ <select name="<?php echo $key; ?>" id="<?php echo $key; ?>">
78
+ <?php
79
+ foreach ( $setting['values'] as $id => $title ) {
80
+ echo "\n\t" . '<option value="' . esc_attr( $id ) . '" ' . selected( $selected_options[ $key ], $id ) . '>' . $title . '</option>';
81
+ }
82
+ ?>
83
+ </select>
84
+ <?php
85
+ } elseif ( $setting['type'] == 'checkboxes' ) {
86
+ echo '<ul class="pref-statuses">';
87
+ foreach ( $setting['values'] as $id => $title ) {
88
+ $cb_name = $key . '[' . esc_attr( $id ) . ']';
89
+ $checked = checked( '1', ( isset( $selected_options[ $key ][ $id ] ) && $selected_options[ $key ][ $id ] ), false );
90
+ echo '<li><input type="checkbox" id="' . $cb_name . '" name="' . $cb_name . '" value="1" ' . $checked . '><label for="' . $cb_name . '">' . $title . '</label></li>';
91
+ }
92
+ echo '</ul>';
93
+ }
94
+ ?>
95
+ <p class="description">
96
+ <?php echo $setting['description']; ?>
97
+ </p>
98
+ </tr>
99
+ <?php
100
+ }//end foreach
101
+ ?>
102
  </table>
103
 
104
+ <?php submit_button( __( 'Save Changes', 'wp-lingotek' ), 'primary', 'submit', false ); ?>
105
  </form>
admin/manage/view-content.php CHANGED
@@ -2,99 +2,97 @@
2
 
3
  global $polylang;
4
 
5
- foreach ($polylang->model->get_translated_post_types() as $post_type) {
6
- $post_type_object = get_post_type_object($post_type);
7
- $data[$post_type] = array(
8
- 'type' => $post_type,
9
- 'name' => $post_type_object->labels->name,
10
- 'fields' => array(
11
- 'label' => Lingotek_Group_Post::get_content_type_fields($post_type)
12
- )
13
  );
14
  }
15
 
16
- foreach ($polylang->model->get_translated_taxonomies() as $tax) {
17
- $taxonomy = get_taxonomy($tax);
18
- $data[$tax] = array(
19
- 'type' => $tax,
20
- 'name' => $taxonomy->labels->name,
21
- 'fields' => array(
22
- 'label' => Lingotek_Group_Term::get_content_type_fields($tax)
23
- )
24
  );
25
  }
26
 
27
  $data['string'] = array(
28
- 'type' => 'string',
29
- 'name' => __('Strings', 'lingotek-translation'),
30
  );
31
 
32
- if (empty($_POST)) {
33
- $content_types = get_option('lingotek_content_type');
34
- }
35
-
36
- else {
37
- check_admin_referer('lingotek-content-types', '_wpnonce_lingotek-content-types');
38
-
39
- $profiles = array_keys(get_option('lingotek_profiles'));
40
- $content_types = get_option('lingotek_content_type');
41
- foreach ($data as $key => $item) {
42
- if (isset($data[$key]['name']) && isset($_POST[$key])) {
43
- if (in_array($_POST[$key]['profile'], $profiles))
44
- $content_types[$key]['profile'] = $_POST[$key]['profile'];
45
 
46
- foreach ($polylang->model->get_languages_list() as $language) {
47
- if (isset($_POST[$key]['sources'][$language->slug]) && in_array($_POST[$key]['sources'][$language->slug], $profiles))
48
- $content_types[$key]['sources'][$language->slug] = $_POST[$key]['sources'][$language->slug];
 
 
 
49
  }
50
 
 
 
 
 
 
51
  }
52
- if (isset($data[$key]['fields'])) {
53
- foreach ($data[$key]['fields']['label'] as $key1 => $arr) {
54
- if (is_array($arr)) {
55
- foreach (array_keys($arr) as $key2) {
56
- if(!isset($_POST[$key]['fields'][$key1][$key2])) {
57
- $content_types[$key]['fields'][$key1][$key2] = 1;
58
- }
59
- else {
60
- $content_types[$key]['fields'][$key1][$key2] = 0;
61
- }
62
  }
63
- }
64
- elseif (isset($_POST[$key]) && empty($_POST[$key]['fields'][$key1])) {
65
- $content_types[$key]['fields'][$key1] = 1;
66
- }
67
- elseif (!empty($_POST[$key]['fields'][$key1])) {
68
- $content_types[$key]['fields'][$key1] = 0;
69
  }
70
  }
71
  }
72
- }
73
 
74
- update_option('lingotek_content_type', $content_types, false);
75
- add_settings_error('lingotek_content_types', 'default', __('Your content types were sucessfully saved.', 'lingotek-translation'), 'updated');
76
  settings_errors();
77
- }
78
 
79
- foreach ($data as $key => $item) {
80
  // default profile is manual except for post
81
- $data[$key]['profile'] = empty($content_types[$key]['profile']) ? ('post' === $key || 'page' === $key ? 'manual' : 'disabled') : $content_types[$key]['profile'];
82
- $data[$key]['sources'] = empty($content_types[$key]['sources']) ? array() : $content_types[$key]['sources'];
83
- if (!empty($content_types[$key]['fields']))
84
- $data[$key]['fields']['value'] = $content_types[$key]['fields'];
 
85
  }
86
 
87
  ?>
88
- <h3><?php _e('Content Type Configuration', 'lingotek-translation'); ?></h3>
89
- <p class="description"><?php _e('Content types can be configured to use any translation profile. Additionally, translation profiles can be set based on the language the content was authored in.', 'lingotek-translation'); ?></p>
90
 
91
- <form id="lingotek-content-types" method="post" action="admin.php?page=lingotek-translation_manage&amp;sm=content" class="validate"><?php
92
- wp_nonce_field('lingotek-content-types', '_wpnonce_lingotek-content-types');
 
93
 
94
- $table = new Lingotek_Content_Table($content_types);
95
- $table->prepare_items($data);
96
  $table->display();
97
 
98
- submit_button(__('Save Changes', 'lingotek-translation'), 'primary', 'submit', false);
99
  ?>
100
  </form>
2
 
3
  global $polylang;
4
 
5
+ foreach ( $polylang->model->get_translated_post_types() as $post_type ) {
6
+ $post_type_object = get_post_type_object( $post_type );
7
+ $data[ $post_type ] = array(
8
+ 'type' => $post_type,
9
+ 'name' => $post_type_object->labels->name,
10
+ 'fields' => array(
11
+ 'label' => Lingotek_Group_Post::get_content_type_fields( $post_type ),
12
+ ),
13
  );
14
  }
15
 
16
+ foreach ( $polylang->model->get_translated_taxonomies() as $tax ) {
17
+ $taxonomy = get_taxonomy( $tax );
18
+ $data[ $tax ] = array(
19
+ 'type' => $tax,
20
+ 'name' => $taxonomy->labels->name,
21
+ 'fields' => array(
22
+ 'label' => Lingotek_Group_Term::get_content_type_fields( $tax ),
23
+ ),
24
  );
25
  }
26
 
27
  $data['string'] = array(
28
+ 'type' => 'string',
29
+ 'name' => __( 'Strings', 'lingotek-translation' ),
30
  );
31
 
32
+ if ( empty( $_POST ) ) {
33
+ $content_types = get_option( 'lingotek_content_type' );
34
+ } else {
35
+ check_admin_referer( 'lingotek-content-types', '_wpnonce_lingotek-content-types' );
 
 
 
 
 
 
 
 
 
36
 
37
+ $profiles = array_keys( get_option( 'lingotek_profiles' ) );
38
+ $content_types = get_option( 'lingotek_content_type' );
39
+ foreach ( $data as $key => $item ) {
40
+ if ( isset( $data[ $key ]['name'] ) && isset( $_POST[ $key ] ) ) {
41
+ if ( in_array( $_POST[ $key ]['profile'], $profiles ) ) {
42
+ $content_types[ $key ]['profile'] = $_POST[ $key ]['profile'];
43
  }
44
 
45
+ foreach ( $polylang->model->get_languages_list() as $language ) {
46
+ if ( isset( $_POST[ $key ]['sources'][ $language->slug ] ) && in_array( $_POST[ $key ]['sources'][ $language->slug ], $profiles ) ) {
47
+ $content_types[ $key ]['sources'][ $language->slug ] = $_POST[ $key ]['sources'][ $language->slug ];
48
+ }
49
+ }
50
  }
51
+ if ( isset( $data[ $key ]['fields'] ) ) {
52
+ foreach ( $data[ $key ]['fields']['label'] as $key1 => $arr ) {
53
+ if ( is_array( $arr ) ) {
54
+ foreach ( array_keys( $arr ) as $key2 ) {
55
+ if ( ! isset( $_POST[ $key ]['fields'][ $key1 ][ $key2 ] ) ) {
56
+ $content_types[ $key ]['fields'][ $key1 ][ $key2 ] = 1;
57
+ } else {
58
+ $content_types[ $key ]['fields'][ $key1 ][ $key2 ] = 0;
59
+ }
 
60
  }
61
+ } elseif ( isset( $_POST[ $key ] ) && empty( $_POST[ $key ]['fields'][ $key1 ] ) ) {
62
+ $content_types[ $key ]['fields'][ $key1 ] = 1;
63
+ } elseif ( ! empty( $_POST[ $key ]['fields'][ $key1 ] ) ) {
64
+ $content_types[ $key ]['fields'][ $key1 ] = 0;
 
 
65
  }
66
  }
67
  }
68
+ }//end foreach
69
 
70
+ update_option( 'lingotek_content_type', $content_types, false );
71
+ add_settings_error( 'lingotek_content_types', 'default', __( 'Your content types were sucessfully saved.', 'lingotek-translation' ), 'updated' );
72
  settings_errors();
73
+ }//end if
74
 
75
+ foreach ( $data as $key => $item ) {
76
  // default profile is manual except for post
77
+ $data[ $key ]['profile'] = empty( $content_types[ $key ]['profile'] ) ? ( 'post' === $key || 'page' === $key ? 'manual' : 'disabled' ) : $content_types[ $key ]['profile'];
78
+ $data[ $key ]['sources'] = empty( $content_types[ $key ]['sources'] ) ? array() : $content_types[ $key ]['sources'];
79
+ if ( ! empty( $content_types[ $key ]['fields'] ) ) {
80
+ $data[ $key ]['fields']['value'] = $content_types[ $key ]['fields'];
81
+ }
82
  }
83
 
84
  ?>
85
+ <h3><?php _e( 'Content Type Configuration', 'lingotek-translation' ); ?></h3>
86
+ <p class="description"><?php _e( 'Content types can be configured to use any translation profile. Additionally, translation profiles can be set based on the language the content was authored in.', 'lingotek-translation' ); ?></p>
87
 
88
+ <form id="lingotek-content-types" method="post" action="admin.php?page=lingotek-translation_manage&amp;sm=content" class="validate">
89
+ <?php
90
+ wp_nonce_field( 'lingotek-content-types', '_wpnonce_lingotek-content-types' );
91
 
92
+ $table = new Lingotek_Content_Table( $content_types );
93
+ $table->prepare_items( $data );
94
  $table->display();
95
 
96
+ submit_button( __( 'Save Changes', 'lingotek-translation' ), 'primary', 'submit', false );
97
  ?>
98
  </form>
admin/manage/view-custom-fields.php CHANGED
@@ -2,102 +2,112 @@
2
 
3
  global $polylang;
4
 
5
- $items = array();
6
- $default_setting = array('ignore' => 'Ignore', 'translate' => 'Translate', 'copy' => 'Copy');
 
 
 
 
7
  $default_custom_fields = '';
8
 
9
- if (!empty($_POST)) {
10
- check_admin_referer('lingotek-custom-fields', '_wpnonce_lingotek-custom-fields');
11
-
12
- if (!empty($_POST['submit'])) {
13
- $arr = empty($_POST['settings']) ? array() : $_POST['settings'];
14
-
15
- if (isset($_POST['default_custom_fields'])) {
16
- $default_custom_fields = $_POST['default_custom_fields'];
17
- update_option('lingotek_default_custom_fields', $default_custom_fields, false);
18
- }
19
- update_option('lingotek_custom_fields', $arr, false);
20
- $post_types = get_post_types();
21
- foreach ($post_types as $post_type) {
22
- $cache_key = 'content_type_fields_' . $post_type;
23
- wp_cache_delete($cache_key, 'lingotek');
24
- }
25
- add_settings_error('lingotek_custom_fields_save', 'custom_fields', __('Your <i>Custom Fields</i> were sucessfully saved.', 'lingotek-translation'), 'updated');
26
- }
27
-
28
- if (!empty($_POST['submit2'])) { //Bulk Change
29
- $arr = empty($_POST['settings']) ? array() : $_POST['settings'];
30
-
31
- if (isset($_POST['custom_fields'])) {
32
- $custom_fields = $_POST['custom_fields'];
33
- }
34
- foreach ($_POST as $post => $value) {
35
- if ($value == 'value1') {
36
- $temp = explode('_', $post);
37
- $temp = implode(' ', $temp);
38
-
39
- foreach ($arr as $item => $val) {
40
- $temp2 = explode('_', $item);
41
- $temp2 = implode(' ', $temp2);
42
- if ($temp == $temp2) {
43
- $arr[$item] = $custom_fields;
44
- }
45
- }
46
- }
47
- }
48
- update_option('lingotek_custom_fields', $arr, false);
49
- }
50
-
51
- if (!empty($_POST['refresh'])) {
52
- Lingotek_Group_Post::get_updated_meta_values();
53
- add_settings_error('lingotek_custom_fields_refresh', 'custom_fields', __('Your <i>Custom Fields</i> were sucessfully identified.', 'lingotek-translation'), 'updated');
54
- }
55
- settings_errors();
56
- }
57
-
58
- $items = Lingotek_Group_Post::get_cached_meta_values();
59
- $default_custom_fields = get_option('lingotek_default_custom_fields');
 
60
 
61
  ?>
62
 
63
- <h3><?php _e('Custom Field Configuration', 'lingotek-translation'); ?></h3>
64
  <p class="description">
65
- <?php _e('Custom Fields can be translated, copied, or ignored. Click "Refresh Custom Fields" to identify and enable your custom fields.', 'lingotek-translation'); ?>
66
  </p>
67
 
68
  <form id="lingotek-custom-fields" method="post" action="admin.php?page=lingotek-translation_manage&amp;sm=custom-fields"
69
- class="validate">
70
- <?php
71
- wp_nonce_field('lingotek-custom-fields', '_wpnonce_lingotek-custom-fields'); ?>
72
-
73
- <br>
74
- <label for="default_custom_fields">Default configuration for new Custom Fields</label>
75
- <select name="default_custom_fields"><?php
76
- foreach ($default_setting as $key => $title) {
77
- $selected = $key == $default_custom_fields ? 'selected="selected"' : '';
78
- echo "\n\t<option value='" . $key . "' $selected>" . $title . '</option>';
79
- } ?>
80
- </select>
81
- </br>
82
- <div id="d1" style="display: none;">
83
- <select name="custom_fields"><?php
84
- foreach ($default_setting as $key => $title) {
85
- $selected = $key == $default_custom_fields ? 'selected="selected"' : '';
86
- echo "\n\t<option value='" . $key . "' $selected>" . $title . '</option>';
87
- } ?>
88
- </select>
89
- <?php
90
- submit_button(__('Bulk Change', 'lingotek-translation'), 'primary', 'submit2', false);
91
- echo "</div>";
92
- $table = new Lingotek_Custom_Fields_Table();
93
- $table->prepare_items($items);
94
- $table->display();
95
- ?>
96
-
97
- <p>
98
- <?php submit_button(__('Save Changes', 'lingotek-translation'), 'primary', 'submit', false); ?>
99
- <?php submit_button(__('Refresh Custom Fields', 'lingotek-translation'), 'secondary', 'refresh', false); ?>
100
- </p>
 
 
 
 
 
101
  </form>
102
 
103
 
@@ -131,4 +141,4 @@ function toggle(source) {
131
  checkboxes[i].checked = source.checked;
132
  }
133
 
134
- </script>" ?>
2
 
3
  global $polylang;
4
 
5
+ $items = array();
6
+ $default_setting = array(
7
+ 'ignore' => 'Ignore',
8
+ 'translate' => 'Translate',
9
+ 'copy' => 'Copy',
10
+ );
11
  $default_custom_fields = '';
12
 
13
+ if ( ! empty( $_POST ) ) {
14
+ check_admin_referer( 'lingotek-custom-fields', '_wpnonce_lingotek-custom-fields' );
15
+
16
+ if ( ! empty( $_POST['submit'] ) ) {
17
+ $arr = empty( $_POST['settings'] ) ? array() : $_POST['settings'];
18
+
19
+ if ( isset( $_POST['default_custom_fields'] ) ) {
20
+ $default_custom_fields = $_POST['default_custom_fields'];
21
+ update_option( 'lingotek_default_custom_fields', $default_custom_fields, false );
22
+ }
23
+ update_option( 'lingotek_custom_fields', $arr, false );
24
+ $post_types = get_post_types();
25
+ foreach ( $post_types as $post_type ) {
26
+ $cache_key = 'content_type_fields_' . $post_type;
27
+ wp_cache_delete( $cache_key, 'lingotek' );
28
+ }
29
+ add_settings_error( 'lingotek_custom_fields_save', 'custom_fields', __( 'Your <i>Custom Fields</i> were sucessfully saved.', 'lingotek-translation' ), 'updated' );
30
+ }
31
+
32
+ // Bulk Change.
33
+ if ( ! empty( $_POST['submit2'] ) ) {
34
+ $arr = empty( $_POST['settings'] ) ? array() : $_POST['settings'];
35
+
36
+ if ( isset( $_POST['custom_fields'] ) ) {
37
+ $custom_fields = $_POST['custom_fields'];
38
+ }
39
+ foreach ( $_POST as $post => $value ) {
40
+ if ( $value == 'value1' ) {
41
+ $temp = explode( '_', $post );
42
+ $temp = implode( ' ', $temp );
43
+
44
+ foreach ( $arr as $item => $val ) {
45
+ $temp2 = explode( '_', $item );
46
+ $temp2 = implode( ' ', $temp2 );
47
+ if ( $temp == $temp2 ) {
48
+ $arr[ $item ] = $custom_fields;
49
+ }
50
+ }
51
+ }
52
+ }
53
+ update_option( 'lingotek_custom_fields', $arr, false );
54
+ }//end if
55
+
56
+ if ( ! empty( $_POST['refresh'] ) ) {
57
+ Lingotek_Group_Post::get_updated_meta_values();
58
+ add_settings_error( 'lingotek_custom_fields_refresh', 'custom_fields', __( 'Your <i>Custom Fields</i> were sucessfully identified.', 'lingotek-translation' ), 'updated' );
59
+ }
60
+ settings_errors();
61
+ }//end if
62
+
63
+ $items = Lingotek_Group_Post::get_cached_meta_values();
64
+ $default_custom_fields = get_option( 'lingotek_default_custom_fields' );
65
 
66
  ?>
67
 
68
+ <h3><?php _e( 'Custom Field Configuration', 'lingotek-translation' ); ?></h3>
69
  <p class="description">
70
+ <?php _e( 'Custom Fields can be translated, copied, or ignored. Click "Refresh Custom Fields" to identify and enable your custom fields.', 'lingotek-translation' ); ?>
71
  </p>
72
 
73
  <form id="lingotek-custom-fields" method="post" action="admin.php?page=lingotek-translation_manage&amp;sm=custom-fields"
74
+ class="validate">
75
+ <?php
76
+ wp_nonce_field( 'lingotek-custom-fields', '_wpnonce_lingotek-custom-fields' );
77
+ ?>
78
+
79
+ <br>
80
+ <label for="default_custom_fields">Default configuration for new Custom Fields</label>
81
+ <select name="default_custom_fields">
82
+ <?php
83
+ foreach ( $default_setting as $key => $title ) {
84
+ $selected = $key == $default_custom_fields ? 'selected="selected"' : '';
85
+ echo "\n\t<option value='" . $key . "' $selected>" . $title . '</option>';
86
+ }
87
+ ?>
88
+ </select>
89
+ </br>
90
+ <div id="d1" style="display: none;">
91
+ <select name="custom_fields">
92
+ <?php
93
+ foreach ( $default_setting as $key => $title ) {
94
+ $selected = $key == $default_custom_fields ? 'selected="selected"' : '';
95
+ echo "\n\t<option value='" . $key . "' $selected>" . $title . '</option>';
96
+ }
97
+ ?>
98
+ </select>
99
+ <?php
100
+ submit_button( __( 'Bulk Change', 'lingotek-translation' ), 'primary', 'submit2', false );
101
+ echo '</div>';
102
+ $table = new Lingotek_Custom_Fields_Table();
103
+ $table->prepare_items( $items );
104
+ $table->display();
105
+ ?>
106
+
107
+ <p>
108
+ <?php submit_button( __( 'Save Changes', 'lingotek-translation' ), 'primary', 'submit', false ); ?>
109
+ <?php submit_button( __( 'Refresh Custom Fields', 'lingotek-translation' ), 'secondary', 'refresh', false ); ?>
110
+ </p>
111
  </form>
112
 
113
 
141
  checkboxes[i].checked = source.checked;
142
  }
143
 
144
+ </script>" ?>
admin/manage/view-edit-profile.php CHANGED
@@ -2,136 +2,164 @@
2
 
3
  $settings = $this->get_profiles_settings();
4
 
5
- $defaults = get_option('lingotek_defaults');
6
- $default = __('Use global default (%s)', 'lingotek-translation');
7
- foreach ($settings as $key => $setting) {
8
- if (isset($defaults[$key]) && array_key_exists($defaults[$key], $settings[$key]['options'])) {
9
- $default_arr = array('default' => sprintf($default, $settings[$key]['options'][$defaults[$key]]));
10
- $settings[$key]['options'] = array_merge($default_arr, $settings[$key]['options']);
 
11
  }
12
  }
13
 
14
  $target_settings = array(
15
- 'default' => __('Use default settings', 'lingotek-translation'),
16
- 'custom' => __('Use custom settings', 'lingotek-translation'),
17
- 'copy' => __('Copy source language', 'lingotek-translation'),
18
- 'disabled' => __('Disabled', 'lingotek-translation')
19
  );
20
 
21
- $profiles = $this->get_profiles_usage(get_option('lingotek_profiles'));
22
 
23
- $profile = isset($_GET['profile']) && array_key_exists($_GET['profile'], $profiles) ? $profiles[$_GET['profile']] : array();
24
- $disabled = isset($profile['profile']) && in_array($profile['profile'], array('automatic', 'manual')) ? 'disabled="disabled"' : '';
25
  // Code to determine which filter scenario will be displayed. (Not configured, defaults, custom filters)
26
- $primary_filter_id = array_search('okf_json@with-html-subfilter.fprm', $settings['primary_filter_id']['options']);
27
- $secondary_filter_id = array_search('okf_html@wordpress.fprm', $settings['secondary_filter_id']['options']);
28
- $default_filters = array($primary_filter_id => 'okf_json@with-html-subfilter.fprm', $secondary_filter_id => 'okf_html@wordpress.fprm');
29
- $default_filters_exist = FALSE;
30
- $extra_filters_exist = FALSE;
31
- $no_filters_exist = FALSE;
 
 
 
32
 
33
- if (array_key_exists('default', array_diff_assoc($settings['primary_filter_id']['options'], $default_filters)) && count(array_diff_assoc($settings['primary_filter_id']['options'], $default_filters)) == 1) {
34
- unset($settings['primary_filter_id']['options']['default']);
35
- }
36
- if ($settings['primary_filter_id']['options'] == $default_filters) {
37
- $default_filters_exist = TRUE;
38
- $defaults['primary_filter_id'] = $primary_filter_id;
39
- $defaults['secondary_filter_id'] = $secondary_filter_id;
40
- update_option('lingotek_defaults', $defaults, false);
41
  }
42
- else {
43
- $num = count(array_diff_assoc($settings['primary_filter_id']['options'], $default_filters));
44
- if ($num > 0) {
45
- $extra_filters_exist = TRUE;
46
- }
47
- else {
48
- $defaults['primary_filter_id'] = '';
49
- $defaults['secondary_filter_id'] = '';
50
- update_option('lingotek_defaults', $defaults, false);
51
- $no_filters_exist = TRUE;
52
- }
 
 
 
 
53
  }
54
- unset($settings['primary_filter_id']['options'][$secondary_filter_id]);
55
- unset($settings['secondary_filter_id']['options'][$primary_filter_id]);
56
  ?>
57
 
58
  <form id="lingotek-edit-profile" method="post" action="admin.php?page=lingotek-translation_manage&sm=profiles" class="validate">
59
- <?php wp_nonce_field('lingotek-edit-profile', '_wpnonce_lingotek-edit-profile');?>
60
- <input name="profile" type="hidden" value="<?php echo empty($profile['profile']) ? '' : esc_attr($profile['profile']); ?>">
61
 
62
  <table class="form-table">
63
  <tr>
64
- <th scope="row"><?php printf('<label for="%s">%s</label>', 'name' , __('Profile name', 'lingotek-translation')); ?></th>
65
- <td><?php
66
- if (!empty($profile)) {
67
- $profile_name = $disabled ? __($profile['name'],'lingotek-translation') : $profile['name']; // localize canned profile names
 
 
68
  }
69
- printf('<input name="name" id="name" type="text" value="%s" %s>',
70
- empty($profile['name']) ? '' : esc_attr($profile_name),
71
- $disabled
72
- ); ?>
 
 
73
  </td>
74
  </tr>
75
  </table>
76
 
77
- <h3><?php _e('Default settings', 'lingotek-translation'); ?></h3>
78
 
79
- <table class="form-table"><?php
80
- foreach ($settings as $key => $setting) { ?>
81
- <tr id="<?php echo $key.'_row'?>">
82
- <th scope="row"><?php printf('<label for="%s">%s</label>', $key , $setting['label']); ?></th>
83
- <td><?php
84
- printf('<select name="%1$s" id="%1$s" %2$s>', $key, in_array($key, array('upload', 'download')) ? $disabled : '');
85
- foreach ($setting['options'] as $id => $title) {
86
- $selected = isset($profile[$key]) && $profile[$key] == $id ? 'selected="selected"' : '';
87
- echo "\n\t<option value='" . esc_attr($id) . "' $selected>" . esc_html($title) . '</option>';
88
- } ?>
89
- </select><?php
 
 
 
 
 
90
 
91
- if ('project_id' == $key) { ?>
 
92
  <input type="checkbox" name="update_callback" id="update_callback"/>
93
- <label for="update_callback"><?php _e('Update the callback url for this project.', 'lingotek-translation') ?></label><?php
 
94
  }
95
 
96
- if (isset($setting['description']))
97
- printf('<p class="description">%s</p>', $setting['description']);?>
 
 
98
 
99
  <!-- Code to handle displaying of Primary and Secondary Filters -->
100
- <?php if($no_filters_exist) { ?>
101
- <script> document.getElementById("primary_filter_id_row").style.display = "none";</script>
102
- <script> document.getElementById("secondary_filter_id_row").style.display = "none";</script> <?php
103
- if ('primary_filter_id' == $key) { ?>
104
- <tr id="filters_row"><th><?php _e('Filters', 'lingotek-translation') ?></th><td><i><?php _e('Not configured', 'lingotek-translation') ?></i></td></tr>
105
- <?php }
106
- }
107
- if ($default_filters_exist) { ?>
108
- <script> document.getElementById("primary_filter_id_row").style.display = "none";</script>
109
- <script> document.getElementById("secondary_filter_id_row").style.display = "none";</script>
110
- <?php } ?>
111
- <!-- End of filter code -->
 
 
 
 
112
  </td>
113
- </tr><?php
114
- } ?>
 
 
 
115
  </table>
116
 
117
- <h3><?php _e('Target languages', 'lingotek-translation'); ?></h3>
118
 
119
- <table class="form-table target-table"><?php
120
- unset($settings['upload']); // we don't want this for target languages
121
- unset($settings['project_id']); // FIXME disable the possibility to have a different project per target language for now
 
 
 
122
  // Filters not needed for target languages
123
- unset($settings['primary_filter_id']);
124
- unset($settings['secondary_filter_id']);
125
- ?>
126
  <?php
127
  $custom_profile_chosen = false;
128
- foreach ($this->pllm->get_languages_list() as $language) { ?>
 
129
  <tr>
130
- <th scope="row"><?php printf('<label for="%s">%s (%s)</label>', esc_attr($language->slug) , esc_html($language->name), esc_attr($language->locale)); ?><?php
 
131
 
132
- printf('<a id="%1$s_details_link" %2$s class="dashicons dashicons-arrow-right" onclick="%3$s">%4$s</a>',
133
- esc_attr($language->slug),
134
- isset($profile['targets'][$language->slug]) && 'custom' == $profile['targets'][$language->slug] ? '' : 'style="display:none;"',
 
135
  "
136
  d = document.getElementById('{$language->slug}_details');
137
  if ('none' == d.style.display) {
@@ -142,12 +170,15 @@ unset($settings['secondary_filter_id']['options'][$primary_filter_id]);
142
  d.style.display = 'none';
143
  this.className = 'dashicons dashicons-arrow-right';
144
  }",
145
- '' //__('Show', 'lingotek-translation')
146
-
147
- ); ?></th>
148
- <td class="target-table-td"><?php
149
- printf('<select name="targets[%1$s]" id="targets[%1$s]" onchange="%2$s">',
150
- esc_attr($language->slug),
 
 
 
151
  "
152
  dl = document.getElementById('{$language->slug}_details_link');
153
  d = document.getElementById('{$language->slug}_details');
@@ -183,65 +214,74 @@ unset($settings['secondary_filter_id']['options'][$primary_filter_id]);
183
  }
184
  "
185
  );
186
- foreach ($target_settings as $id => $title) {
187
- $selected = (empty($profile['targets'][$language->slug]) && 'default' == $id) || (isset($profile['targets'][$language->slug]) && $profile['targets'][$language->slug] == $id) ? 'selected="selected"' : '';
188
- echo "\n\t<option value='" . $id . "' $selected>" . $title . '</option>';
189
- } ?>
 
190
  </select>
191
 
192
  </td>
193
  <?php
194
- if (isset($profile['targets'][$language->slug]) && 'custom' === $profile['targets'][$language->slug]) {
195
- $custom_profile_chosen = true;
196
- }
197
- $checked = empty($profile['target_locales'][$language->slug]) ? '' : 'checked="checked"';
198
  $display = '';
199
- if (isset($profile['targets'][$language->slug]) && ('disabled' === $profile['targets'][$language->slug] || 'copy' === $profile['targets'][$language->slug])) {
200
- $display = 'style="display:none;"';
201
- }
202
  ?>
203
  <td><input
204
  <?php echo $checked; ?>
205
  <?php echo $display; ?>
206
  type="checkbox"
207
  class="ltk-target-checkbox"
208
- value="<?php echo esc_attr($language->lingotek_locale); ?>"
209
- id="target_locales[<?php echo esc_attr($language->slug); ?>]"
210
- name="target_locales[<?php echo esc_attr($language->slug); ?>]"
211
  >
212
  <label
213
  <?php echo $display; ?>
214
- for="target_locales[<?php echo esc_attr($language->slug); ?>]"
215
- id="target_locales_label[<?php echo esc_attr($language->slug); ?>]">Auto-request with document upload
216
  </label>
217
  </td>
218
  </tr>
219
- <tr id="<?php echo esc_attr($language->slug); ?>_details" style="display:none;">
220
- <td colspan="2" style="padding:0;">
221
- <table class="form-table" style="background: #ffffff; margin:0; padding: 10px;"><?php
222
- foreach ($settings as $key => $setting) {
223
- $custom_key = 'custom['.$key.']['.esc_attr($language->slug).']'; ?>
 
 
224
  <tr>
225
- <th scope="row">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<?php printf('<label for="%s">%s</label>', $custom_key , $setting['label']); ?></th>
226
- <td><?php
227
- printf('<select name="%1$s" id="%1$s" %2$s>', $custom_key, in_array($key, array('upload', 'download')) ? $disabled : '');
228
- foreach ($setting['options'] as $id => $title) {
229
- if ($id === 'default' && $key === 'workflow_id') {
230
- $id = $defaults['workflow_id'];
231
- }
232
- $selected = isset($profile['custom'][$key][$language->slug]) && $profile['custom'][$key][$language->slug] == $id ? 'selected="selected"' : '';
233
- echo "\n\t<option value='" . esc_attr($id) . "' $selected>" . esc_html($title) . '</option>';
234
- } ?>
 
 
235
  </select>
236
  </td>
237
- </tr><?php
238
- } ?>
 
 
239
  </table>
240
- </td>
241
- </tr>
242
- <?php
243
- } ?>
244
- <tr>
 
 
245
  <td></td>
246
  <td class="target-table-td"></td>
247
  <td>
@@ -256,67 +296,70 @@ unset($settings['secondary_filter_id']['options'][$primary_filter_id]);
256
  }
257
  ";
258
  ?>
259
- <input type="checkbox" name="target_select_all" id="target_select_all" onchange="<?php echo $select_all_on_change; ?>">
260
- <label for="target_select_all">Select All</label></td>
261
- </tr>
262
- <?php
263
  $target_warning = $custom_profile_chosen ? '' : 'style="display:none"';
264
- ?>
265
- <tr>
266
- <td colspan="3"><span id='target_warning' <?php echo $target_warning; ?>><b>Note:</b> If any targets are selected to be uploaded and at the same time a custom workflow is selected
267
- for any of them, all targets to be uploaded must have a non-project-default workflow selected.</span></td>
268
- </tr>
269
  </table>
270
 
271
- <?php $metadata = array(
272
- "author_email" => "Author Email",
273
- "author_name" => "Author Name",
274
- "division" => "Business Division",
275
- "unit" => "Business Unit",
276
- "campaign_id" => "Campaign ID",
277
- "channel" => "Channel",
278
- "contact_email" => "Contact Email",
279
- "contact_name" => "Contact Name",
280
- "description" => "Content Description",
281
- "domain" => "Domain",
282
- "style_id" => "External Style ID",
283
- "purchase_order" => "Purchase Order",
284
- "reference_url" => "Reference URL",
285
- "region" => "Region",
286
- "require_review" => "Require Review"
287
- ) ?>
288
- <h3><?php _e('Document Metadata', 'lingotek-translation'); ?></h3>
 
 
289
  <table class="form-table">
290
- <?php
291
- foreach ($metadata as $key => $data){
292
- $index = array_search($key,array_keys($metadata));
293
- if ($index == 0){
294
- printf('<tr>');
295
- }
296
- if ($index %3 == 0){
297
- printf('</tr>');
298
- printf('<tr>');
299
  }
300
- if (isset($profile[$key])){
301
- printf('<th>&nbsp; %s <br><input type="text" name="%s" value="%s"></th>', $data ,$key, $profile[$key]);
 
302
  }
303
- else{
304
- printf('<th>&nbsp; %s <br><input type="text" name="%s"></th>', $data, $key);
 
 
305
  }
306
  }
307
  ?>
308
- </table>
309
 
310
- <?php submit_button(__('Save Changes', 'lingotek-translation'), 'primary', 'submit', false); ?>
311
  <?php
312
- if (!empty($profile['profile']) && !in_array($profile['profile'], array('automatic', 'manual', 'disabled')) && empty($profile['usage']))
313
  printf(
314
  '<a href="%s" class="button" onclick = "return confirm(\'%s\');">%s</a>',
315
- esc_url(wp_nonce_url('admin.php?page=lingotek-translation_manage&sm=profiles&lingotek_action=delete-profile&noheader=true&profile='.$profile['profile'], 'delete-profile')),
316
- __('You are about to permanently delete this profile. Are you sure?', 'lingotek-translation'),
317
- __('Delete', 'lingotek-translation')
318
  );
319
- ?> <a href="admin.php?page=lingotek-translation_manage&amp;sm=profiles" class="button"> <?php _e('Cancel', 'lingotek-translation'); ?></a>
 
 
320
  </form>
321
 
322
- <?php Lingotek_Workflow_Factory::echo_info_modals(); ?>
2
 
3
  $settings = $this->get_profiles_settings();
4
 
5
+ $defaults = get_option( 'lingotek_defaults', array() );
6
+ /* translators: %s: The global default value. */
7
+ $default = __( 'Use global default (%s)', 'lingotek-translation' );
8
+ foreach ( $settings as $key => $setting ) {
9
+ if ( isset( $defaults[ $key ] ) && array_key_exists( $defaults[ $key ], $settings[ $key ]['options'] ) ) {
10
+ $default_arr = array( 'default' => sprintf( $default, $settings[ $key ]['options'][ $defaults[ $key ] ] ) );
11
+ $settings[ $key ]['options'] = array_merge( $default_arr, $settings[ $key ]['options'] );
12
  }
13
  }
14
 
15
  $target_settings = array(
16
+ 'default' => __( 'Use default settings', 'lingotek-translation' ),
17
+ 'custom' => __( 'Use custom settings', 'lingotek-translation' ),
18
+ 'copy' => __( 'Copy source language', 'lingotek-translation' ),
19
+ 'disabled' => __( 'Disabled', 'lingotek-translation' ),
20
  );
21
 
22
+ $profiles = $this->get_profiles_usage( get_option( 'lingotek_profiles' ) );
23
 
24
+ $profile = isset( $_GET['profile'] ) && array_key_exists( sanitize_key( wp_unslash( $_GET['profile'] ) ), $profiles ) ? $profiles[ sanitize_key( wp_unslash( $_GET['profile'] ) ) ] : array();
25
+ $disabled = isset( $profile['profile'] ) && in_array( $profile['profile'], array( 'automatic', 'manual' ), true ) ? 'disabled="disabled"' : '';
26
  // Code to determine which filter scenario will be displayed. (Not configured, defaults, custom filters)
27
+ $primary_filter_id = array_search( 'okf_json@with-html-subfilter.fprm', $settings['primary_filter_id']['options'], true );
28
+ $secondary_filter_id = array_search( 'okf_html@wordpress.fprm', $settings['secondary_filter_id']['options'], true );
29
+ $default_filters = array(
30
+ $primary_filter_id => 'okf_json@with-html-subfilter.fprm',
31
+ $secondary_filter_id => 'okf_html@wordpress.fprm',
32
+ );
33
+ $default_filters_exist = false;
34
+ $extra_filters_exist = false;
35
+ $no_filters_exist = false;
36
 
37
+ if ( array_key_exists( 'default', array_diff_assoc( $settings['primary_filter_id']['options'], $default_filters ) ) && 1 === count( array_diff_assoc( $settings['primary_filter_id']['options'], $default_filters ) ) ) {
38
+ unset( $settings['primary_filter_id']['options']['default'] );
 
 
 
 
 
 
39
  }
40
+ if ( $settings['primary_filter_id']['options'] === $default_filters ) {
41
+ $default_filters_exist = true;
42
+ $defaults['primary_filter_id'] = $primary_filter_id;
43
+ $defaults['secondary_filter_id'] = $secondary_filter_id;
44
+ update_option( 'lingotek_defaults', $defaults, false );
45
+ } else {
46
+ $num = count( array_diff_assoc( $settings['primary_filter_id']['options'], $default_filters ) );
47
+ if ( $num > 0 ) {
48
+ $extra_filters_exist = true;
49
+ } else {
50
+ $defaults['primary_filter_id'] = '';
51
+ $defaults['secondary_filter_id'] = '';
52
+ update_option( 'lingotek_defaults', $defaults, false );
53
+ $no_filters_exist = true;
54
+ }
55
  }
56
+ unset( $settings['primary_filter_id']['options'][ $secondary_filter_id ] );
57
+ unset( $settings['secondary_filter_id']['options'][ $primary_filter_id ] );
58
  ?>
59
 
60
  <form id="lingotek-edit-profile" method="post" action="admin.php?page=lingotek-translation_manage&sm=profiles" class="validate">
61
+ <?php wp_nonce_field( 'lingotek-edit-profile', '_wpnonce_lingotek-edit-profile' ); ?>
62
+ <input name="profile" type="hidden" value="<?php echo empty( $profile['profile'] ) ? '' : esc_attr( $profile['profile'] ); ?>">
63
 
64
  <table class="form-table">
65
  <tr>
66
+ <th scope="row"><?php printf( '<label for="%s">%s</label>', 'name', esc_attr__( 'Profile name', 'lingotek-translation' ) ); ?></th>
67
+ <td>
68
+ <?php
69
+ if ( ! empty( $profile ) ) {
70
+ // localize canned profile names
71
+ $profile_name = $disabled ? __( 'Disabled', 'lingotek-translation' ) : $profile['name'];
72
  }
73
+ printf(
74
+ '<input name="name" id="name" type="text" value="%s" %s>',
75
+ empty( $profile['name'] ) ? '' : esc_attr( $profile_name ),
76
+ esc_html( $disabled )
77
+ );
78
+ ?>
79
  </td>
80
  </tr>
81
  </table>
82
 
83
+ <h3><?php esc_html_e( 'Default settings', 'lingotek-translation' ); ?></h3>
84
 
85
+ <table class="form-table">
86
+ <?php
87
+ foreach ( $settings as $key => $setting ) {
88
+ ?>
89
+ <tr id="<?php echo $key . '_row'; ?>">
90
+ <th scope="row"><?php printf( '<label for="%s">%s</label>', $key, $setting['label'] ); ?></th>
91
+ <td>
92
+ <?php
93
+ printf( '<select name="%1$s" id="%1$s" %2$s>', $key, in_array( $key, array( 'upload', 'download' ) ) ? $disabled : '' );
94
+ foreach ( $setting['options'] as $option_id => $option_title ) {
95
+ $selected = isset( $profile[ $key ] ) && $profile[ $key ] == $option_id ? 'selected="selected"' : '';
96
+ echo "\n\t<option value='" . esc_attr( $option_id ) . "' $selected>" . esc_html( $option_title ) . '</option>';
97
+ }
98
+ ?>
99
+ </select>
100
+ <?php
101
 
102
+ if ( 'project_id' == $key ) {
103
+ ?>
104
  <input type="checkbox" name="update_callback" id="update_callback"/>
105
+ <label for="update_callback"><?php _e( 'Update the callback url for this project.', 'lingotek-translation' ); ?></label>
106
+ <?php
107
  }
108
 
109
+ if ( isset( $setting['description'] ) ) {
110
+ printf( '<p class="description">%s</p>', $setting['description'] );
111
+ }
112
+ ?>
113
 
114
  <!-- Code to handle displaying of Primary and Secondary Filters -->
115
+ <?php if ( $no_filters_exist ) { ?>
116
+ <script> document.getElementById("primary_filter_id_row").style.display = "none";</script>
117
+ <script> document.getElementById("secondary_filter_id_row").style.display = "none";</script>
118
+ <?php
119
+ if ( 'primary_filter_id' == $key ) {
120
+ ?>
121
+ <tr id="filters_row"><th><?php _e( 'Filters', 'lingotek-translation' ); ?></th><td><i><?php _e( 'Not configured', 'lingotek-translation' ); ?></i></td></tr>
122
+ <?php
123
+ }
124
+ }
125
+ if ( $default_filters_exist ) {
126
+ ?>
127
+ <script> document.getElementById("primary_filter_id_row").style.display = "none";</script>
128
+ <script> document.getElementById("secondary_filter_id_row").style.display = "none";</script>
129
+ <?php } ?>
130
+ <!-- End of filter code -->
131
  </td>
132
+ </tr>
133
+ <?php
134
+ }//end foreach
135
+
136
+ ?>
137
  </table>
138
 
139
+ <h3><?php _e( 'Target languages', 'lingotek-translation' ); ?></h3>
140
 
141
+ <table class="form-table target-table">
142
+ <?php
143
+ // we don't want this for target languages
144
+ unset( $settings['upload'] );
145
+ // FIXME disable the possibility to have a different project per target language for now
146
+ unset( $settings['project_id'] );
147
  // Filters not needed for target languages
148
+ unset( $settings['primary_filter_id'] );
149
+ unset( $settings['secondary_filter_id'] );
150
+ ?>
151
  <?php
152
  $custom_profile_chosen = false;
153
+ foreach ( $this->pllm->get_languages_list() as $language ) {
154
+ ?>
155
  <tr>
156
+ <th scope="row"><?php printf( '<label for="%s">%s (%s)</label>', esc_attr( $language->slug ), esc_html( $language->name ), esc_attr( $language->locale ) ); ?>
157
+ <?php
158
 
159
+ printf(
160
+ '<a id="%1$s_details_link" %2$s class="dashicons dashicons-arrow-right" onclick="%3$s">%4$s</a>',
161
+ esc_attr( $language->slug ),
162
+ isset( $profile['targets'][ $language->slug ] ) && 'custom' == $profile['targets'][ $language->slug ] ? '' : 'style="display:none;"',
163
  "
164
  d = document.getElementById('{$language->slug}_details');
165
  if ('none' == d.style.display) {
170
  d.style.display = 'none';
171
  this.className = 'dashicons dashicons-arrow-right';
172
  }",
173
+ ''
174
+ );
175
+ ?>
176
+ </th>
177
+ <td class="target-table-td">
178
+ <?php
179
+ printf(
180
+ '<select name="targets[%1$s]" id="targets[%1$s]" onchange="%2$s">',
181
+ esc_attr( $language->slug ),
182
  "
183
  dl = document.getElementById('{$language->slug}_details_link');
184
  d = document.getElementById('{$language->slug}_details');
214
  }
215
  "
216
  );
217
+ foreach ( $target_settings as $target_id => $target_title ) {
218
+ $selected = ( empty( $profile['targets'][ $language->slug ] ) && 'default' === $target_id ) || ( isset( $profile['targets'][ $language->slug ] ) && $profile['targets'][ $language->slug ] === $target_id ) ? 'selected="selected"' : '';
219
+ echo "\n\t<option value='" . esc_attr( $target_id ) . "' $selected>" . esc_html( $target_title ) . '</option>';
220
+ }
221
+ ?>
222
  </select>
223
 
224
  </td>
225
  <?php
226
+ if ( isset( $profile['targets'][ $language->slug ] ) && 'custom' === $profile['targets'][ $language->slug ] ) {
227
+ $custom_profile_chosen = true;
228
+ }
229
+ $checked = empty( $profile['target_locales'][ $language->slug ] ) ? '' : 'checked="checked"';
230
  $display = '';
231
+ if ( isset( $profile['targets'][ $language->slug ] ) && ( 'disabled' === $profile['targets'][ $language->slug ] || 'copy' === $profile['targets'][ $language->slug ] ) ) {
232
+ $display = 'style="display:none;"';
233
+ }
234
  ?>
235
  <td><input
236
  <?php echo $checked; ?>
237
  <?php echo $display; ?>
238
  type="checkbox"
239
  class="ltk-target-checkbox"
240
+ value="<?php echo esc_attr( $language->lingotek_locale ); ?>"
241
+ id="target_locales[<?php echo esc_attr( $language->slug ); ?>]"
242
+ name="target_locales[<?php echo esc_attr( $language->slug ); ?>]"
243
  >
244
  <label
245
  <?php echo $display; ?>
246
+ for="target_locales[<?php echo esc_attr( $language->slug ); ?>]"
247
+ id="target_locales_label[<?php echo esc_attr( $language->slug ); ?>]">Auto-request with document upload
248
  </label>
249
  </td>
250
  </tr>
251
+ <tr id="<?php echo esc_attr( $language->slug ); ?>_details" style="display:none;">
252
+ <td colspan="2" style="padding:0;">
253
+ <table class="form-table" style="background: #ffffff; margin:0; padding: 10px;">
254
+ <?php
255
+ foreach ( $settings as $key => $setting ) {
256
+ $custom_key = 'custom[' . $key . '][' . esc_attr( $language->slug ) . ']';
257
+ ?>
258
  <tr>
259
+ <th scope="row"><?php printf( '<label for="%s">%s</label>', esc_attr( $custom_key ), esc_attr( $setting['label'] ) ); ?></th>
260
+ <td>
261
+ <?php
262
+ printf( '<select name="%1$s" id="%1$s" %2$s>', $custom_key, in_array( $key, array( 'upload', 'download' ) ) ? $disabled : '' );
263
+ foreach ( $setting['options'] as $option_id => $option_title ) {
264
+ if ( 'default' === $option_id && 'workflow_id' === $key ) {
265
+ $option_id = $defaults['workflow_id'];
266
+ }
267
+ $selected = isset( $profile['custom'][ $key ][ $language->slug ] ) && $profile['custom'][ $key ][ $language->slug ] == $option_id ? 'selected="selected"' : '';
268
+ echo "\n\t<option value='" . esc_attr( $option_id ) . "' $selected>" . esc_html( $option_title ) . '</option>';
269
+ }
270
+ ?>
271
  </select>
272
  </td>
273
+ </tr>
274
+ <?php
275
+ }//end foreach
276
+ ?>
277
  </table>
278
+ </td>
279
+ </tr>
280
+ <?php
281
+ }//end foreach
282
+
283
+ ?>
284
+ <tr>
285
  <td></td>
286
  <td class="target-table-td"></td>
287
  <td>
296
  }
297
  ";
298
  ?>
299
+ <input type="checkbox" name="target_select_all" id="target_select_all" onchange="<?php echo esc_attr( $select_all_on_change ); ?>">
300
+ <label for="target_select_all"><?php esc_html_e( 'Select All', 'lingotek-translation' ); ?></label></td>
301
+ </tr>
302
+ <?php
303
  $target_warning = $custom_profile_chosen ? '' : 'style="display:none"';
304
+ ?>
305
+ <tr>
306
+ <td colspan="3"><span id='target_warning' <?php echo $target_warning; ?>><b>Note:</b> If any targets are selected to be uploaded and at the same time a custom workflow is selected
307
+ for any of them, all targets to be uploaded must have a non-project-default workflow selected.</span></td>
308
+ </tr>
309
  </table>
310
 
311
+ <?php
312
+ $metadata = array(
313
+ 'author_email' => 'Author Email',
314
+ 'author_name' => 'Author Name',
315
+ 'division' => 'Business Division',
316
+ 'unit' => 'Business Unit',
317
+ 'campaign_id' => 'Campaign ID',
318
+ 'channel' => 'Channel',
319
+ 'contact_email' => 'Contact Email',
320
+ 'contact_name' => 'Contact Name',
321
+ 'description' => 'Content Description',
322
+ 'domain' => 'Domain',
323
+ 'style_id' => 'External Style ID',
324
+ 'purchase_order' => 'Purchase Order',
325
+ 'reference_url' => 'Reference URL',
326
+ 'region' => 'Region',
327
+ 'require_review' => 'Require Review',
328
+ )
329
+ ?>
330
+ <h3><?php esc_html_e( 'Document Metadata', 'lingotek-translation' ); ?></h3>
331
  <table class="form-table">
332
+ <?php
333
+ foreach ( $metadata as $key => $data ) {
334
+ $index = array_search( $key, array_keys( $metadata ), true );
335
+ if ( 0 === $index ) {
336
+ printf( '<tr>' );
 
 
 
 
337
  }
338
+ if ( 0 === $index % 3 ) {
339
+ printf( '</tr>' );
340
+ printf( '<tr>' );
341
  }
342
+ if ( isset( $profile[ $key ] ) ) {
343
+ printf( '<th>&nbsp; %s <br><input type="text" name="%s" value="%s"></th>', esc_html( $data ), esc_attr( $key ), esc_attr( $profile[ $key ] ) );
344
+ } else {
345
+ printf( '<th>&nbsp; %s <br><input type="text" name="%s"></th>', esc_html( $data ), esc_attr( $key ) );
346
  }
347
  }
348
  ?>
349
+ </table>
350
 
351
+ <?php submit_button( __( 'Save Changes', 'lingotek-translation' ), 'primary', 'submit', false ); ?>
352
  <?php
353
+ if ( ! empty( $profile['profile'] ) && ! in_array( $profile['profile'], array( 'automatic', 'manual', 'disabled' ), true ) && empty( $profile['usage'] ) ) {
354
  printf(
355
  '<a href="%s" class="button" onclick = "return confirm(\'%s\');">%s</a>',
356
+ esc_url( wp_nonce_url( 'admin.php?page=lingotek-translation_manage&sm=profiles&lingotek_action=delete-profile&noheader=true&profile=' . $profile['profile'], 'delete-profile' ) ),
357
+ esc_html__( 'You are about to permanently delete this profile. Are you sure?', 'lingotek-translation' ),
358
+ esc_html__( 'Delete', 'lingotek-translation' )
359
  );
360
+ }
361
+ ?>
362
+ <a href="admin.php?page=lingotek-translation_manage&amp;sm=profiles" class="button"> <?php esc_html_e( 'Cancel', 'lingotek-translation' ); ?></a>
363
  </form>
364
 
365
+ <?php Lingotek_Workflow_Factory::lingotek_translation_professional_translation_info_modals(); ?>
admin/manage/view-profiles.php CHANGED
@@ -2,125 +2,139 @@
2
  global $polylang;
3
 
4
  $profiles = Lingotek::get_profiles();
5
- $profiles = $this->get_profiles_usage($profiles);
6
  $settings = $this->get_profiles_settings();
7
 
8
- if (isset($_GET['lingotek_action']) && 'delete-profile' == $_GET['lingotek_action']) {
9
- check_admin_referer('delete-profile');
10
 
11
  // check again that usage empty
12
- if (!empty($profiles[$_GET['profile']]) && empty($profiles[$_GET['profile']]['usage'])) {
13
- unset($profiles[$_GET['profile']]);
14
- update_option('lingotek_profiles', $profiles, false);
15
- add_settings_error('lingotek_profile', 'default', __('Your translation profile was sucessfully deleted.', 'lingotek-translation'), 'updated');
16
- set_transient('settings_errors', get_settings_errors(), 30);
17
- wp_redirect(admin_url('admin.php?page=lingotek-translation_manage&sm=profiles&settings-updated=1'));
18
  exit;
19
  }
20
  }
21
 
22
- if (!empty($_POST)) {
23
- check_admin_referer('lingotek-edit-profile', '_wpnonce_lingotek-edit-profile');
24
 
25
- $defaults = get_option('lingotek_defaults');
26
 
27
- if (empty($_POST['name']) && empty($_POST['profile'])) {
28
- add_settings_error('lingotek_profile', 'default', __('You must provide a name for your translation profile.', 'lingotek-translation'), 'error');
29
- }
30
- else {
31
- $profile_id = empty($_POST['profile']) ? uniqid(rand()) : $_POST['profile'];
32
- $profiles[$profile_id]['profile'] = $profile_id;
33
- if (!empty($_POST['name']))
34
- $profiles[$profile_id]['name'] = strip_tags($_POST['name']);
35
-
36
- foreach (array('upload', 'download', 'project_id', 'workflow_id', 'primary_filter_id', 'secondary_filter_id','author_email', 'author_name','division','unit','campaign_id','channel','contact_email','contact_name','description','domain','style_id','purchase_order','reference_url','region','require_review') as $key) {
37
- if (isset($_POST[$key]) )
38
- $profiles[$profile_id][$key] = $_POST[$key];
39
-
40
- if (empty($_POST[$key]) || 'default' == $_POST[$key])
41
- unset($profiles[$profile_id][$key]);
 
 
42
  }
43
 
44
- $custom_profile_keys = array('download', 'project_id', 'workflow_id');
45
 
46
- foreach ($this->pllm->get_languages_list() as $language) {
47
- switch($_POST['targets'][$language->slug]) {
48
  case 'custom':
49
- foreach ($custom_profile_keys as $key) {
50
- if (isset($_POST['custom'][$key][$language->slug]) && in_array($_POST['custom'][$key][$language->slug], array_keys($settings[$key]['options']))) {
51
- $profiles[$profile_id]['custom'][$key][$language->slug] = $_POST['custom'][$key][$language->slug];
52
  }
53
 
54
- if ($key != 'workflow_id' && (empty($_POST['custom'][$key][$language->slug]) || 'default' == $_POST['custom'][$key][$language->slug])) {
55
- unset($profiles[$profile_id]['custom'][$key][$language->slug]);
56
  }
57
  }
58
- $profiles[$profile_id]['targets'][$language->slug] = $_POST['targets'][$language->slug];
59
  break;
60
 
61
  case 'disabled':
62
  case 'copy':
63
- $profiles[$profile_id]['targets'][$language->slug] = $_POST['targets'][$language->slug];
64
- foreach ($custom_profile_keys as $key) {
65
- unset($profiles[$profile_id]['custom'][$key][$language->slug]);
66
  }
67
  break;
68
 
69
  case 'default':
70
- unset($profiles[$profile_id]['targets'][$language->slug]);
71
- foreach ($custom_profile_keys as $key) {
72
- if ($key !== 'workflow_id') {
73
- unset($profiles[$profile_id]['custom'][$key][$language->slug]);
74
  }
75
  }
 
 
 
76
  }
77
- if ($_POST['targets'][$language->slug] != 'disabled' && isset($_POST['custom']['workflow_id'][$language->slug])) {
78
- $profiles[$profile_id]['custom']['workflow_id'][$language->slug] = $_POST['custom']['workflow_id'][$language->slug];
 
 
 
79
  }
80
- }
81
- if (!isset($_POST['custom']['workflow_id'])) {
82
- unset($profiles[$profile_id]['custom']['workflow_id']);
83
  }
84
 
85
  // Add target locales to request
86
- $profiles[$profile_id]['target_locales'] = empty($_POST['target_locales']) ? array() : $_POST['target_locales'];
87
 
88
- // hardcode default values for automatic and manual profiles as the process above emptied them
89
  $profiles['automatic']['upload'] = $profiles['automatic']['download'] = 'automatic';
90
- $profiles['manual']['upload'] = $profiles['manual']['download'] = 'manual';
91
- $profiles['automatic']['name'] = 'Automatic'; $profiles['manual']['name'] = 'Manual'; $profiles['disabled']['name'] = 'Disabled';// do not localize names here
 
 
 
 
92
 
93
- update_option('lingotek_profiles', $profiles, false);
94
- add_settings_error('lingotek_profile', 'default', __('Your translation profile was sucessfully saved.', 'lingotek-translation'), 'updated');
95
 
96
- if (isset($_POST['update_callback'])) {
97
- $project_id = isset($profiles[$profile_id]['project_id']) ? $profiles[$profile_id]['project_id'] : $defaults['project_id'];
98
- $client = new Lingotek_API();
99
- if ($client->update_callback_url($project_id))
100
- add_settings_error('lingotek_profile', 'default', __('Your callback url was successfully updated.', 'lingotek-translation'), 'updated');
 
101
  }
102
- }
103
  settings_errors();
104
- }
105
 
106
  ?>
107
- <h3><?php _e('Translation Profiles', 'lingotek-translation'); ?></h3>
108
  <p class="description">
109
- <?php _e('Translation profiles allow you to quickly configure and re-use translation settings.', 'lingotek-translation'); ?>
110
- </p><?php
 
111
 
112
  $table = new Lingotek_Profiles_Table();
113
- $table->prepare_items($profiles);
114
  ?>
115
  <style>
116
  .tablenav {
117
- clear: none !important;
118
  }
119
  </style>
120
  <?php
121
  $table->display();
122
  printf(
123
  '<a href="%s" class="button button-primary">%s</a>',
124
- admin_url('admin.php?page=lingotek-translation_manage&sm=edit-profile'),
125
- __('Add New Profile', 'lingotek-translation')
126
- );
2
  global $polylang;
3
 
4
  $profiles = Lingotek::get_profiles();
5
+ $profiles = $this->get_profiles_usage( $profiles );
6
  $settings = $this->get_profiles_settings();
7
 
8
+ if ( isset( $_GET['lingotek_action'] ) && 'delete-profile' == $_GET['lingotek_action'] ) {
9
+ check_admin_referer( 'delete-profile' );
10
 
11
  // check again that usage empty
12
+ if ( ! empty( $profiles[ $_GET['profile'] ] ) && empty( $profiles[ $_GET['profile'] ]['usage'] ) ) {
13
+ unset( $profiles[ $_GET['profile'] ] );
14
+ update_option( 'lingotek_profiles', $profiles, false );
15
+ add_settings_error( 'lingotek_profile', 'default', __( 'Your translation profile was sucessfully deleted.', 'lingotek-translation' ), 'updated' );
16
+ set_transient( 'settings_errors', get_settings_errors(), 30 );
17
+ wp_redirect( admin_url( 'admin.php?page=lingotek-translation_manage&sm=profiles&settings-updated=1' ) );
18
  exit;
19
  }
20
  }
21
 
22
+ if ( ! empty( $_POST ) ) {
23
+ check_admin_referer( 'lingotek-edit-profile', '_wpnonce_lingotek-edit-profile' );
24
 
25
+ $defaults = get_option( 'lingotek_defaults', array() );
26
 
27
+ if ( empty( $_POST['name'] ) && empty( $_POST['profile'] ) ) {
28
+ add_settings_error( 'lingotek_profile', 'default', __( 'You must provide a name for your translation profile.', 'lingotek-translation' ), 'error' );
29
+ } else {
30
+ $profile_id = empty( $_POST['profile'] ) ? uniqid( rand() ) : $_POST['profile'];
31
+ $profiles[ $profile_id ]['profile'] = $profile_id;
32
+ if ( ! empty( $_POST['name'] ) ) {
33
+ $profiles[ $profile_id ]['name'] = strip_tags( $_POST['name'] );
34
+ }
35
+
36
+ foreach ( array( 'upload', 'download', 'project_id', 'workflow_id', 'primary_filter_id', 'secondary_filter_id', 'author_email', 'author_name', 'division', 'unit', 'campaign_id', 'channel', 'contact_email', 'contact_name', 'description', 'domain', 'style_id', 'purchase_order', 'reference_url', 'region', 'require_review' ) as $key ) {
37
+ if ( isset( $_POST[ $key ] ) ) {
38
+ $profiles[ $profile_id ][ $key ] = $_POST[ $key ];
39
+ }
40
+
41
+ if ( empty( $_POST[ $key ] ) || 'default' == $_POST[ $key ] ) {
42
+ unset( $profiles[ $profile_id ][ $key ] );
43
+ }
44
  }
45
 
46
+ $custom_profile_keys = array( 'download', 'project_id', 'workflow_id' );
47
 
48
+ foreach ( $this->pllm->get_languages_list() as $language ) {
49
+ switch ( $_POST['targets'][ $language->slug ] ) {
50
  case 'custom':
51
+ foreach ( $custom_profile_keys as $key ) {
52
+ if ( isset( $_POST['custom'][ $key ][ $language->slug ] ) && in_array( $_POST['custom'][ $key ][ $language->slug ], array_keys( $settings[ $key ]['options'] ) ) ) {
53
+ $profiles[ $profile_id ]['custom'][ $key ][ $language->slug ] = $_POST['custom'][ $key ][ $language->slug ];
54
  }
55
 
56
+ if ( $key != 'workflow_id' && ( empty( $_POST['custom'][ $key ][ $language->slug ] ) || 'default' == $_POST['custom'][ $key ][ $language->slug ] ) ) {
57
+ unset( $profiles[ $profile_id ]['custom'][ $key ][ $language->slug ] );
58
  }
59
  }
60
+ $profiles[ $profile_id ]['targets'][ $language->slug ] = $_POST['targets'][ $language->slug ];
61
  break;
62
 
63
  case 'disabled':
64
  case 'copy':
65
+ $profiles[ $profile_id ]['targets'][ $language->slug ] = $_POST['targets'][ $language->slug ];
66
+ foreach ( $custom_profile_keys as $key ) {
67
+ unset( $profiles[ $profile_id ]['custom'][ $key ][ $language->slug ] );
68
  }
69
  break;
70
 
71
  case 'default':
72
+ unset( $profiles[ $profile_id ]['targets'][ $language->slug ] );
73
+ foreach ( $custom_profile_keys as $key ) {
74
+ if ( $key !== 'workflow_id' ) {
75
+ unset( $profiles[ $profile_id ]['custom'][ $key ][ $language->slug ] );
76
  }
77
  }
78
+ }//end switch
79
+ if ( $_POST['targets'][ $language->slug ] != 'disabled' && isset( $_POST['custom']['workflow_id'][ $language->slug ] ) ) {
80
+ $profiles[ $profile_id ]['custom']['workflow_id'][ $language->slug ] = $_POST['custom']['workflow_id'][ $language->slug ];
81
  }
82
+ // If target workflow is set to default, and there is another target with a custom workflow, set default workflow id
83
+ if ( $_POST['targets'][ $language->slug ] === 'default' && in_array( 'custom', $_POST['targets'] ) && isset( $_POST['custom']['workflow_id'][ $language->slug ] ) ) {
84
+ $profiles[ $profile_id ]['custom']['workflow_id'][ $language->slug ] = $_POST['workflow_id'];
85
+ } elseif ( $_POST['targets'][ $language->slug ] != 'disabled' && isset( $_POST['custom']['workflow_id'][ $language->slug ] ) ) {
86
+ $profiles[ $profile_id ]['custom']['workflow_id'][ $language->slug ] = $_POST['custom']['workflow_id'][ $language->slug ];
87
  }
88
+ }//end foreach
89
+ if ( ! isset( $_POST['custom']['workflow_id'] ) ) {
90
+ unset( $profiles[ $profile_id ]['custom']['workflow_id'] );
91
  }
92
 
93
  // Add target locales to request
94
+ $profiles[ $profile_id ]['target_locales'] = empty( $_POST['target_locales'] ) ? array() : $_POST['target_locales'];
95
 
96
+ // Hardcode default values for automatic and manual profiles as the process above emptied them.
97
  $profiles['automatic']['upload'] = $profiles['automatic']['download'] = 'automatic';
98
+ $profiles['manual']['upload'] = $profiles['manual']['download'] = 'manual';
99
+
100
+ // Do not localize names here.
101
+ $profiles['automatic']['name'] = 'Automatic';
102
+ $profiles['manual']['name'] = 'Manual';
103
+ $profiles['disabled']['name'] = 'Disabled';
104
 
105
+ update_option( 'lingotek_profiles', $profiles, false );
106
+ add_settings_error( 'lingotek_profile', 'default', __( 'Your translation profile was sucessfully saved.', 'lingotek-translation' ), 'updated' );
107
 
108
+ if ( isset( $_POST['update_callback'] ) ) {
109
+ $project_id = isset( $profiles[ $profile_id ]['project_id'] ) ? $profiles[ $profile_id ]['project_id'] : $defaults['project_id'];
110
+ $client = new Lingotek_API();
111
+ if ( $client->update_callback_url( $project_id ) ) {
112
+ add_settings_error( 'lingotek_profile', 'default', __( 'Your callback url was successfully updated.', 'lingotek-translation' ), 'updated' );
113
+ }
114
  }
115
+ }//end if
116
  settings_errors();
117
+ }//end if
118
 
119
  ?>
120
+ <h3><?php _e( 'Translation Profiles', 'lingotek-translation' ); ?></h3>
121
  <p class="description">
122
+ <?php _e( 'Translation profiles allow you to quickly configure and re-use translation settings.', 'lingotek-translation' ); ?>
123
+ </p>
124
+ <?php
125
 
126
  $table = new Lingotek_Profiles_Table();
127
+ $table->prepare_items( $profiles );
128
  ?>
129
  <style>
130
  .tablenav {
131
+ clear: none !important;
132
  }
133
  </style>
134
  <?php
135
  $table->display();
136
  printf(
137
  '<a href="%s" class="button button-primary">%s</a>',
138
+ admin_url( 'admin.php?page=lingotek-translation_manage&sm=edit-profile' ),
139
+ __( 'Add New Profile', 'lingotek-translation' )
140
+ );
admin/manage/view-string-groups.php CHANGED
@@ -1,41 +1,49 @@
1
- <h3><?php _e('String Groups', 'lingotek-translation'); ?></h3>
2
 
3
- <p class="description"><?php printf(__('Manage group translation of system, widget, and plugin-specific strings. View individual strings on the <a href="%s"><b>Strings</b></a> page.', 'lingotek-translation'), 'admin.php?page=lingotek-translation_manage&sm=strings'); ?></p>
4
  <?php
5
 
6
- $profile = Lingotek_Model::get_profile('string', $this->pllm->get_language($this->pllm->options['default_lang']));
7
 
8
- if ('disabled' == $profile['profile']) {
9
- printf('<div class="error" style="border-left: 4px solid #ffba00;"><p>%s</p></div>', // no warning class in WP 4.0, color form .update-nag
10
- sprintf(__('The strings translation is disabled in %sContent Type Configuration%s.', 'lingotek-translation'),
11
- '<a href="' . admin_url('admin.php?page=lingotek-translation_settings&sm=content') . '">',
 
 
 
12
  '</a>'
13
  )
14
  );
15
- }
16
- else {
17
  $string_actions = $GLOBALS['wp_lingotek']->string_actions;
18
- $table = new Lingotek_Strings_Table($string_actions);
19
- $action = $table->current_action();
20
- if (!empty($action)) {
21
- ob_end_clean(); // flush the output buffer.
22
- $string_actions->manage_actions($action);
23
- }
 
24
 
25
  $data = Lingotek_Model::get_strings();
26
- foreach ($data as $key => $row) {
27
- $data[$key]['row'] = $key; // store the row number for convenience
28
- }
29
-
30
- $table->prepare_items($data); ?>
 
 
31
 
32
- <form id="lingotek-strings" method="post" action="admin.php?page=lingotek-translation_manage&amp;noheader=true&amp;sm=string-groups"><?php
33
- $table->display(); ?>
34
- </form><?php
 
 
 
35
 
36
- foreach (Lingotek_String_actions::$actions as $action => $strings) {
37
- if (!empty($_GET['bulk-lingotek-' . $action])) {
38
- printf('<div id="lingotek-progressdialog" title="%s"><div id="lingotek-progressbar"></div></div>', $strings['progress']);
39
- }
40
  }
41
- }
1
+ <h3><?php _e( 'String Groups', 'lingotek-translation' ); ?></h3>
2
 
3
+ <p class="description"><?php printf( __( 'Manage group translation of system, widget, and plugin-specific strings. View individual strings on the <a href="%s"><b>Strings</b></a> page.', 'lingotek-translation' ), 'admin.php?page=lingotek-translation_manage&sm=strings' ); ?></p>
4
  <?php
5
 
6
+ $profile = Lingotek_Model::get_profile( 'string', $this->pllm->get_language( $this->pllm->options['default_lang'] ) );
7
 
8
+ if ( 'disabled' == $profile['profile'] ) {
9
+ // no warning class in WP 4.0, color form .update-nag
10
+ printf(
11
+ '<div class="error" style="border-left: 4px solid #ffba00;"><p>%s</p></div>',
12
+ sprintf(
13
+ __( 'The strings translation is disabled in %1$sContent Type Configuration%2$s.', 'lingotek-translation' ),
14
+ '<a href="' . admin_url( 'admin.php?page=lingotek-translation_settings&sm=content' ) . '">',
15
  '</a>'
16
  )
17
  );
18
+ } else {
 
19
  $string_actions = $GLOBALS['wp_lingotek']->string_actions;
20
+ $table = new Lingotek_Strings_Table( $string_actions );
21
+ $action = $table->current_action();
22
+ if ( ! empty( $action ) ) {
23
+ // flush the output buffer.
24
+ ob_end_clean();
25
+ $string_actions->manage_actions( $action );
26
+ }
27
 
28
  $data = Lingotek_Model::get_strings();
29
+ foreach ( $data as $key => $row ) {
30
+ // Store the row number for convenience.
31
+ $data[ $key ]['row'] = $key;
32
+ }
33
+
34
+ $table->prepare_items( $data );
35
+ ?>
36
 
37
+ <form id="lingotek-strings" method="post" action="admin.php?page=lingotek-translation_manage&amp;noheader=true&amp;sm=string-groups">
38
+ <?php
39
+ $table->display();
40
+ ?>
41
+ </form>
42
+ <?php
43
 
44
+ foreach ( Lingotek_String_actions::$actions as $action => $strings ) {
45
+ if ( ! empty( $_GET[ 'bulk-lingotek-' . $action ] ) ) {
46
+ printf( '<div id="lingotek-progressdialog" title="%s"><div id="lingotek-progressbar"></div></div>', $strings['progress'] );
47
+ }
48
  }
49
+ }//end if
admin/manage/view-strings.php CHANGED
@@ -1,4 +1,4 @@
1
- <h3 style="padding-top:10px; margin-top:10px; margin-bottom:-25px;"><?php _e('Strings', 'lingotek-translation'); ?> <a href="admin.php?page=mlang_strings" title="<?php _e('Edit on Polylang Strings Translation page', 'lingotek-translation'); ?>" class="dashicons dashicons-edit"></a></h3>
2
 
3
  <?php
4
  $listlanguages = $GLOBALS['polylang']->model->get_languages_list();
@@ -8,42 +8,49 @@ $listlanguages = $GLOBALS['polylang']->model->get_languages_list();
8
  // get the strings to translate
9
  $data = PLL_Admin_Strings::get_strings();
10
 
11
- $selected = empty($_REQUEST['group']) ? -1 : $_REQUEST['group'];
12
- foreach ($data as $key=>$row) {
13
- $groups[] = $row['context']; // get the groups
 
14
 
15
  // filter for search string
16
- if (($selected !=-1 && $row['context'] != $selected) || (!empty($_REQUEST['s']) && stripos($row['name'], $_REQUEST['s']) === false && stripos($row['string'], $_REQUEST['s']) === false))
17
- unset ($data[$key]);
 
18
  }
19
 
20
- $groups = array_unique($groups);
21
 
22
  // load translations
23
- foreach ($listlanguages as $language) {
24
  // filters by language if requested
25
- if (($lg = get_user_meta(get_current_user_id(), 'pll_filter_content', true)) && $language->slug != $lg)
26
  continue;
 
27
 
28
  $mo = new PLL_MO();
29
- $mo->import_from_db($language);
30
- foreach ($data as $key=>$row) {
31
- $data[$key]['translations'][$language->slug] = $mo->translate($row['string']);
32
- $data[$key]['row'] = $key; // store the row number for convenience
 
33
  }
34
  }
35
 
36
  // get an array with language slugs as keys, names as values
37
- $languages = array_combine(wp_list_pluck($listlanguages, 'slug'), wp_list_pluck($listlanguages, 'name'));
38
 
39
- $string_table = new Lingotek_Table_String(compact('languages', 'groups', 'selected'));
40
- $string_table->prepare_items($data); ?>
 
41
 
42
  <div class="form-wrap">
43
  <form id="string-translation" method="post" action="admin.php?page=mlang_strings&amp;noheader=true">
44
- <input type="hidden" name="pll_action" value="string-translation" /><?php
45
- $string_table->search_box(__('Search translations', 'lingotek-translation'), 'translations' );
46
- wp_nonce_field('string-translation', '_wpnonce_string-translation');
47
- $string_table->display(); ?>
 
 
48
  </form>
49
  </div>
1
+ <h3 style="padding-top:10px; margin-top:10px; margin-bottom:-25px;"><?php _e( 'Strings', 'lingotek-translation' ); ?> <a href="admin.php?page=mlang_strings" title="<?php _e( 'Edit on Polylang Strings Translation page', 'lingotek-translation' ); ?>" class="dashicons dashicons-edit"></a></h3>
2
 
3
  <?php
4
  $listlanguages = $GLOBALS['polylang']->model->get_languages_list();
8
  // get the strings to translate
9
  $data = PLL_Admin_Strings::get_strings();
10
 
11
+ $selected = empty( $_REQUEST['group'] ) ? -1 : $_REQUEST['group'];
12
+ foreach ( $data as $key => $row ) {
13
+ // get the groups
14
+ $groups[] = $row['context'];
15
 
16
  // filter for search string
17
+ if ( ( $selected != -1 && $row['context'] != $selected ) || ( ! empty( $_REQUEST['s'] ) && stripos( $row['name'], $_REQUEST['s'] ) === false && stripos( $row['string'], $_REQUEST['s'] ) === false ) ) {
18
+ unset( $data[ $key ] );
19
+ }
20
  }
21
 
22
+ $groups = array_unique( $groups );
23
 
24
  // load translations
25
+ foreach ( $listlanguages as $language ) {
26
  // filters by language if requested
27
+ if ( ( $lg = get_user_meta( get_current_user_id(), 'pll_filter_content', true ) ) && $language->slug != $lg ) {
28
  continue;
29
+ }
30
 
31
  $mo = new PLL_MO();
32
+ $mo->import_from_db( $language );
33
+ foreach ( $data as $key => $row ) {
34
+ $data[ $key ]['translations'][ $language->slug ] = $mo->translate( $row['string'] );
35
+ // Store the row number for convenience.
36
+ $data[ $key ]['row'] = $key;
37
  }
38
  }
39
 
40
  // get an array with language slugs as keys, names as values
41
+ $languages = array_combine( wp_list_pluck( $listlanguages, 'slug' ), wp_list_pluck( $listlanguages, 'name' ) );
42
 
43
+ $string_table = new Lingotek_Table_String( compact( 'languages', 'groups', 'selected' ) );
44
+ $string_table->prepare_items( $data );
45
+ ?>
46
 
47
  <div class="form-wrap">
48
  <form id="string-translation" method="post" action="admin.php?page=mlang_strings&amp;noheader=true">
49
+ <input type="hidden" name="pll_action" value="string-translation" />
50
+ <?php
51
+ $string_table->search_box( __( 'Search translations', 'lingotek-translation' ), 'translations' );
52
+ wp_nonce_field( 'string-translation', '_wpnonce_string-translation' );
53
+ $string_table->display();
54
+ ?>
55
  </form>
56
  </div>
admin/post-actions.php CHANGED
@@ -6,7 +6,7 @@
6
  *
7
  * @since 0.2
8
  */
9
- class Lingotek_Post_actions extends Lingotek_Actions {
10
 
11
  /**
12
  * Constructor
@@ -16,30 +16,26 @@ class Lingotek_Post_actions extends Lingotek_Actions {
16
  public function __construct() {
17
  parent::__construct( 'post' );
18
 
19
- // row actions.
20
  add_filter( 'post_row_actions', array( &$this, 'post_row_actions' ), 10, 2 );
21
- add_filter( 'page_row_actions', array( &$this, 'post_row_actions' ), 10, 2 ); // hierarchical post types.
 
22
  add_filter( 'media_row_actions', array( &$this, 'post_row_actions' ), 10, 2 );
23
 
24
  // add bulk actions.
25
  add_filter( 'bulk_actions-edit-post', array( &$this, 'add_bulk_actions' ) );
26
  add_filter( 'bulk_actions-edit-page', array( &$this, 'add_bulk_actions' ) );
27
 
28
- foreach(PLL()->model->get_translated_taxonomies() as $taxonomy) {
29
  add_filter( "bulk_actions-edit-$taxonomy", array( &$this, 'add_bulk_actions' ) );
30
  }
31
- // add_filter( 'bulk_actions-edit-category', array( &$this, 'add_bulk_actions' ) );
32
 
33
  $polylang_enabled = PLL()->model->get_translated_post_types();
34
- $custom_post_types = get_post_types( array( '_builtin' => false ) );
35
- unset( $custom_post_types[ 'polylang_mo' ] );
36
 
37
- foreach ( $custom_post_types as $type )
38
- {
39
- if (isset($polylang_enabled[$type]))
40
- {
41
- add_filter( "bulk_actions-edit-$type", array( &$this, 'add_bulk_actions' ) );
42
- }
43
  }
44
 
45
  // manage bulk actions, row actions and icon actions.
@@ -113,22 +109,23 @@ class Lingotek_Post_actions extends Lingotek_Actions {
113
  }
114
 
115
  public function manage_promotions() {
116
- if (null !== filter_input(INPUT_GET, 'ltk-promotion') && 'dismiss' === filter_input(INPUT_GET, 'ltk-promotion')) {
117
- update_option('lingotek_professional_promotion_shown', true, false);
118
- } else if (null !== filter_input(INPUT_GET, 'ltk-promotion') && 'view' === filter_input(INPUT_GET, 'ltk-promotion')) {
119
- update_option('lingotek_professional_promotion_shown', true, false);
120
  wp_safe_redirect( 'admin.php?page=lingotek-translation_tutorial&sm=content&tutorial=ltk-prof#ltk-prof-trans-header' );
121
  die();
122
  }
123
  function lingotek_professional_translation_notice() {
124
- echo sprintf( '<div style="height: 45px;" class="notice notice-success"><p>%s <a style="float:right;" class="button" href="%s" >Dismiss</a><a style="float:right; margin-right: 6px;" class="button button-primary" href="%s" >Learn More</a></p></div>',
125
- __( '<b>NEW FEATURE!</b> Lingotek Professional Translation is now available.', 'lingotek-translation' ),
126
- admin_url( 'edit.php?ltk-promotion=dismiss' ),
127
- admin_url( 'edit.php?ltk-promotion=view' )
 
 
128
  );
129
  }
130
- // update_option('lingotek_professional_promotion_shown', false);
131
- if (!get_option('lingotek_professional_promotion_shown')) {
132
  add_action( 'admin_notices', 'lingotek_professional_translation_notice' );
133
  }
134
  }
@@ -149,7 +146,7 @@ class Lingotek_Post_actions extends Lingotek_Actions {
149
  // get the action.
150
  // $typenow is empty for media.
151
  $wp_list_table = _get_list_table( empty( $typenow ) ? 'WP_Media_List_Table' : 'WP_Posts_List_Table' );
152
- $action = $wp_list_table->current_action();
153
 
154
  if ( empty( $action ) ) {
155
  return;
@@ -162,7 +159,7 @@ class Lingotek_Post_actions extends Lingotek_Actions {
162
 
163
  switch ( $action ) {
164
  case 'bulk-lingotek-upload':
165
- $type = empty( $typenow ) ? 'media' : 'post';
166
  $filtered_get = filter_input_array( INPUT_GET );
167
  if ( ! isset( $filtered_get[ $type ] ) ) {
168
  return;
@@ -174,13 +171,13 @@ class Lingotek_Post_actions extends Lingotek_Actions {
174
  // safe upload.
175
  if ( $this->lgtm->can_upload( 'post', $post_id ) ) {
176
  $post_ids[] = $post_id;
177
- } // the document is already translated so will be overwritten.
178
- elseif ( ($document = $this->lgtm->get_group( 'post', $post_id )) && empty( $document->source ) ) {
179
  // take care to upload only one post in a translation group.
180
  $intersect = array_intersect( $post_ids, PLL()->model->post->get_translations( $post_id ) );
181
  if ( empty( $intersect ) ) {
182
  $post_ids[] = $post_id;
183
- $redirect = add_query_arg( 'lingotek_warning', 1, $redirect );
184
  }
185
  }
186
  }
@@ -189,7 +186,7 @@ class Lingotek_Post_actions extends Lingotek_Actions {
189
  if ( ! empty( $post_ids ) ) {
190
  foreach ( $post_ids as $key => $post_id ) {
191
  $language = PLL()->model->post->get_language( $post_id );
192
- $profile = Lingotek_Model::get_profile( $post_type, $language );
193
  if ( 'disabled' === $profile['profile'] ) {
194
  unset( $post_ids[ $key ] );
195
  }
@@ -202,7 +199,7 @@ class Lingotek_Post_actions extends Lingotek_Actions {
202
  case 'bulk-lingotek-delete':
203
  case 'bulk-lingotek-cancel':
204
  if ( empty( $post_ids ) ) {
205
- $type = empty( $typenow ) ? 'media' : 'post';
206
  $filtered_get = filter_input_array( INPUT_GET );
207
  if ( ! isset( $filtered_get[ $type ] ) ) {
208
  return;
@@ -210,41 +207,41 @@ class Lingotek_Post_actions extends Lingotek_Actions {
210
 
211
  $post_ids = array_map( 'intval', $filtered_get[ $type ] );
212
  }
213
-
214
  empty( $typenow ) ? check_admin_referer( 'bulk-media' ) : check_admin_referer( 'bulk-posts' );
215
- if( $action == 'bulk-lingotek-cancel' || $action == 'bulk-lingotek-delete'){
216
  $redirect = add_query_arg( 'lingotek_remove', 1, $redirect );
217
  }
218
  $redirect = add_query_arg( $action, 1, $redirect );
219
  $redirect = add_query_arg( 'ids', implode( ',', $post_ids ), $redirect );
220
  break;
221
-
222
  case 'lingotek-upload':
223
  check_admin_referer( 'lingotek-upload' );
224
- $id = filter_input( INPUT_GET, 'post');
225
- $document = $this->lgtm->get_group('post', $id);
226
- $this->lgtm->upload_post($id);
227
- $redirect = add_query_arg( 'id', $id, $redirect);
228
- $redirect = add_query_arg( 'type', 'post', $redirect);
229
- $redirect = add_query_arg( 'source', $this->pllm->post->get_language($id)->locale, $redirect);
230
  break;
231
 
232
  case 'lingotek-copy':
233
  check_admin_referer( 'lingotek-copy' );
234
  $post_to_copy = get_post( (int) filter_input( INPUT_GET, 'post' ) );
235
- $target = filter_input( INPUT_GET, 'target' );
236
  $this->lgtm->copy_post( $post_to_copy, $target );
237
  break;
238
-
239
  default:
240
  if ( ! $this->_manage_actions( $action ) ) {
241
- return; // do not redirect if this is not one of our actions.
 
242
  }
243
- }
244
 
245
  wp_safe_redirect( $redirect );
246
  exit();
247
-
248
  }
249
 
250
  /**
@@ -254,15 +251,15 @@ class Lingotek_Post_actions extends Lingotek_Actions {
254
  */
255
  public function ajax_upload() {
256
  check_ajax_referer( 'lingotek_progress', '_lingotek_nonce' );
257
- $id = (int)filter_input(INPUT_POST, 'id');
258
- $wp_locales = json_decode(filter_input( INPUT_POST, 'locales'));
259
- if (isset($wp_locales)) {
260
- $lingotek_locales = array_map('Lingotek::map_to_lingotek_locale', $wp_locales);
261
- $lingotek_locales = array('translation_locale_code' => $lingotek_locales);
262
- $wp_locales = array_map(array($this->pllm, 'get_language'), $wp_locales);
263
- $wp_locales = array_column($wp_locales, 'locale');
264
  }
265
- $this->lgtm->upload_post($id);
266
  die();
267
  }
268
 
@@ -273,33 +270,31 @@ class Lingotek_Post_actions extends Lingotek_Actions {
273
  */
274
  public function lingotek_add_meta_boxes() {
275
  global $post;
276
- $lgtm = new Lingotek_Model();
277
  $group = $lgtm->get_group( $post->post_type, $post->ID );
278
 
279
  // if it's a new page, $group will be null, so don't check if it's a source page.
280
  if ( $group ) {
281
  $desc_array = $group->desc_array;
282
- $source_id = $desc_array['lingotek']['source'];
283
  // only display the meta box if it's a source.
284
  if ( isset( $desc_array['lingotek']['source'] ) && $post->ID !== $source_id ) {
285
  return;
286
  }
287
  }
288
 
289
- $polylang_enabled = PLL()->model->get_translated_post_types();
290
  $custom_post_types = get_post_types( array( '_builtin' => false ) );
291
- unset( $custom_post_types[ 'polylang_mo' ] );
292
 
293
- foreach ( $custom_post_types as $type )
294
- {
295
- if (isset($polylang_enabled[$type]))
296
- {
297
- add_meta_box('lingotek_post_meta_box', __('Lingotek Translation', 'lingotek-translation'), array( __CLASS__, 'lingotek_edit_meta_box_html'), $type, 'side', 'default');
298
  }
299
  }
300
 
301
- add_meta_box('lingotek_post_meta_box', __('Lingotek Translation', 'lingotek-translation'), array( __CLASS__, 'lingotek_edit_meta_box_html'), 'post', 'side', 'default');
302
- add_meta_box('lingotek_page_meta_box', __('Lingotek Translation', 'lingotek-translation'), array( __CLASS__, 'lingotek_edit_meta_box_html'), 'page', 'side', 'default');
303
  }
304
 
305
  /**
@@ -308,61 +303,64 @@ class Lingotek_Post_actions extends Lingotek_Actions {
308
  * @since 0.1
309
  */
310
  public static function lingotek_edit_meta_box_html() {
311
- wp_enqueue_script( 'lingotek_defaults', LINGOTEK_URL . '/js/defaults.js' );
312
 
313
  global $post;
314
- $post_type = get_post_type( $post->ID );
315
- $lgtm = new Lingotek_Model();
316
- $group = $lgtm->get_group( 'post', $post->ID );
317
- $profiles = Lingotek::get_profiles();
318
- $content_profiles = get_option('lingotek_content_type');
319
- $language_profiles = self::retrieve_lang_Profiles($post_type, $profiles, $content_profiles);
320
- $default_name = empty($content_profiles) == false ? $profiles[$content_profiles[$post->post_type]['profile']]['name'] : __('Manual', 'lingotek-translation');
321
- if ( ! isset( $default_name ) || 'disabled' === $default_name )
322
- {
323
- echo esc_html( __('You must enable translation for this content type in Lingotek\'s Content Type Configuration to enable Translation Profiles.', 'lingotek-translation') );
324
  return;
325
  }
326
- $content_default_profile = array('default' => array(
327
- 'name' => __('Content Default', 'lingotek-translation') . ' (' . $default_name . ')', // Adds in the name of the content type default profile
328
- ));
 
 
 
329
 
330
  $language_profiles['defaults'] = array(
331
  'content_default' => $default_name,
332
- 'title' => __( 'Content Default', 'lingotek-translation' ),
333
  );
334
- $profiles = array_merge( $content_default_profile, $profiles );
335
- $post_profile = self::get_post_profile( $post->ID );
336
  if ( isset( $post_profile ) ) {
337
  $selected[ $post_profile->description ] = $profiles[ $post_profile->description ];
338
  unset( $profiles[ $post_profile->description ] );
339
  $profiles = array_merge( $selected, $profiles );
340
  }
341
 
342
- if ( isset( $group->source ) ) { // Disables selection of a different profile if content has been uploaded to Lingotek.
 
343
  $args = array(
344
  'document_id' => $group->document_id,
345
- 'action' => 'lingotek-delete',
346
- 'noheader' => true,
347
  );
348
- if ( $post_type === 'page' ) {
349
  $args['lingotek_redirect'] = true;
350
  }
351
- $site_id = get_current_blog_id();
352
- $url = $post_type === 'page' ? get_site_url( $site_id, '/wp-admin/edit.php?post_type=page' ) : get_site_url( $site_id, '/wp-admin/edit.php' );
353
  $disassociate_url = wp_nonce_url( add_query_arg( $args, $url ), 'lingotek-delete' );
354
- $remove_post = 'post=' . $post->ID;
355
  $disassociate_url = str_replace( $remove_post, '', $disassociate_url );
356
- $confirm_message = __( 'Are you sure you want to do this?', 'lingotek-translation' );
357
- $confirm_message = sprintf( ' onclick = "return confirm(\'%s\');"', esc_html( $confirm_message ) );
358
  printf( '<strong>%s</strong><br><br>', esc_html( __( 'Translation Profile', 'lingotek-translation' ) ) );
359
  printf( '<em>%s</em><br>', esc_html( __( 'Delete this content from your Lingotek community to change the Translation Profile', 'lingotek-translation' ) ) );
360
- printf( ('<a class="button button-small" href="%s" %s>%s</a><br><br>'), esc_url( $disassociate_url ), esc_html( $confirm_message ), esc_html( __( 'Delete', 'lingotek-translation' ) ) );
361
  printf( '<select disabled class="lingotek-profile-setting" name="%1$s" id="%1$s">', esc_html( 'lingotek_profile_meta' ) );
362
  } else {
363
  printf( '<strong>%s</strong><br><br>', esc_html( __( 'Translation Profile', 'lingotek-translation' ) ) );
364
  printf( '<select class="lingotek-profile-setting" name="%1$s" id="%1$s">', 'lingotek_profile_meta' );
365
- }
366
 
367
  foreach ( $profiles as $key => $profile ) {
368
  echo "\n\t<option value=" . esc_attr( $key ) . '>' . esc_attr( $profile['name'] ) . '</option>';
@@ -377,15 +375,15 @@ class Lingotek_Post_actions extends Lingotek_Actions {
377
  }
378
 
379
  global $post;
380
- $profile_choice = filter_input( INPUT_POST, 'lingotek_profile_meta' );
381
- $document_id = 'lingotek_profile_' . $post->ID;
382
- $term = self::get_post_profile( $post->ID );
383
- $post_language = $this->get_language( $post->ID );
384
  $content_profiles = get_option( 'lingotek_content_type' );
385
 
386
- if ( $profile_choice === 'default' && ! empty( $term ) ) {
387
  wp_delete_term( (int) $term->term_id, 'lingotek_profile' );
388
- } elseif ( $profile_choice !== 'default' ) {
389
  if ( empty( $term ) ) {
390
  wp_insert_term( $document_id, 'lingotek_profile', array( 'description' => $profile_choice ) );
391
  } else {
6
  *
7
  * @since 0.2
8
  */
9
+ class Lingotek_Post_Actions extends Lingotek_Actions {
10
 
11
  /**
12
  * Constructor
16
  public function __construct() {
17
  parent::__construct( 'post' );
18
 
19
+ // Row actions.
20
  add_filter( 'post_row_actions', array( &$this, 'post_row_actions' ), 10, 2 );
21
+ // Hierarchical post types.
22
+ add_filter( 'page_row_actions', array( &$this, 'post_row_actions' ), 10, 2 );
23
  add_filter( 'media_row_actions', array( &$this, 'post_row_actions' ), 10, 2 );
24
 
25
  // add bulk actions.
26
  add_filter( 'bulk_actions-edit-post', array( &$this, 'add_bulk_actions' ) );
27
  add_filter( 'bulk_actions-edit-page', array( &$this, 'add_bulk_actions' ) );
28
 
29
+ foreach ( PLL()->model->get_translated_taxonomies() as $taxonomy ) {
30
  add_filter( "bulk_actions-edit-$taxonomy", array( &$this, 'add_bulk_actions' ) );
31
  }
 
32
 
33
  $polylang_enabled = PLL()->model->get_translated_post_types();
34
+ // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
35
+ $polylang_enabled = apply_filters( 'pll_get_post_types', $polylang_enabled, false );
36
 
37
+ foreach ( $polylang_enabled as $type ) {
38
+ add_filter( "bulk_actions-edit-$type", array( &$this, 'add_bulk_actions' ) );
 
 
 
 
39
  }
40
 
41
  // manage bulk actions, row actions and icon actions.
109
  }
110
 
111
  public function manage_promotions() {
112
+ if ( null !== filter_input( INPUT_GET, 'ltk-promotion' ) && 'dismiss' === filter_input( INPUT_GET, 'ltk-promotion' ) ) {
113
+ update_option( 'lingotek_professional_promotion_shown', true, false );
114
+ } elseif ( null !== filter_input( INPUT_GET, 'ltk-promotion' ) && 'view' === filter_input( INPUT_GET, 'ltk-promotion' ) ) {
115
+ update_option( 'lingotek_professional_promotion_shown', true, false );
116
  wp_safe_redirect( 'admin.php?page=lingotek-translation_tutorial&sm=content&tutorial=ltk-prof#ltk-prof-trans-header' );
117
  die();
118
  }
119
  function lingotek_professional_translation_notice() {
120
+ echo sprintf(
121
+ '<div style="height: 45px;" class="notice notice-success"><p><b>%s</b>%s <a style="float:right;" class="button" href="%s" >Dismiss</a><a style="float:right; margin-right: 6px;" class="button button-primary" href="%s" >Learn More</a></p></div>',
122
+ esc_html__( 'NEW FEATURE!', 'lingotek-translation' ),
123
+ esc_html__( 'Lingotek Professional Translation is now available.', 'lingotek-translation' ),
124
+ esc_url( admin_url( 'edit.php?ltk-promotion=dismiss' ) ),
125
+ esc_url( admin_url( 'edit.php?ltk-promotion=view' ) )
126
  );
127
  }
128
+ if ( ! get_option( 'lingotek_professional_promotion_shown' ) ) {
 
129
  add_action( 'admin_notices', 'lingotek_professional_translation_notice' );
130
  }
131
  }
146
  // get the action.
147
  // $typenow is empty for media.
148
  $wp_list_table = _get_list_table( empty( $typenow ) ? 'WP_Media_List_Table' : 'WP_Posts_List_Table' );
149
+ $action = $wp_list_table->current_action();
150
 
151
  if ( empty( $action ) ) {
152
  return;
159
 
160
  switch ( $action ) {
161
  case 'bulk-lingotek-upload':
162
+ $type = empty( $typenow ) ? 'media' : 'post';
163
  $filtered_get = filter_input_array( INPUT_GET );
164
  if ( ! isset( $filtered_get[ $type ] ) ) {
165
  return;
171
  // safe upload.
172
  if ( $this->lgtm->can_upload( 'post', $post_id ) ) {
173
  $post_ids[] = $post_id;
174
+ // phpcs:ignore WordPress.CodeAnalysis.AssignmentInCondition.Found,Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure
175
+ } elseif ( ( $document = $this->lgtm->get_group( 'post', $post_id ) ) && empty( $document->source ) ) {
176
  // take care to upload only one post in a translation group.
177
  $intersect = array_intersect( $post_ids, PLL()->model->post->get_translations( $post_id ) );
178
  if ( empty( $intersect ) ) {
179
  $post_ids[] = $post_id;
180
+ $redirect = add_query_arg( 'lingotek_warning', 1, $redirect );
181
  }
182
  }
183
  }
186
  if ( ! empty( $post_ids ) ) {
187
  foreach ( $post_ids as $key => $post_id ) {
188
  $language = PLL()->model->post->get_language( $post_id );
189
+ $profile = Lingotek_Model::get_profile( $post_type, $language );
190
  if ( 'disabled' === $profile['profile'] ) {
191
  unset( $post_ids[ $key ] );
192
  }
199
  case 'bulk-lingotek-delete':
200
  case 'bulk-lingotek-cancel':
201
  if ( empty( $post_ids ) ) {
202
+ $type = empty( $typenow ) ? 'media' : 'post';
203
  $filtered_get = filter_input_array( INPUT_GET );
204
  if ( ! isset( $filtered_get[ $type ] ) ) {
205
  return;
207
 
208
  $post_ids = array_map( 'intval', $filtered_get[ $type ] );
209
  }
210
+
211
  empty( $typenow ) ? check_admin_referer( 'bulk-media' ) : check_admin_referer( 'bulk-posts' );
212
+ if ( in_array( $action, array( 'bulk-lingotek-cancel', 'bulk-lingotek-delete' ), true ) ) {
213
  $redirect = add_query_arg( 'lingotek_remove', 1, $redirect );
214
  }
215
  $redirect = add_query_arg( $action, 1, $redirect );
216
  $redirect = add_query_arg( 'ids', implode( ',', $post_ids ), $redirect );
217
  break;
218
+
219
  case 'lingotek-upload':
220
  check_admin_referer( 'lingotek-upload' );
221
+ $id = filter_input( INPUT_GET, 'post' );
222
+ $document = $this->lgtm->get_group( 'post', $id );
223
+ $this->lgtm->upload_post( $id );
224
+ $redirect = add_query_arg( 'id', $id, $redirect );
225
+ $redirect = add_query_arg( 'type', 'post', $redirect );
226
+ $redirect = add_query_arg( 'source', $this->pllm->post->get_language( $id )->locale, $redirect );
227
  break;
228
 
229
  case 'lingotek-copy':
230
  check_admin_referer( 'lingotek-copy' );
231
  $post_to_copy = get_post( (int) filter_input( INPUT_GET, 'post' ) );
232
+ $target = filter_input( INPUT_GET, 'target' );
233
  $this->lgtm->copy_post( $post_to_copy, $target );
234
  break;
235
+
236
  default:
237
  if ( ! $this->_manage_actions( $action ) ) {
238
+ // Do not redirect if this is not one of our actions.
239
+ return;
240
  }
241
+ }//end switch
242
 
243
  wp_safe_redirect( $redirect );
244
  exit();
 
245
  }
246
 
247
  /**
251
  */
252
  public function ajax_upload() {
253
  check_ajax_referer( 'lingotek_progress', '_lingotek_nonce' );
254
+ $id = (int) filter_input( INPUT_POST, 'id' );
255
+ $wp_locales = json_decode( filter_input( INPUT_POST, 'locales' ) );
256
+ if ( isset( $wp_locales ) ) {
257
+ $lingotek_locales = array_map( 'Lingotek::map_to_lingotek_locale', $wp_locales );
258
+ $lingotek_locales = array( 'translation_locale_code' => $lingotek_locales );
259
+ $wp_locales = array_map( array( $this->pllm, 'get_language' ), $wp_locales );
260
+ $wp_locales = array_column( $wp_locales, 'locale' );
261
  }
262
+ $this->lgtm->upload_post( $id );
263
  die();
264
  }
265
 
270
  */
271
  public function lingotek_add_meta_boxes() {
272
  global $post;
273
+ $lgtm = new Lingotek_Model();
274
  $group = $lgtm->get_group( $post->post_type, $post->ID );
275
 
276
  // if it's a new page, $group will be null, so don't check if it's a source page.
277
  if ( $group ) {
278
  $desc_array = $group->desc_array;
279
+ $source_id = $desc_array['lingotek']['source'];
280
  // only display the meta box if it's a source.
281
  if ( isset( $desc_array['lingotek']['source'] ) && $post->ID !== $source_id ) {
282
  return;
283
  }
284
  }
285
 
286
+ $polylang_enabled = PLL()->model->get_translated_post_types();
287
  $custom_post_types = get_post_types( array( '_builtin' => false ) );
288
+ unset( $custom_post_types['polylang_mo'] );
289
 
290
+ foreach ( $custom_post_types as $type ) {
291
+ if ( isset( $polylang_enabled[ $type ] ) ) {
292
+ add_meta_box( 'lingotek_post_meta_box', __( 'Lingotek Translation', 'lingotek-translation' ), array( __CLASS__, 'lingotek_edit_meta_box_html' ), $type, 'side', 'default' );
 
 
293
  }
294
  }
295
 
296
+ add_meta_box( 'lingotek_post_meta_box', __( 'Lingotek Translation', 'lingotek-translation' ), array( __CLASS__, 'lingotek_edit_meta_box_html' ), 'post', 'side', 'default' );
297
+ add_meta_box( 'lingotek_page_meta_box', __( 'Lingotek Translation', 'lingotek-translation' ), array( __CLASS__, 'lingotek_edit_meta_box_html' ), 'page', 'side', 'default' );
298
  }
299
 
300
  /**
303
  * @since 0.1
304
  */
305
  public static function lingotek_edit_meta_box_html() {
306
+ wp_enqueue_script( 'lingotek_defaults', LINGOTEK_URL . '/js/defaults.js', array(), LINGOTEK_VERSION, false );
307
 
308
  global $post;
309
+ $post_type = get_post_type( $post->ID );
310
+ $lgtm = new Lingotek_Model();
311
+ $group = $lgtm->get_group( 'post', $post->ID );
312
+ $profiles = Lingotek::get_profiles();
313
+ $content_profiles = get_option( 'lingotek_content_type' );
314
+ $language_profiles = self::retrieve_lang_Profiles( $post_type, $profiles, $content_profiles );
315
+ $default_name = ! empty( $content_profiles ) ? $profiles[ $content_profiles[ $post->post_type ]['profile'] ]['name'] : __( 'Manual', 'lingotek-translation' );
316
+ if ( ! isset( $default_name ) || 'disabled' === $default_name ) {
317
+ echo esc_html( __( 'You must enable translation for this content type in Lingotek\'s Content Type Configuration to enable Translation Profiles.', 'lingotek-translation' ) );
 
318
  return;
319
  }
320
+ $content_default_profile = array(
321
+ 'default' => array(
322
+ // Adds in the name of the content type default profile.
323
+ 'name' => __( 'Content Default', 'lingotek-translation' ) . ' (' . $default_name . ')',
324
+ ),
325
+ );
326
 
327
  $language_profiles['defaults'] = array(
328
  'content_default' => $default_name,
329
+ 'title' => __( 'Content Default', 'lingotek-translation' ),
330
  );
331
+ $profiles = array_merge( $content_default_profile, $profiles );
332
+ $post_profile = self::get_post_profile( $post->ID );
333
  if ( isset( $post_profile ) ) {
334
  $selected[ $post_profile->description ] = $profiles[ $post_profile->description ];
335
  unset( $profiles[ $post_profile->description ] );
336
  $profiles = array_merge( $selected, $profiles );
337
  }
338
 
339
+ // Disables selection of a different profile if content has been uploaded to Lingotek.
340
+ if ( isset( $group->source ) ) {
341
  $args = array(
342
  'document_id' => $group->document_id,
343
+ 'action' => 'lingotek-delete',
344
+ 'noheader' => true,
345
  );
346
+ if ( 'page' === $post_type ) {
347
  $args['lingotek_redirect'] = true;
348
  }
349
+ $site_id = get_current_blog_id();
350
+ $url = 'page' === $post_type ? get_site_url( $site_id, '/wp-admin/edit.php?post_type=page' ) : get_site_url( $site_id, '/wp-admin/edit.php' );
351
  $disassociate_url = wp_nonce_url( add_query_arg( $args, $url ), 'lingotek-delete' );
352
+ $remove_post = 'post=' . $post->ID;
353
  $disassociate_url = str_replace( $remove_post, '', $disassociate_url );
354
+ $confirm_message = __( 'Are you sure you want to do this?', 'lingotek-translation' );
355
+ $confirm_message = sprintf( ' onclick = "return confirm(\'%s\');"', esc_html( $confirm_message ) );
356
  printf( '<strong>%s</strong><br><br>', esc_html( __( 'Translation Profile', 'lingotek-translation' ) ) );
357
  printf( '<em>%s</em><br>', esc_html( __( 'Delete this content from your Lingotek community to change the Translation Profile', 'lingotek-translation' ) ) );
358
+ printf( ( '<a class="button button-small" href="%s" %s>%s</a><br><br>' ), esc_url( $disassociate_url ), esc_html( $confirm_message ), esc_html( __( 'Delete', 'lingotek-translation' ) ) );
359
  printf( '<select disabled class="lingotek-profile-setting" name="%1$s" id="%1$s">', esc_html( 'lingotek_profile_meta' ) );
360
  } else {
361
  printf( '<strong>%s</strong><br><br>', esc_html( __( 'Translation Profile', 'lingotek-translation' ) ) );
362
  printf( '<select class="lingotek-profile-setting" name="%1$s" id="%1$s">', 'lingotek_profile_meta' );
363
+ }//end if
364
 
365
  foreach ( $profiles as $key => $profile ) {
366
  echo "\n\t<option value=" . esc_attr( $key ) . '>' . esc_attr( $profile['name'] ) . '</option>';
375
  }
376
 
377
  global $post;
378
+ $profile_choice = filter_input( INPUT_POST, 'lingotek_profile_meta' );
379
+ $document_id = 'lingotek_profile_' . $post->ID;
380
+ $term = self::get_post_profile( $post->ID );
381
+ $post_language = $this->get_language( $post->ID );
382
  $content_profiles = get_option( 'lingotek_content_type' );
383
 
384
+ if ( 'default' === $profile_choice && ! empty( $term ) ) {
385
  wp_delete_term( (int) $term->term_id, 'lingotek_profile' );
386
+ } elseif ( 'default' !== $profile_choice ) {
387
  if ( empty( $term ) ) {
388
  wp_insert_term( $document_id, 'lingotek_profile', array( 'description' => $profile_choice ) );
389
  } else {
admin/profiles-table.php CHANGED
@@ -1,7 +1,8 @@
1
  <?php
2
 
3
  if ( ! class_exists( 'WP_List_Table' ) ) {
4
- require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' ); // since WP 3.1.
 
5
  }
6
 
7
  /**
@@ -14,11 +15,14 @@ class Lingotek_Profiles_Table extends WP_List_Table {
14
  *
15
  * @since 0.2
16
  */
17
- function __construct() {
18
- parent::__construct(array(
19
- 'plural' => 'lingotek-profiles', // do not translate (used for css class).
20
- 'ajax' => false,
21
- ));
 
 
 
22
  }
23
 
24
  /**
@@ -30,7 +34,7 @@ class Lingotek_Profiles_Table extends WP_List_Table {
30
  * @param string $column_name column.
31
  * @return string
32
  */
33
- function column_default( $item, $column_name ) {
34
  return isset( $item[ $column_name ] ) ? esc_html( $item[ $column_name ] ) : '';
35
  }
36
 
@@ -42,9 +46,10 @@ class Lingotek_Profiles_Table extends WP_List_Table {
42
  * @param array $item item.
43
  * @return string
44
  */
45
- function column_usage( $item ) {
46
  return empty( $item['usage'] ) ?
47
  __( 'No content types', 'lingotek-translation' ) :
 
48
  sprintf( _n( '%d content type', '%d content types', $item['usage'], 'lingotek-translation' ), number_format_i18n( $item['usage'] ) );
49
  }
50
 
@@ -56,7 +61,7 @@ class Lingotek_Profiles_Table extends WP_List_Table {
56
  * @param array $item item.
57
  * @return string
58
  */
59
- function column_actions( $item ) {
60
  $actions = array();
61
 
62
  if ( 'disabled' !== $item['profile'] ) {
@@ -86,9 +91,9 @@ class Lingotek_Profiles_Table extends WP_List_Table {
86
  *
87
  * @return array the list of column titles
88
  */
89
- function get_columns() {
90
  return array(
91
- 'name' => __( 'Profile name', 'lingotek-translation' ),
92
  'usage' => __( 'Usage', 'lingotek-translation' ),
93
  'actions' => __( 'Actions', 'lingotek-translation' ),
94
  );
@@ -101,7 +106,7 @@ class Lingotek_Profiles_Table extends WP_List_Table {
101
  *
102
  * @return array
103
  */
104
- function get_sortable_columns() {
105
  return array(
106
  'name' => array( 'name', false ),
107
  );
@@ -114,8 +119,8 @@ class Lingotek_Profiles_Table extends WP_List_Table {
114
  *
115
  * @param array $data data.
116
  */
117
- function prepare_items( $data = array() ) {
118
- $per_page = $this->get_items_per_page( 'lingotek_profiles_per_page' );
119
  $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() );
120
 
121
  /**
@@ -126,23 +131,28 @@ class Lingotek_Profiles_Table extends WP_List_Table {
126
  * @return int sort direction.
127
  */
128
  function usort_reorder( $a, $b ) {
129
- $order = filter_input( INPUT_GET, 'order' );
130
  $orderby = filter_input( INPUT_GET, 'orderby' );
131
- $result = strcmp( $a[ $orderby ], $b[ $orderby ] ); // determine sort order.
132
- return (empty( $order ) || 'asc' === $order ) ? $result : -$result; // send final sort direction to usort.
 
 
133
  };
134
 
135
- if ( ! empty( $orderby ) ) { // no sort by default.
 
136
  usort( $data, 'usort_reorder' );
137
  }
138
 
139
  $total_items = count( $data );
140
- $this->items = array_slice( $data, ($this->get_pagenum() - 1) * $per_page, $per_page );
141
-
142
- $this->set_pagination_args(array(
143
- 'total_items' => $total_items,
144
- 'per_page' => $per_page,
145
- 'total_pages' => ceil( $total_items / $per_page ),
146
- ));
 
 
147
  }
148
  }
1
  <?php
2
 
3
  if ( ! class_exists( 'WP_List_Table' ) ) {
4
+ // since WP 3.1.
5
+ require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
6
  }
7
 
8
  /**
15
  *
16
  * @since 0.2
17
  */
18
+ public function __construct() {
19
+ parent::__construct(
20
+ array(
21
+ // do not translate (used for css class).
22
+ 'plural' => 'lingotek-profiles',
23
+ 'ajax' => false,
24
+ )
25
+ );
26
  }
27
 
28
  /**
34
  * @param string $column_name column.
35
  * @return string
36
  */
37
+ public function column_default( $item, $column_name ) {
38
  return isset( $item[ $column_name ] ) ? esc_html( $item[ $column_name ] ) : '';
39
  }
40
 
46
  * @param array $item item.
47
  * @return string
48
  */
49
+ protected function column_usage( $item ) {
50
  return empty( $item['usage'] ) ?
51
  __( 'No content types', 'lingotek-translation' ) :
52
+ /* translators: %d: Number of content types. */
53
  sprintf( _n( '%d content type', '%d content types', $item['usage'], 'lingotek-translation' ), number_format_i18n( $item['usage'] ) );
54
  }
55
 
61
  * @param array $item item.
62
  * @return string
63
  */
64
+ public function column_actions( $item ) {
65
  $actions = array();
66
 
67
  if ( 'disabled' !== $item['profile'] ) {
91
  *
92
  * @return array the list of column titles
93
  */
94
+ public function get_columns() {
95
  return array(
96
+ 'name' => __( 'Profile name', 'lingotek-translation' ),
97
  'usage' => __( 'Usage', 'lingotek-translation' ),
98
  'actions' => __( 'Actions', 'lingotek-translation' ),
99
  );
106
  *
107
  * @return array
108
  */
109
+ public function get_sortable_columns() {
110
  return array(
111
  'name' => array( 'name', false ),
112
  );
119
  *
120
  * @param array $data data.
121
  */
122
+ public function prepare_items( $data = array() ) {
123
+ $per_page = $this->get_items_per_page( 'lingotek_profiles_per_page' );
124
  $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() );
125
 
126
  /**
131
  * @return int sort direction.
132
  */
133
  function usort_reorder( $a, $b ) {
134
+ $order = filter_input( INPUT_GET, 'order' );
135
  $orderby = filter_input( INPUT_GET, 'orderby' );
136
+ // Determine sort order.
137
+ $result = strcmp( $a[ $orderby ], $b[ $orderby ] );
138
+ // Send final sort direction to usort.
139
+ return ( empty( $order ) || 'asc' === $order ) ? $result : -$result;
140
  };
141
 
142
+ // No sort by default.
143
+ if ( ! empty( $orderby ) ) {
144
  usort( $data, 'usort_reorder' );
145
  }
146
 
147
  $total_items = count( $data );
148
+ $this->items = array_slice( $data, ( $this->get_pagenum() - 1 ) * $per_page, $per_page );
149
+
150
+ $this->set_pagination_args(
151
+ array(
152
+ 'total_items' => $total_items,
153
+ 'per_page' => $per_page,
154
+ 'total_pages' => ceil( $total_items / $per_page ),
155
+ )
156
+ );
157
  }
158
  }
admin/settings.php CHANGED
@@ -1,5 +1,5 @@
1
  <div class="wrap">
2
- <h2><?php esc_html_e( 'Settings', 'lingotek-translation' ); ?></h2>
3
 
4
  <?php
5
  if ( strlen( $access_token ) ) {
@@ -9,13 +9,13 @@
9
  <?php
10
 
11
  $menu_items = array(
12
- 'account' => __( 'Account', 'lingotek-translation' ),
13
  );
14
 
15
  $community_required_menu_items = array(
16
- 'defaults' => __( 'Defaults', 'lingotek-translation' ),
17
- 'preferences' => __( 'Preferences', 'lingotek-translation' ),
18
- 'utilities' => __( 'Utilities', 'lingotek-translation' ),
19
  );
20
 
21
  if ( false !== $community_id ) {
@@ -28,35 +28,39 @@
28
  <?php
29
  $menu_item_index = 0;
30
  foreach ( $menu_items as $menu_item_key => $menu_item_label ) {
31
- $use_as_default = (0 === $menu_item_index && empty( $sm )) ? true : false;
32
- $alias = null;
33
  // custom sub sub-menus.
34
  if ( ! empty( $sm ) && 'edit-profile' === $sm ) {
35
  $alias = 'profiles';
36
  }
37
  ?>
38
-
39
- <a class="nav-tab <?php if ( $use_as_default || ( ! empty( $sm ) && $sm === $menu_item_key) || $alias === $menu_item_key ) : ?> nav-tab-active<?php endif; ?>"
40
- href="admin.php?page=<?php echo filter_input( INPUT_GET, 'page' ); ?>&amp;sm=<?php echo esc_html( $menu_item_key ); ?>"><?php echo esc_html( $menu_item_label ); ?></a>
 
 
 
41
  <?php
42
- $menu_item_index++;
43
  }
44
- ?>
45
  </h3>
46
 
47
  <?php
48
  settings_errors();
49
- $submenu = ! empty( $sm ) ? sanitize_text_field( $sm ) : 'account';
50
- $dir = dirname( __FILE__ ) . '/settings/';
51
  $filename = $dir . 'view-' . $submenu . '.php';
52
  if ( file_exists( $filename ) ) {
53
  include $filename;
54
- } else { echo 'TO-DO: create <i>settings/view-' . esc_html( $submenu ) . '.php</i>';
 
55
  }
56
  ?>
57
 
58
  <?php
59
- }
60
  ?>
61
  </div>
62
  <script>jQuery(document).ready(function($) { $('#wpfooter').remove(); } );</script>
1
  <div class="wrap">
2
+ <h2><?php esc_html_e( 'Settings', 'lingotek-translation' ); ?></h2>
3
 
4
  <?php
5
  if ( strlen( $access_token ) ) {
9
  <?php
10
 
11
  $menu_items = array(
12
+ 'account' => __( 'Account', 'lingotek-translation' ),
13
  );
14
 
15
  $community_required_menu_items = array(
16
+ 'defaults' => __( 'Defaults', 'lingotek-translation' ),
17
+ 'preferences' => __( 'Preferences', 'lingotek-translation' ),
18
+ 'utilities' => __( 'Utilities', 'lingotek-translation' ),
19
  );
20
 
21
  if ( false !== $community_id ) {
28
  <?php
29
  $menu_item_index = 0;
30
  foreach ( $menu_items as $menu_item_key => $menu_item_label ) {
31
+ $use_as_default = ( 0 === $menu_item_index && empty( $sm ) ) ? true : false;
32
+ $alias = null;
33
  // custom sub sub-menus.
34
  if ( ! empty( $sm ) && 'edit-profile' === $sm ) {
35
  $alias = 'profiles';
36
  }
37
  ?>
38
+ <a class="nav-tab
39
+ <?php
40
+ if ( $use_as_default || ( ! empty( $sm ) && $sm === $menu_item_key ) || $alias === $menu_item_key ) :
41
+ ?>
42
+ nav-tab-active<?php endif; ?>"
43
+ href="admin.php?page=<?php echo filter_input( INPUT_GET, 'page' ); ?>&amp;sm=<?php echo esc_html( $menu_item_key ); ?>"><?php echo esc_html( $menu_item_label ); ?></a>
44
  <?php
45
+ $menu_item_index++;
46
  }
47
+ ?>
48
  </h3>
49
 
50
  <?php
51
  settings_errors();
52
+ $submenu = ! empty( $sm ) ? sanitize_text_field( $sm ) : 'account';
53
+ $dir = dirname( __FILE__ ) . '/settings/';
54
  $filename = $dir . 'view-' . $submenu . '.php';
55
  if ( file_exists( $filename ) ) {
56
  include $filename;
57
+ } else {
58
+ echo 'TO-DO: create <i>settings/view-' . esc_html( $submenu ) . '.php</i>';
59
  }
60
  ?>
61
 
62
  <?php
63
+ }//end if
64
  ?>
65
  </div>
66
  <script>jQuery(document).ready(function($) { $('#wpfooter').remove(); } );</script>
admin/settings/connect-account.php CHANGED
@@ -30,52 +30,52 @@ jQuery(document).ready(function ($){
30
  })
31
  }
32
  } else if (window.location.search.includes("connect")) {
33
- window.location.href = "<?php echo esc_url_raw( $connect_url ) ?>";
34
  }
35
  });
36
  </script>
37
  <!-- Connect Your Account Button -->
38
  <div class="loader content" hidden></div>
39
  <div class="wrap content">
40
- <h2><?php esc_html_e( 'Connect Your Account', 'lingotek-translation' ) ?></h2>
41
  <div>
42
  <p class="description">
43
- <?php esc_html_e( 'Get started by clicking the button below to connect your Lingotek account to this Wordpress installation.', 'lingotek-translation' ) ?>
44
  </p>
45
  <hr/>
46
  <p>
47
- <a class="button button-large button-hero" href="<?php echo esc_url_raw( $connect_account_cloak_url_new ) ?>">
48
- <img src="<?php echo esc_url_raw( LINGOTEK_URL ); ?>/img/lingotek-icon.png" style="padding: 0 4px 2px 0;" align="absmiddle"/> <?php esc_html_e( 'Connect New Account', 'lingotek-translation' ) ?>
49
  </a>
50
  </p>
51
  <hr/>
52
  <p class="description">
53
  <?php
54
- $allowed_html = array(
55
- 'a' => array(
56
- 'href' => array(),
57
- ),
58
  );
59
-
60
- echo sprintf( wp_kses( __( 'Do you already have a Lingotek account? <a href="%s">Connect Lingotek Account</a>', 'lingotek-translation' ), $allowed_html ), esc_attr( $connect_account_cloak_url_prod ) )
61
- ?>
62
  </p>
63
  </div>
64
  </div>
65
  <style>
66
  .loader {
67
- border: 16px solid #dedede;
68
- border-top: 16px solid #3498db;
69
- border-radius: 50%;
70
- width: 100px;
71
- height: 100px;
72
- animation: spin 1.5s linear infinite;
73
- animation-direction: reverse;
74
- margin: 7em;
75
  }
76
 
77
  @keyframes spin {
78
- 0% { transform: rotate(0deg); }
79
- 100% { transform: rotate(360deg); }
80
  }
81
  </style>
30
  })
31
  }
32
  } else if (window.location.search.includes("connect")) {
33
+ window.location.href = "<?php echo esc_url_raw( $connect_url ); ?>";
34
  }
35
  });
36
  </script>
37
  <!-- Connect Your Account Button -->
38
  <div class="loader content" hidden></div>
39
  <div class="wrap content">
40
+ <h2><?php esc_html_e( 'Connect Your Account', 'lingotek-translation' ); ?></h2>
41
  <div>
42
  <p class="description">
43
+ <?php esc_html_e( 'Get started by clicking the button below to connect your Lingotek account to this WordPress installation.', 'lingotek-translation' ); ?>
44
  </p>
45
  <hr/>
46
  <p>
47
+ <a class="button button-large button-hero" href="<?php echo esc_url_raw( $connect_account_cloak_url_new ); ?>">
48
+ <img src="<?php echo esc_url_raw( LINGOTEK_URL ); ?>/img/lingotek-icon.png" style="padding: 0 4px 2px 0;" align="absmiddle"/> <?php esc_html_e( 'Connect New Account', 'lingotek-translation' ); ?>
49
  </a>
50
  </p>
51
  <hr/>
52
  <p class="description">
53
  <?php
54
+ $allowed_html = array(
55
+ 'a' => array(
56
+ 'href' => array(),
57
+ ),
58
  );
59
+ /* translators: %s: Connect to Lingotek url. */
60
+ echo sprintf( wp_kses( __( 'Do you already have a Lingotek account? <a href="%s">Connect Lingotek Account</a>', 'lingotek-translation' ), $allowed_html ), esc_attr( $connect_account_cloak_url_prod ) )
61
+ ?>
62
  </p>
63
  </div>
64
  </div>
65
  <style>
66
  .loader {
67
+ border: 16px solid #dedede;
68
+ border-top: 16px solid #3498db;
69
+ border-radius: 50%;
70
+ width: 100px;
71
+ height: 100px;
72
+ animation: spin 1.5s linear infinite;
73
+ animation-direction: reverse;
74
+ margin: 7em;
75
  }
76
 
77
  @keyframes spin {
78
+ 0% { transform: rotate(0deg); }
79
+ 100% { transform: rotate(360deg); }
80
  }
81
  </style>
admin/settings/view-account.php CHANGED
@@ -1,13 +1,13 @@
1
  <?php
2
- $client = new Lingotek_API();
3
  $api_communities = $client->get_communities();
4
  if ( ! isset( $api_communities->entities ) ) {
5
  add_settings_error( 'lingotek_community_resources', 'error', __( 'The Lingotek TMS is currently unavailable. Please try again later. If the problem persists, contact Lingotek Support.', 'lingotek-translation' ), 'error' );
6
  settings_errors();
7
  }
8
  if ( ! $community_id ) {
9
- $ltk_client = new Lingotek_API();
10
- $ltk_communities = $ltk_client->get_communities();
11
  $ltk_num_communities = $ltk_communities->properties->total;
12
  if ( 1 === $ltk_num_communities ) {
13
  $ltk_community_id = $ltk_communities->entities[0]->properties->id;
@@ -23,52 +23,60 @@ if ( ! $community_id ) {
23
  <table class="form-table">
24
  <tr>
25
  <th scope="row">
26
- <?php esc_html_e( 'Connected', 'lingotek-translation' ) ?>
27
- <a id="cd-show-link" class="dashicons dashicons-arrow-right" onclick="document.getElementById('connection-details').style.display = ''; document.getElementById('cd-hide-link').style.display = ''; this.style.display = 'none'; return false;"></a>
28
- <a id="cd-hide-link" class="dashicons dashicons-arrow-down" onclick="document.getElementById('connection-details').style.display = 'none'; document.getElementById('cd-show-link').style.display = ''; this.style.display = 'none'; return false;" style="display: none;"></a>
29
  </th>
30
  <td>
31
- <?php esc_html_e( 'Yes', 'lingotek-translation' ) ?><span title="<?php esc_html_e( 'Connected', 'lingotek-translation' ) ?>" class="dashicons dashicons-yes" style="color: green;"></span>
32
  </td>
33
  </tr>
34
  <tbody id="connection-details" style="display: none;">
35
  <tr>
36
- <th scope="row"><?php echo esc_html( __( 'Login ID', 'lingotek-translation' ) ) ?></th>
37
  <td>
38
- <label>
39
- <?php
40
- printf(
41
- '<input name="%s" class="regular-text" type="text" value="%s" disabled="disabled" />', 'login_id', esc_html( $token_details['login_id'] )
42
- );
43
- ?>
44
- </label>
 
 
45
  </td>
46
  </tr>
47
  <tr>
48
- <th scope="row"><?php echo esc_html( __( 'Access Token', 'lingotek-translation' ) ) ?></th>
49
  <td>
50
- <label>
51
- <?php
52
- printf(
53
- '<input name="%s" class="regular-text" type="password" value="%s" disabled="disabled" style="display: none;" />', 'access_token', esc_html( $token_details['access_token'] )
54
- );
55
- printf(
56
- '<input name="%s" class="regular-text" type="text" value="%s" disabled="disabled" />', 'access_token', esc_html( $token_details['access_token'] )
57
- );
58
- ?>
59
- </label>
 
 
 
 
60
  </td>
61
  </tr>
62
  <tr>
63
- <th scope="row"><?php echo esc_html( __( 'API Endpoint', 'lingotek-translation' ) ) ?></th>
64
  <td>
65
- <label>
66
- <?php
67
- printf(
68
- '<input name="%s" class="regular-text" type="text" value="%s" disabled="disabled" />', 'base_url', esc_html( $base_url )
69
- );
70
- ?>
71
- </label>
 
 
72
  </td>
73
  </tr>
74
  <tr>
@@ -90,73 +98,73 @@ if ( ! $community_id ) {
90
 
91
  <table class="form-table">
92
  <tr>
93
- <th scope="row"><label for="lingotek_community"><?php esc_html_e( 'Community', 'lingotek-translation' ) ?></label></th>
94
- <td>
95
- <select name="lingotek_community" id="lingotek_community">
96
- <?php
97
- $default_community_id = $community_id;
98
 
99
- // Community.
100
- $communities = array();
101
- if ( isset( $api_communities->entities ) ) {
102
- foreach ( $api_communities->entities as $community ) {
103
- $communities[ $community->properties->id ] = $community->properties->title;
104
- }
105
 
106
- $num_communities = count( $communities );
107
- if ( 1 === $num_communities && ! $community_id ) {
108
- update_option( 'lingotek_community', current( array_keys( $communities ) ) );
109
- }
110
- if ( ! $community_id && $num_communities > 1 ) {
111
- echo "\n\t" . '<option value="">' . esc_html( __( 'Select', 'lingotek-translation' ) ) . '...</option>';
 
 
 
 
 
112
  }
113
- foreach ( $communities as $community_id_option => $community_title ) {
114
- $selected = ($default_community_id === $community_id_option) ? 'selected="selected"' : '';
115
- echo "\n\t" . '<option value="' . esc_attr( $community_id_option ) . '" ' . esc_html( $selected ) . '>' . esc_html( $community_title ) . '</option>';
116
- }
117
- }
118
- ?>
119
- </select>
120
- </td>
121
  </tr>
122
  <tr>
123
- <th scope="row"><?php esc_html_e( 'Payment Method', 'lingotek-translation' ) ?></th>
124
  <td>
125
-
126
  <?php
127
  add_thickbox();
128
- wp_enqueue_script( 'lingotek_professional_workflow_account', LINGOTEK_URL . '/js/workflow/professional-workflow-account.js' );
129
  $vars = array(
130
- 'modal_id' => 'payment-portal-screen',
131
- 'bridge_payment' => BRIDGE_URL . '/#/payment/portal'
132
  );
133
  wp_localize_script( 'lingotek_professional_workflow_account', 'account_vars', $vars );
134
  wp_enqueue_style( 'lingotek_professional_workflow_style', LINGOTEK_URL . '/css/workflow/professional-workflow-style.css', array(), LINGOTEK_VERSION );
135
- $ltk_client = new Lingotek_API();
136
- $payment_info = $ltk_client->get_user_payment_information();
137
- $cc = '';
138
- $cc_type = '';
139
- if ($payment_method_set = isset($payment_info['payment_info']['payment_profile']['cc'])) {
 
140
  $cc = $payment_info['payment_info']['payment_profile']['cc'];
141
- $cc = str_replace('X','', $cc);
142
 
143
  $cc_type = $payment_info['payment_info']['payment_profile']['cc_type'];
144
  }
145
- ?>
146
  <div id='modal-window-id-payment-portal-screen' style='display:none;' >
147
  <div id='payment-portal-wrapper' class='payment-portal-element'>
148
- <img class='payment-portal-element payment-portal-image' src="<?php echo esc_url_raw( LINGOTEK_URL ) ?>/img/translation-logo.png"/>
149
- <img class='payment-portal-element payment-portal-loading' src="<?php echo esc_url_raw( LINGOTEK_URL ) ?>/img/loading.gif"/>
150
  <span class='payment-portal-element You-are-now-being-re'>You are now being redirected to the Lingotek Secure Payment Portal...</span>
151
  </div>
152
  </div>
153
- <div class='payment-method-setup professional-card-border' style="<?php echo ($payment_method_set) ? 'display:inline-block;' : 'display:none'; ?>">
154
  <div class='payment-method-setup blue-radio-button-div'><img id='blue-radio-button' class='payment-method-setup' src="<?php echo esc_url_raw( LINGOTEK_URL ); ?>/img/blue-radio-button.svg"/></div>
155
  <div class='payment-method-setup credit-card-dots-div'><img id='credit-card-dots' class='payment-method-setup' src="<?php echo esc_url_raw( LINGOTEK_URL ); ?>/img/credit-dots.svg" /></div>
156
- <div class='payment-method-setup last-four-digits-div'><span id='last-four-digits' class='payment-method-setup'><?php echo $cc; ?></span></div>
157
- <div class='payment-method-setup credit-card-image-div'><img id='credit-card-image' class='payment-method-setup' src="<?php echo Lingotek_Credit_Card_To_Path::get_cc_type_asset_url($cc_type) ?>"/></div>
158
  </div>
159
- <div style="height:37px; display:inline-block;padding-left: 10px;"><a id="professional-payment-info-link" href="<?php echo esc_url_raw( BRIDGE_URL ); ?>/#/payment/portal?redirect_url=<?php echo urlencode( home_url( add_query_arg( NULL, NULL ) ) ); ?>" style="display: table-cell;padding-top: 7%;"><?php echo ($payment_method_set) ? 'Edit Payment Method' : 'Set Up Payment Method'; ?></a></div>
160
  </td>
161
  </tr>
162
  </table>
1
  <?php
2
+ $client = new Lingotek_API();
3
  $api_communities = $client->get_communities();
4
  if ( ! isset( $api_communities->entities ) ) {
5
  add_settings_error( 'lingotek_community_resources', 'error', __( 'The Lingotek TMS is currently unavailable. Please try again later. If the problem persists, contact Lingotek Support.', 'lingotek-translation' ), 'error' );
6
  settings_errors();
7
  }
8
  if ( ! $community_id ) {
9
+ $ltk_client = new Lingotek_API();
10
+ $ltk_communities = $ltk_client->get_communities();
11
  $ltk_num_communities = $ltk_communities->properties->total;
12
  if ( 1 === $ltk_num_communities ) {
13
  $ltk_community_id = $ltk_communities->entities[0]->properties->id;
23
  <table class="form-table">
24
  <tr>
25
  <th scope="row">
26
+ <?php esc_html_e( 'Connected', 'lingotek-translation' ); ?>
27
+ <a id="cd-show-link" class="dashicons dashicons-arrow-right" onclick="document.getElementById('connection-details').style.display = ''; document.getElementById('cd-hide-link').style.display = ''; this.style.display = 'none'; return false;"></a>
28
+ <a id="cd-hide-link" class="dashicons dashicons-arrow-down" onclick="document.getElementById('connection-details').style.display = 'none'; document.getElementById('cd-show-link').style.display = ''; this.style.display = 'none'; return false;" style="display: none;"></a>
29
  </th>
30
  <td>
31
+ <?php esc_html_e( 'Yes', 'lingotek-translation' ); ?><span title="<?php esc_html_e( 'Connected', 'lingotek-translation' ); ?>" class="dashicons dashicons-yes" style="color: green;"></span>
32
  </td>
33
  </tr>
34
  <tbody id="connection-details" style="display: none;">
35
  <tr>
36
+ <th scope="row"><?php echo esc_html( __( 'Login ID', 'lingotek-translation' ) ); ?></th>
37
  <td>
38
+ <label>
39
+ <?php
40
+ printf(
41
+ '<input name="%s" class="regular-text" type="text" value="%s" disabled="disabled" />',
42
+ 'login_id',
43
+ esc_html( $token_details['login_id'] )
44
+ );
45
+ ?>
46
+ </label>
47
  </td>
48
  </tr>
49
  <tr>
50
+ <th scope="row"><?php echo esc_html( __( 'Access Token', 'lingotek-translation' ) ); ?></th>
51
  <td>
52
+ <label>
53
+ <?php
54
+ printf(
55
+ '<input name="%s" class="regular-text" type="password" value="%s" disabled="disabled" style="display: none;" />',
56
+ 'access_token',
57
+ esc_html( $token_details['access_token'] )
58
+ );
59
+ printf(
60
+ '<input name="%s" class="regular-text" type="text" value="%s" disabled="disabled" />',
61
+ 'access_token',
62
+ esc_html( $token_details['access_token'] )
63
+ );
64
+ ?>
65
+ </label>
66
  </td>
67
  </tr>
68
  <tr>
69
+ <th scope="row"><?php echo esc_html( __( 'API Endpoint', 'lingotek-translation' ) ); ?></th>
70
  <td>
71
+ <label>
72
+ <?php
73
+ printf(
74
+ '<input name="%s" class="regular-text" type="text" value="%s" disabled="disabled" />',
75
+ 'base_url',
76
+ esc_html( $base_url )
77
+ );
78
+ ?>
79
+ </label>
80
  </td>
81
  </tr>
82
  <tr>
98
 
99
  <table class="form-table">
100
  <tr>
101
+ <th scope="row"><label for="lingotek_community"><?php esc_html_e( 'Community', 'lingotek-translation' ); ?></label></th>
102
+ <td>
103
+ <select name="lingotek_community" id="lingotek_community">
104
+ <?php
105
+ $default_community_id = $community_id;
106
 
107
+ // Community.
108
+ $communities = array();
109
+ if ( isset( $api_communities->entities ) ) {
110
+ foreach ( $api_communities->entities as $community ) {
111
+ $communities[ $community->properties->id ] = $community->properties->title;
112
+ }
113
 
114
+ $num_communities = count( $communities );
115
+ if ( 1 === $num_communities && ! $community_id ) {
116
+ update_option( 'lingotek_community', current( array_keys( $communities ) ) );
117
+ }
118
+ if ( ! $community_id && $num_communities > 1 ) {
119
+ echo "\n\t" . '<option value="">' . esc_html( __( 'Select', 'lingotek-translation' ) ) . '...</option>';
120
+ }
121
+ foreach ( $communities as $community_id_option => $community_title ) {
122
+ $selected = ( $default_community_id === $community_id_option ) ? 'selected="selected"' : '';
123
+ echo "\n\t" . '<option value="' . esc_attr( $community_id_option ) . '" ' . esc_html( $selected ) . '>' . esc_html( $community_title ) . '</option>';
124
+ }
125
  }
126
+ ?>
127
+ </select>
128
+ </td>
 
 
 
 
 
129
  </tr>
130
  <tr>
131
+ <th scope="row"><?php esc_html_e( 'Payment Method', 'lingotek-translation' ); ?></th>
132
  <td>
 
133
  <?php
134
  add_thickbox();
135
+ wp_enqueue_script( 'lingotek_professional_workflow_account', LINGOTEK_URL . '/js/workflow/professional-workflow-account.js', array(), LINGOTEK_VERSION, false );
136
  $vars = array(
137
+ 'modal_id' => 'payment-portal-screen',
138
+ 'bridge_payment' => BRIDGE_URL . '/#/payment/portal',
139
  );
140
  wp_localize_script( 'lingotek_professional_workflow_account', 'account_vars', $vars );
141
  wp_enqueue_style( 'lingotek_professional_workflow_style', LINGOTEK_URL . '/css/workflow/professional-workflow-style.css', array(), LINGOTEK_VERSION );
142
+ $ltk_client = new Lingotek_API();
143
+ $payment_info = $ltk_client->get_user_payment_information();
144
+ $cc = '';
145
+ $cc_type = '';
146
+ $payment_method_set = isset( $payment_info['payment_info']['payment_profile']['cc'] );
147
+ if ( $payment_method_set ) {
148
  $cc = $payment_info['payment_info']['payment_profile']['cc'];
149
+ $cc = str_replace( 'X', '', $cc );
150
 
151
  $cc_type = $payment_info['payment_info']['payment_profile']['cc_type'];
152
  }
153
+ ?>
154
  <div id='modal-window-id-payment-portal-screen' style='display:none;' >
155
  <div id='payment-portal-wrapper' class='payment-portal-element'>
156
+ <img class='payment-portal-element payment-portal-image' src="<?php echo esc_url_raw( LINGOTEK_URL ); ?>/img/translation-logo.png"/>
157
+ <img class='payment-portal-element payment-portal-loading' src="<?php echo esc_url_raw( LINGOTEK_URL ); ?>/img/loading.gif"/>
158
  <span class='payment-portal-element You-are-now-being-re'>You are now being redirected to the Lingotek Secure Payment Portal...</span>
159
  </div>
160
  </div>
161
+ <div class='payment-method-setup professional-card-border' style="<?php echo ( $payment_method_set ) ? 'display:inline-block;' : 'display:none'; ?>">
162
  <div class='payment-method-setup blue-radio-button-div'><img id='blue-radio-button' class='payment-method-setup' src="<?php echo esc_url_raw( LINGOTEK_URL ); ?>/img/blue-radio-button.svg"/></div>
163
  <div class='payment-method-setup credit-card-dots-div'><img id='credit-card-dots' class='payment-method-setup' src="<?php echo esc_url_raw( LINGOTEK_URL ); ?>/img/credit-dots.svg" /></div>
164
+ <div class='payment-method-setup last-four-digits-div'><span id='last-four-digits' class='payment-method-setup'><?php echo esc_html( $cc ); ?></span></div>
165
+ <div class='payment-method-setup credit-card-image-div'><img id='credit-card-image' class='payment-method-setup' src="<?php echo esc_html( Lingotek_Credit_Card_To_Path::get_cc_type_asset_url( $cc_type ) ); ?>"/></div>
166
  </div>
167
+ <div style="height:37px; display:inline-block;padding-left: 10px;"><a id="professional-payment-info-link" href="<?php echo esc_url_raw( BRIDGE_URL ); ?>/#/payment/portal?redirect_url=<?php echo rawurlencode( home_url( add_query_arg( null, null ) ) ); ?>" style="display: table-cell;padding-top: 7%;"><?php echo ( $payment_method_set ) ? 'Edit Payment Method' : 'Set Up Payment Method'; ?></a></div>
168
  </td>
169
  </tr>
170
  </table>
admin/settings/view-defaults.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  $page_key = $this->plugin_slug . '_settings&sm=defaults';
4
 
5
- wp_enqueue_script( 'defaults', LINGOTEK_URL . '/js/defaults.js' );
6
 
7
  if ( ! empty( $_POST ) ) {
8
  check_admin_referer( $page_key, '_wpnonce_' . $page_key );
@@ -19,7 +19,7 @@ if ( ! empty( $_POST ) ) {
19
  add_settings_error( 'lingotek_community_resources', 'error', __( 'The Lingotek TMS is currently unavailable. Please try again later. If the problem persists, contact Lingotek Support.', 'lingotek-translation' ), 'error' );
20
  }
21
  } else {
22
- $options = array();
23
  $settings = $this->get_profiles_settings( true );
24
  foreach ( $settings as $key => $setting ) {
25
  $key_input = filter_input( INPUT_POST, $key );
@@ -41,33 +41,38 @@ if ( ! empty( $_POST ) ) {
41
  // adds new project if text box is filled out.
42
  $new_project = filter_input( INPUT_POST, 'new_project' );
43
  if ( ! empty( $new_project ) ) {
44
- $client = new Lingotek_API();
45
- $title = stripslashes( filter_input( INPUT_POST, 'new_project' ) );
46
 
47
- if ( $new_id = $client->create_project( $title, $community_id ) ) {
 
48
  add_settings_error( 'lingotek_defaults', 'defaultgs', __( 'Your new project was successfully created.', 'lingotek-translation' ), 'updated' );
49
- $this->set_community_resources( $community_id );// updates the cache to include the newly created project.
 
50
  $options['project_id'] = $new_id;
51
  update_option( 'lingotek_defaults', $options );
52
  }
53
  }
54
- }
55
  settings_errors();
56
- }
57
  $settings = $this->get_profiles_settings( true );
58
- $options = get_option( 'lingotek_defaults' );
59
 
60
  // Code to determine which filter scenario will be displayed (Not configured, defaults, custom filters).
61
- $primary_filter_id = array_search( 'okf_json@with-html-subfilter.fprm', $settings['primary_filter_id']['options'], true );
62
- $secondary_filter_id = array_search( 'okf_html@wordpress.fprm', $settings['secondary_filter_id']['options'], true );
63
- $default_filters = array( $primary_filter_id => 'okf_json@with-html-subfilter.fprm', $secondary_filter_id => 'okf_html@wordpress.fprm' );
 
 
 
64
  $default_filters_exist = false;
65
- $extra_filters_exist = false;
66
- $no_filters_exist = false;
67
 
68
  if ( $settings['primary_filter_id']['options'] === $default_filters ) {
69
- $default_filters_exist = true;
70
- $options['primary_filter_id'] = $primary_filter_id;
71
  $options['secondary_filter_id'] = $secondary_filter_id;
72
  update_option( 'lingotek_defaults', $options );
73
  } else {
@@ -75,7 +80,7 @@ if ( $settings['primary_filter_id']['options'] === $default_filters ) {
75
  if ( $num > 0 ) {
76
  $extra_filters_exist = true;
77
  } else {
78
- $options['primary_filter_id'] = '';
79
  $options['secondary_filter_id'] = '';
80
  update_option( 'lingotek_defaults', $options );
81
  $no_filters_exist = true;
@@ -92,45 +97,58 @@ unset( $settings['secondary_filter_id']['options'][ $primary_filter_id ] );
92
  <form id="lingotek-settings" method="post" action="admin.php?page=<?php echo esc_html( $page_key ); ?>" class="validate">
93
  <?php wp_nonce_field( $page_key, '_wpnonce_' . $page_key ); ?>
94
 
95
- <table class="form-table"><?php foreach ( $settings as $key => $setting ) { ?>
96
- <tr id="<?php echo esc_html( $key ) . '_row'?>">
97
- <th scope="row"><label for="<?php echo esc_html( $key ); ?>"><?php echo esc_html( $setting['label'] ) ?></label></th>
 
98
  <td>
99
- <select name="<?php echo esc_html( $key ) ?>" id="<?php echo esc_html( $key ) ?>"><?php
100
- foreach ( $setting['options'] as $id => $title ) {
101
- $selected = array_key_exists( $key, $options ) && ($options[ $key ] === $id) ? 'selected="selected"' : '';
102
- echo "\n\t<option value='" . esc_attr( $id ) . "' " . esc_html( $selected ) . '>' . esc_html( $title ) . '</option>';
103
- } ?>
104
- </select><?php
105
- if ( 'project_id' === $key ) { ?>
 
 
 
 
106
  <?php
107
 
108
- if ( empty( $setting['options'] ) ) { ?>
 
109
  <script> document.getElementById('project_id').style.display = 'none';</script>
110
- <input type="text" name="new_project" id="new_project" placeholder="<?php esc_html_e( 'Enter new project name', 'lingotek-translation' ) ?>" />
111
  <?php } else { ?>
112
 
113
- <input type="text" style="display:none" name="new_project" id="new_project" placeholder="<?php esc_html_e( 'Enter new project name', 'lingotek-translation' ) ?>" />
114
  <input type="checkbox" name="update_callback" id="update_callback"/>
115
- <label for="update_callback" id="callback_label"><?php esc_html_e( 'Update the callback url for this project.', 'lingotek-translation' ) ?></label>
116
 
117
- <br/><a href="#" id="create" onclick="toggleTextbox()" style="padding-left:3px; color:#999; font-size:80%; text-decoration:none"><b>+</b> <?php echo esc_html_e( 'Create New Project', 'lingotek-translation' ) ?></a>
118
  <?php } ?>
119
  <?php } ?>
120
  <!-- Code to handle displaying of Primary and Secondary Filters. -->
121
- <?php if ( $no_filters_exist ) { ?>
122
  <script> document.getElementById("primary_filter_id_row").style.display = "none";</script>
123
- <script> document.getElementById("secondary_filter_id_row").style.display = "none";</script> <?php
124
- if ( 'primary_filter_id' === $key ) { ?>
125
- <tr id="filters_row"><th><?php esc_html_e( 'Filters', 'lingotek-translation' ) ?></th><td><i><?php esc_html_e( 'Not configured', 'lingotek-translation' ) ?></i></td></tr>
126
- <?php }
127
- }
128
- if ( $default_filters_exist ) { ?>
 
 
 
 
129
  <script> document.getElementById("primary_filter_id_row").style.display = "none";</script>
130
  <script> document.getElementById("secondary_filter_id_row").style.display = "none";</script>
131
- <?php } ?>
132
  <!-- End of filter code. -->
133
- </tr><?php } ?>
 
 
 
134
  </table>
135
 
136
  <p>
@@ -139,4 +157,4 @@ if ( $default_filters_exist ) { ?>
139
  </p>
140
  </form>
141
 
142
- <?php Lingotek_Workflow_Factory::echo_info_modals(); ?>
2
 
3
  $page_key = $this->plugin_slug . '_settings&sm=defaults';
4
 
5
+ wp_enqueue_script( 'defaults', LINGOTEK_URL . '/js/defaults.js', array(), LINGOTEK_VERSION, false );
6
 
7
  if ( ! empty( $_POST ) ) {
8
  check_admin_referer( $page_key, '_wpnonce_' . $page_key );
19
  add_settings_error( 'lingotek_community_resources', 'error', __( 'The Lingotek TMS is currently unavailable. Please try again later. If the problem persists, contact Lingotek Support.', 'lingotek-translation' ), 'error' );
20
  }
21
  } else {
22
+ $options = array();
23
  $settings = $this->get_profiles_settings( true );
24
  foreach ( $settings as $key => $setting ) {
25
  $key_input = filter_input( INPUT_POST, $key );
41
  // adds new project if text box is filled out.
42
  $new_project = filter_input( INPUT_POST, 'new_project' );
43
  if ( ! empty( $new_project ) ) {
44
+ $client = new Lingotek_API();
45
+ $project_title = stripslashes( filter_input( INPUT_POST, 'new_project' ) );
46
 
47
+ $new_id = $client->create_project( $project_title, $community_id );
48
+ if ( $new_id ) {
49
  add_settings_error( 'lingotek_defaults', 'defaultgs', __( 'Your new project was successfully created.', 'lingotek-translation' ), 'updated' );
50
+ // Updates the cache to include the newly created project.
51
+ $this->set_community_resources( $community_id );
52
  $options['project_id'] = $new_id;
53
  update_option( 'lingotek_defaults', $options );
54
  }
55
  }
56
+ }//end if
57
  settings_errors();
58
+ }//end if
59
  $settings = $this->get_profiles_settings( true );
60
+ $options = get_option( 'lingotek_defaults', array() );
61
 
62
  // Code to determine which filter scenario will be displayed (Not configured, defaults, custom filters).
63
+ $primary_filter_id = array_search( 'okf_json@with-html-subfilter.fprm', $settings['primary_filter_id']['options'], true );
64
+ $secondary_filter_id = array_search( 'okf_html@wordpress.fprm', $settings['secondary_filter_id']['options'], true );
65
+ $default_filters = array(
66
+ $primary_filter_id => 'okf_json@with-html-subfilter.fprm',
67
+ $secondary_filter_id => 'okf_html@wordpress.fprm',
68
+ );
69
  $default_filters_exist = false;
70
+ $extra_filters_exist = false;
71
+ $no_filters_exist = false;
72
 
73
  if ( $settings['primary_filter_id']['options'] === $default_filters ) {
74
+ $default_filters_exist = true;
75
+ $options['primary_filter_id'] = $primary_filter_id;
76
  $options['secondary_filter_id'] = $secondary_filter_id;
77
  update_option( 'lingotek_defaults', $options );
78
  } else {
80
  if ( $num > 0 ) {
81
  $extra_filters_exist = true;
82
  } else {
83
+ $options['primary_filter_id'] = '';
84
  $options['secondary_filter_id'] = '';
85
  update_option( 'lingotek_defaults', $options );
86
  $no_filters_exist = true;
97
  <form id="lingotek-settings" method="post" action="admin.php?page=<?php echo esc_html( $page_key ); ?>" class="validate">
98
  <?php wp_nonce_field( $page_key, '_wpnonce_' . $page_key ); ?>
99
 
100
+ <table class="form-table">
101
+ <?php foreach ( $settings as $key => $setting ) { ?>
102
+ <tr id="<?php echo esc_html( $key ) . '_row'; ?>">
103
+ <th scope="row"><label for="<?php echo esc_html( $key ); ?>"><?php echo esc_html( $setting['label'] ); ?></label></th>
104
  <td>
105
+ <select name="<?php echo esc_html( $key ); ?>" id="<?php echo esc_html( $key ); ?>">
106
+ <?php
107
+ foreach ( $setting['options'] as $option_id => $option_title ) {
108
+ $selected = array_key_exists( $key, $options ) && ( $options[ $key ] === $option_id ) ? 'selected="selected"' : '';
109
+ echo "\n\t<option value='" . esc_attr( $option_id ) . "' " . esc_html( $selected ) . '>' . esc_html( $option_title ) . '</option>';
110
+ }
111
+ ?>
112
+ </select>
113
+ <?php
114
+ if ( 'project_id' === $key ) {
115
+ ?>
116
  <?php
117
 
118
+ if ( empty( $setting['options'] ) ) {
119
+ ?>
120
  <script> document.getElementById('project_id').style.display = 'none';</script>
121
+ <input type="text" name="new_project" id="new_project" placeholder="<?php esc_html_e( 'Enter new project name', 'lingotek-translation' ); ?>" />
122
  <?php } else { ?>
123
 
124
+ <input type="text" style="display:none" name="new_project" id="new_project" placeholder="<?php esc_html_e( 'Enter new project name', 'lingotek-translation' ); ?>" />
125
  <input type="checkbox" name="update_callback" id="update_callback"/>
126
+ <label for="update_callback" id="callback_label"><?php esc_html_e( 'Update the callback url for this project.', 'lingotek-translation' ); ?></label>
127
 
128
+ <br/><a href="#" id="create" onclick="toggleTextbox()" style="padding-left:3px; color:#999; font-size:80%; text-decoration:none"><b>+</b> <?php echo esc_html_e( 'Create New Project', 'lingotek-translation' ); ?></a>
129
  <?php } ?>
130
  <?php } ?>
131
  <!-- Code to handle displaying of Primary and Secondary Filters. -->
132
+ <?php if ( $no_filters_exist ) { ?>
133
  <script> document.getElementById("primary_filter_id_row").style.display = "none";</script>
134
+ <script> document.getElementById("secondary_filter_id_row").style.display = "none";</script>
135
+ <?php
136
+ if ( 'primary_filter_id' === $key ) {
137
+ ?>
138
+ <tr id="filters_row"><th><?php esc_html_e( 'Filters', 'lingotek-translation' ); ?></th><td><i><?php esc_html_e( 'Not configured', 'lingotek-translation' ); ?></i></td></tr>
139
+ <?php
140
+ }
141
+ }
142
+ if ( $default_filters_exist ) {
143
+ ?>
144
  <script> document.getElementById("primary_filter_id_row").style.display = "none";</script>
145
  <script> document.getElementById("secondary_filter_id_row").style.display = "none";</script>
146
+ <?php } ?>
147
  <!-- End of filter code. -->
148
+ </tr>
149
+ <?php
150
+ }//end foreach
151
+ ?>
152
  </table>
153
 
154
  <p>
157
  </p>
158
  </form>
159
 
160
+ <?php Lingotek_Workflow_Factory::lingotek_translation_professional_translation_info_modals(); ?>
admin/settings/view-preferences.php CHANGED
@@ -1,72 +1,75 @@
1
  <?php
2
  global $wp_post_statuses;
3
  $setting_details = array(
4
- 'download_post_status' => array(
5
- 'type' => 'dropdown',
6
- 'label' => __( 'Download translation status', 'lingotek-translation' ),
7
  'description' => __( 'The post status for newly downloaded translations', 'lingotek-translation' ),
8
- 'values' => array(
9
- Lingotek_Group_Post::SAME_AS_SOURCE => __( 'Same as source post', 'lingotek-translation' )
10
  ),
11
  ),
12
- 'auto_upload_post_statuses' => array( // blacklist.
13
- 'type' => 'checkboxes',
14
- 'label' => __( 'Auto upload statuses', 'lingotek-translation' ),
15
  'description' => __( 'The post statuses checked above are enabled for automatic upload (when using automatic uploading translation profiles).', 'lingotek-translation' ),
16
- 'values' => array(),
17
  ),
18
- 'trash_linked_content' => array(
19
- 'type' => 'checkboxes',
20
- 'label' => __( 'Trashed Content', 'wp-lingotek' ),
21
- 'description' => __( 'When enabled, sending source or target content to the trash will also send all linked content to the trash. ', 'wp-lingotek' ),
22
- 'values' => array(
23
- 'enabled' => __( 'Sync trashed content', 'wp-lingotek' ),
24
  ),
25
  ),
26
- 'import_enabled' => array(
27
- 'type' => 'checkboxes',
28
- 'label' => __( 'Import', 'wp-lingotek' ),
29
- 'description' => __( 'When checked, an "Import" submenu will appear.', 'wp-lingotek' ),
30
- 'values' => array(
31
- 'enabled' => __( 'Enable importing from Lingotek Content Cloud. (beta)', 'wp-lingotek' ),
32
  ),
33
  ),
34
- 'auto_update_status' => array(
35
- 'type' => 'dropdown',
36
- 'label' => __( 'Automatic Status Update Interval', 'wp-lingotek' ),
37
- 'description' => __( 'Changes the rate at which content statuses update automatically.', 'wp-lingotek' ),
38
- 'values' => array(
39
- '10' => '10 seconds', '30' => '30 seconds', '60' => '60 seconds', '-1' => 'Do not update automatically'
 
 
 
40
  ),
41
  ),
42
- 'enable_lingotek_logs' => array(
43
- 'type' => 'checkboxes',
44
- 'label' => __('Enable Lingotek Debug Logs', 'wp-lingotek'),
45
- 'description' => __( 'Enables Lingotek\'s logs for debugging purposes.' , 'wp-lingotek'),
46
- 'values' => array(
47
- 'enabled' => __( 'Enable Lingotek Logs', 'wp-lingotek' )
48
  ),
49
  ),
50
  );
51
 
52
- function map_wp_post_status($status){
53
  return __( $status->label, 'lingotek-translation' );
54
  }
55
 
56
- function filter_statuses($statuses){
57
- $statuses_to_filter = array('auto-draft', 'trash', 'inactive', 'inherit');
58
- $ret = array();
59
- foreach ($statuses as $status => $value) {
60
- if (!in_array($status,$statuses_to_filter)) {
61
- $ret[$status] = $value;
62
  }
63
  }
64
  return $ret;
65
  }
66
 
67
- $post_statuses = filter_statuses(array_map("map_wp_post_status", $wp_post_statuses));
68
- $setting_details["auto_upload_post_statuses"]["values"] = array_merge($post_statuses, $setting_details["auto_upload_post_statuses"]["values"]);
69
- $setting_details["download_post_status"]["values"] = array_merge($post_statuses, $setting_details["download_post_status"]["values"]);
70
 
71
  $page_key = $this->plugin_slug . '_settings&sm=preferences';
72
 
@@ -79,10 +82,9 @@ if ( ! empty( $_POST ) ) {
79
  $options[ $key ] = $key_input;
80
  } else {
81
  $key_input = filter_input_array( INPUT_POST );
82
- if (!empty($key_input[$key])) {
83
- $options[ $key ] = $key_input[$key];
84
- }
85
- else {
86
  $options[ $key ] = null;
87
  }
88
  }
@@ -91,7 +93,7 @@ if ( ! empty( $_POST ) ) {
91
 
92
  add_settings_error( 'lingotek_prefs', 'prefs', __( 'Your preferences were successfully updated.', 'lingotek-translation' ), 'updated' );
93
  settings_errors();
94
- }
95
  $selected_options = Lingotek_Model::get_prefs();
96
 
97
  ?>
@@ -103,32 +105,37 @@ $selected_options = Lingotek_Model::get_prefs();
103
  <form id="lingotek-settings" method="post" action="admin.php?page=<?php echo esc_html( $page_key ); ?>" class="validate">
104
  <?php wp_nonce_field( $page_key, '_wpnonce_' . $page_key ); ?>
105
 
106
- <table class="form-table"><?php foreach ( $setting_details as $key => $setting ) { ?>
107
-
108
- <tr>
109
- <th scope="row"><label for="<?php echo esc_html( $key ); ?>"><?php echo esc_html( $setting['label'] ) ?></label></th>
110
- <td>
111
- <?php if ( 'dropdown' === $setting['type'] ) { ?>
112
- <select name="<?php echo esc_html( $key ); ?>" id="<?php echo esc_html( $key ); ?>">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  <?php
114
- foreach ( $setting['values'] as $id => $title ) {
115
- echo "\n\t" . '<option value="' . esc_attr( $id ) . '" ' . selected( $selected_options[ $key ], $id ) . '>' . esc_html( $title ) . '</option>';
116
- }
117
- ?>
118
- </select>
119
- <?php } elseif ( 'checkboxes' === $setting['type'] ) {
120
- echo '<ul class="pref-statuses">';
121
- foreach ( $setting['values'] as $id => $title ) {
122
- $cb_name = $key . '[' . esc_attr( $id ) . ']';
123
- $checked = checked( '1', (isset( $selected_options[ $key ][ $id ] ) && $selected_options[ $key ][ $id ]), false );
124
- echo '<li><input type="checkbox" id="' . esc_attr( $cb_name ) . '" name="' . esc_attr( $cb_name ) . '" value="1" ' . esc_attr( $checked ) . '><label for="' . esc_attr( $cb_name ) . '">' . esc_html( $title ) . '</label></li>';
125
- }
126
- echo '</ul>';
127
- } ?>
128
- <p class="description">
129
- <?php echo esc_html( $setting['description'] ); ?>
130
- </p>
131
- </tr><?php } ?>
132
  </table>
133
 
134
  <?php submit_button( __( 'Save Changes', 'lingotek-translation' ), 'primary', 'submit', false ); ?>
1
  <?php
2
  global $wp_post_statuses;
3
  $setting_details = array(
4
+ 'download_post_status' => array(
5
+ 'type' => 'dropdown',
6
+ 'label' => __( 'Download translation status', 'lingotek-translation' ),
7
  'description' => __( 'The post status for newly downloaded translations', 'lingotek-translation' ),
8
+ 'values' => array(
9
+ Lingotek_Group_Post::SAME_AS_SOURCE => __( 'Same as source post', 'lingotek-translation' ),
10
  ),
11
  ),
12
+ 'auto_upload_post_statuses' => array(
13
+ 'type' => 'checkboxes',
14
+ 'label' => __( 'Auto upload statuses', 'lingotek-translation' ),
15
  'description' => __( 'The post statuses checked above are enabled for automatic upload (when using automatic uploading translation profiles).', 'lingotek-translation' ),
16
+ 'values' => array(),
17
  ),
18
+ 'trash_linked_content' => array(
19
+ 'type' => 'checkboxes',
20
+ 'label' => __( 'Trashed Content', 'lingotek-translation' ),
21
+ 'description' => __( 'When enabled, sending source or target content to the trash will also send all linked content to the trash. ', 'lingotek-translation' ),
22
+ 'values' => array(
23
+ 'enabled' => __( 'Sync trashed content', 'lingotek-translation' ),
24
  ),
25
  ),
26
+ 'import_enabled' => array(
27
+ 'type' => 'checkboxes',
28
+ 'label' => __( 'Import', 'lingotek-translation' ),
29
+ 'description' => __( 'When checked, an "Import" submenu will appear.', 'lingotek-translation' ),
30
+ 'values' => array(
31
+ 'enabled' => __( 'Enable importing from Lingotek Content Cloud. (beta)', 'lingotek-translation' ),
32
  ),
33
  ),
34
+ 'auto_update_status' => array(
35
+ 'type' => 'dropdown',
36
+ 'label' => __( 'Automatic Status Update Interval', 'lingotek-translation' ),
37
+ 'description' => __( 'Changes the rate at which content statuses update automatically.', 'lingotek-translation' ),
38
+ 'values' => array(
39
+ '10' => '10 seconds',
40
+ '30' => '30 seconds',
41
+ '60' => '60 seconds',
42
+ '-1' => 'Do not update automatically',
43
  ),
44
  ),
45
+ 'enable_lingotek_logs' => array(
46
+ 'type' => 'checkboxes',
47
+ 'label' => __( 'Enable Lingotek Debug Logs', 'lingotek-translation' ),
48
+ 'description' => __( 'Enables Lingotek\'s logs for debugging purposes.', 'lingotek-translation' ),
49
+ 'values' => array(
50
+ 'enabled' => __( 'Enable Lingotek Logs', 'lingotek-translation' ),
51
  ),
52
  ),
53
  );
54
 
55
+ function lingotek_translation_preferences_map_wp_post_status( $status ) {
56
  return __( $status->label, 'lingotek-translation' );
57
  }
58
 
59
+ function lingotek_translation_preferences_filter_statuses( $statuses ) {
60
+ $statuses_to_filter = array( 'auto-draft', 'trash', 'inactive', 'inherit' );
61
+ $ret = array();
62
+ foreach ( $statuses as $status => $value ) {
63
+ if ( ! in_array( $status, $statuses_to_filter, true ) ) {
64
+ $ret[ $status ] = $value;
65
  }
66
  }
67
  return $ret;
68
  }
69
 
70
+ $post_statuses = lingotek_translation_preferences_filter_statuses( array_map( 'lingotek_translation_preferences_map_wp_post_status', $wp_post_statuses ) );
71
+ $setting_details['auto_upload_post_statuses']['values'] = array_merge( $post_statuses, $setting_details['auto_upload_post_statuses']['values'] );
72
+ $setting_details['download_post_status']['values'] = array_merge( $post_statuses, $setting_details['download_post_status']['values'] );
73
 
74
  $page_key = $this->plugin_slug . '_settings&sm=preferences';
75
 
82
  $options[ $key ] = $key_input;
83
  } else {
84
  $key_input = filter_input_array( INPUT_POST );
85
+ if ( ! empty( $key_input[ $key ] ) ) {
86
+ $options[ $key ] = $key_input[ $key ];
87
+ } else {
 
88
  $options[ $key ] = null;
89
  }
90
  }
93
 
94
  add_settings_error( 'lingotek_prefs', 'prefs', __( 'Your preferences were successfully updated.', 'lingotek-translation' ), 'updated' );
95
  settings_errors();
96
+ }//end if
97
  $selected_options = Lingotek_Model::get_prefs();
98
 
99
  ?>
105
  <form id="lingotek-settings" method="post" action="admin.php?page=<?php echo esc_html( $page_key ); ?>" class="validate">
106
  <?php wp_nonce_field( $page_key, '_wpnonce_' . $page_key ); ?>
107
 
108
+ <table class="form-table">
109
+ <?php foreach ( $setting_details as $key => $setting ) { ?>
110
+ <tr>
111
+ <th scope="row"><label for="<?php echo esc_html( $key ); ?>"><?php echo esc_html( $setting['label'] ); ?></label></th>
112
+ <td>
113
+ <?php if ( 'dropdown' === $setting['type'] ) { ?>
114
+ <select name="<?php echo esc_html( $key ); ?>" id="<?php echo esc_html( $key ); ?>">
115
+ <?php
116
+ foreach ( $setting['values'] as $setting_id => $setting_title ) {
117
+ echo "\n\t" . '<option value="' . esc_attr( $setting_id ) . '" ' . selected( $selected_options[ $key ], $setting_id ) . '>' . esc_html( $setting_title ) . '</option>';
118
+ }
119
+ ?>
120
+ </select>
121
+ <?php
122
+ } elseif ( 'checkboxes' === $setting['type'] ) {
123
+ echo '<ul class="pref-statuses">';
124
+ foreach ( $setting['values'] as $setting_id => $setting_title ) {
125
+ $cb_name = $key . '[' . esc_attr( $setting_id ) . ']';
126
+ $checked = checked( '1', ( isset( $selected_options[ $key ][ $setting_id ] ) && $selected_options[ $key ][ $setting_id ] ), false );
127
+ echo '<li><input type="checkbox" id="' . esc_attr( $cb_name ) . '" name="' . esc_attr( $cb_name ) . '" value="1" ' . esc_attr( $checked ) . '><label for="' . esc_attr( $cb_name ) . '">' . esc_html( $setting_title ) . '</label></li>';
128
+ }
129
+ echo '</ul>';
130
+ }
131
+ ?>
132
+ <p class="description">
133
+ <?php echo esc_html( $setting['description'] ); ?>
134
+ </p>
135
+ </tr>
136
  <?php
137
+ }//end foreach
138
+ ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  </table>
140
 
141
  <?php submit_button( __( 'Save Changes', 'lingotek-translation' ), 'primary', 'submit', false ); ?>
admin/settings/view-utilities.php CHANGED
@@ -13,11 +13,11 @@ if ( ! empty( $_POST ) ) {
13
  }
14
  }
15
 
16
- $utility_cancel = filter_input(INPUT_POST, 'utility_cancel');
17
- if(!empty($utility_cancel)){
18
  $ids = Lingotek_Utilities::get_all_document_ids();
19
- if(!empty($ids)){
20
- printf('<div id="lingotek-progressdialog" title="%s"><div id="lingotek-progressbar"></div></div>', esc_html(__('Cancelling content...', 'lingotek-translation')));
21
  }
22
  }
23
 
@@ -29,14 +29,15 @@ if ( ! empty( $_POST ) ) {
29
  $GLOBALS['wp_lingotek']->utilities->run_utilities( $utilities );
30
 
31
  settings_errors();
32
- }
33
 
34
  ?>
35
  <h3><?php esc_html_e( 'Utilities', 'lingotek-translation' ); ?></h3>
36
  <p class="description"><?php esc_html_e( 'These utilities are designed to help you prepare and maintain your multilingual content.', 'lingotek-translation' ); ?></p>
37
 
38
  <h4><?php esc_html_e( 'Language', 'lingotek-translation' ); ?></h4>
39
- <form id="lingotek-utilities" method="post" action="admin.php?page=<?php echo esc_attr( $page_key ); ?>" class="validate"><?php
 
40
  wp_nonce_field( $page_key, '_wpnonce_' . $page_key );
41
 
42
  $allowed_html = array(
@@ -50,28 +51,28 @@ if ( ! empty( $_POST ) ) {
50
 
51
  ?>
52
 
53
- <h4><?php esc_html_e('Cancellation', 'lingotek-translation');?></h4>
54
  <?php
55
 
56
  printf(
57
  '<p><input type="checkbox" name="%1$s" id="%1$s"/><label for="%1$s">%2$s</label></p>',
58
  'utility_cancel',
59
- esc_html(__('Cancel any existing content from your Lingotek community', 'lingotek-translation'))
60
  );
61
  ?>
62
-
63
  <h4><?php esc_html_e( 'Deletion', 'lingotek-translation' ); ?></h4>
64
  <?php
65
 
66
  printf(
67
  '<p><input type="checkbox" name="%1$s" id="%1$s"/><label for="%1$s">%2$s</label></p>',
68
  'utility_disassociate',
69
- esc_html( __( 'Delete all unfinished documents from WordPress and cancel corresponding documents from your Lingotek Community.', 'lingotek-translation' ) ) . " <b>Use with caution.</b>"
70
- );
71
 
72
  $confirm_delete = __( 'You are about to delete all your content from your Lingotek community. Are you sure ?', 'lingotek-translation' );
73
 
74
- $confirm_cancel = __('You are about to cancel all of your content from your Lingotek community. Are you sure ?', 'lingotek-translation');
75
 
76
  $confirm_js = "
77
  d = document.getElementById('utility_disassociate');
@@ -82,5 +83,7 @@ if ( ! empty( $_POST ) ) {
82
  return confirm('$confirm_cancel');
83
  }";
84
 
85
- submit_button( __( 'Run Utilities', 'lingotek-translation' ), 'primary', 'submit', true, sprintf( 'onclick="%s"', $confirm_js ) ); ?>
86
- </form><?php
 
 
13
  }
14
  }
15
 
16
+ $utility_cancel = filter_input( INPUT_POST, 'utility_cancel' );
17
+ if ( ! empty( $utility_cancel ) ) {
18
  $ids = Lingotek_Utilities::get_all_document_ids();
19
+ if ( ! empty( $ids ) ) {
20
+ printf( '<div id="lingotek-progressdialog" title="%s"><div id="lingotek-progressbar"></div></div>', esc_html( __( 'Cancelling content...', 'lingotek-translation' ) ) );
21
  }
22
  }
23
 
29
  $GLOBALS['wp_lingotek']->utilities->run_utilities( $utilities );
30
 
31
  settings_errors();
32
+ }//end if
33
 
34
  ?>
35
  <h3><?php esc_html_e( 'Utilities', 'lingotek-translation' ); ?></h3>
36
  <p class="description"><?php esc_html_e( 'These utilities are designed to help you prepare and maintain your multilingual content.', 'lingotek-translation' ); ?></p>
37
 
38
  <h4><?php esc_html_e( 'Language', 'lingotek-translation' ); ?></h4>
39
+ <form id="lingotek-utilities" method="post" action="admin.php?page=<?php echo esc_attr( $page_key ); ?>" class="validate">
40
+ <?php
41
  wp_nonce_field( $page_key, '_wpnonce_' . $page_key );
42
 
43
  $allowed_html = array(
51
 
52
  ?>
53
 
54
+ <h4><?php esc_html_e( 'Cancellation', 'lingotek-translation' ); ?></h4>
55
  <?php
56
 
57
  printf(
58
  '<p><input type="checkbox" name="%1$s" id="%1$s"/><label for="%1$s">%2$s</label></p>',
59
  'utility_cancel',
60
+ esc_html( __( 'Cancel any existing content from your Lingotek community', 'lingotek-translation' ) )
61
  );
62
  ?>
63
+
64
  <h4><?php esc_html_e( 'Deletion', 'lingotek-translation' ); ?></h4>
65
  <?php
66
 
67
  printf(
68
  '<p><input type="checkbox" name="%1$s" id="%1$s"/><label for="%1$s">%2$s</label></p>',
69
  'utility_disassociate',
70
+ esc_html( __( 'Delete all unfinished documents from WordPress and cancel corresponding documents from your Lingotek Community.', 'lingotek-translation' ) ) . ' <b>Use with caution.</b>'
71
+ );
72
 
73
  $confirm_delete = __( 'You are about to delete all your content from your Lingotek community. Are you sure ?', 'lingotek-translation' );
74
 
75
+ $confirm_cancel = __( 'You are about to cancel all of your content from your Lingotek community. Are you sure ?', 'lingotek-translation' );
76
 
77
  $confirm_js = "
78
  d = document.getElementById('utility_disassociate');
83
  return confirm('$confirm_cancel');
84
  }";
85
 
86
+ submit_button( __( 'Run Utilities', 'lingotek-translation' ), 'primary', 'submit', true, sprintf( 'onclick="%s"', $confirm_js ) );
87
+ ?>
88
+ </form>
89
+ <?php
admin/string-actions.php CHANGED
@@ -28,7 +28,6 @@ class Lingotek_String_actions extends Lingotek_Actions {
28
  */
29
  protected function get_language( $name ) {
30
  return $this->pllm->get_language( $this->pllm->options['default_lang'] );
31
- ;
32
  }
33
 
34
 
@@ -53,7 +52,7 @@ class Lingotek_String_actions extends Lingotek_Actions {
53
  * @return string
54
  */
55
  protected function get_action_link( $args, $warning = false ) {
56
- $args['page'] = 'lingotek-translation_manage';
57
  $args['noheader'] = true;
58
  return parent::get_action_link( $args, $warning );
59
  }
@@ -78,7 +77,6 @@ class Lingotek_String_actions extends Lingotek_Actions {
78
  * @param string $action action.
79
  */
80
  public function manage_actions( $action ) {
81
-
82
  $redirect = remove_query_arg( array( 'action', 'action2' ), wp_get_referer() );
83
  if ( ! $redirect ) {
84
  $redirect = admin_url( 'admin.php?page=lingotek-translation_manage&sm=strings' );
@@ -120,13 +118,13 @@ class Lingotek_String_actions extends Lingotek_Actions {
120
 
121
  default:
122
  if ( ! $this->_manage_actions( $action ) ) {
123
- return; // do not redirect if this is not one of our actions.
 
124
  }
125
- }
126
 
127
  wp_redirect( $redirect );
128
  exit();
129
-
130
  }
131
 
132
  /**
28
  */
29
  protected function get_language( $name ) {
30
  return $this->pllm->get_language( $this->pllm->options['default_lang'] );
 
31
  }
32
 
33
 
52
  * @return string
53
  */
54
  protected function get_action_link( $args, $warning = false ) {
55
+ $args['page'] = 'lingotek-translation_manage';
56
  $args['noheader'] = true;
57
  return parent::get_action_link( $args, $warning );
58
  }
77
  * @param string $action action.
78
  */
79
  public function manage_actions( $action ) {
 
80
  $redirect = remove_query_arg( array( 'action', 'action2' ), wp_get_referer() );
81
  if ( ! $redirect ) {
82
  $redirect = admin_url( 'admin.php?page=lingotek-translation_manage&sm=strings' );
118
 
119
  default:
120
  if ( ! $this->_manage_actions( $action ) ) {
121
+ // Do not redirect if this is not one of our actions.
122
+ return;
123
  }
124
+ }//end switch
125
 
126
  wp_redirect( $redirect );
127
  exit();
 
128
  }
129
 
130
  /**
admin/strings-table.php CHANGED
@@ -1,7 +1,8 @@
1
  <?php
2
 
3
  if ( ! class_exists( 'WP_List_Table' ) ) {
4
- require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' ); // since WP 3.1.
 
5
  }
6
 
7
  /**
@@ -34,12 +35,15 @@ class Lingotek_Strings_Table extends WP_List_Table {
34
  * @param string $string_actions string actions.
35
  */
36
  function __construct( $string_actions ) {
37
- parent::__construct(array(
38
- 'plural' => 'lingotek-strings-translations', // do not translate (used for css class).
39
- 'ajax' => false,
40
- ));
41
- $this->pllm = $GLOBALS['polylang']->model;
42
- $this->lgtm = $GLOBALS['wp_lingotek']->model;
 
 
 
43
  $this->string_actions = $string_actions;
44
  }
45
 
@@ -59,49 +63,51 @@ class Lingotek_Strings_Table extends WP_List_Table {
59
 
60
  // language column.
61
  $language = $this->pllm->get_language( substr( $column_name, 9 ) );
62
- $document = $this->lgtm->get_group( 'string', $item['context'] ); // FIXME.
63
-
64
 
65
- $workflow_id = Lingotek_Model::get_profile_option('workflow_id', 'string', $language);
66
- $workflow = Lingotek_Workflow_Factory::get_workflow_instance( $workflow_id ); // TODO: put workflow_id here. It is currently not set up.
67
- $workflow->echo_strings_modal($item['row'], $language->locale);
 
68
 
69
  $allowed_html = array(
70
- 'a' => array(
71
- 'class' => array(),
72
- 'title' => array(),
73
- 'href' => array(),
74
- ),
75
- 'img' => array(
76
- 'src' => array()
77
- ),
78
- 'div' => array(
79
- 'title' => array(),
80
- 'class' => array(),
81
- ),
82
  );
83
  // post ready for upload.
84
  if ( $this->lgtm->can_upload( 'string', $item['context'] ) && $language->slug === $this->pllm->options['default_lang'] ) {
85
  echo wp_kses( $this->string_actions->upload_icon( $item['context'] ), $allowed_html );
86
- } // translation disabled.
87
  elseif ( isset( $document->source ) && $document->is_disabled_target( $language ) ) {
88
  echo '<div class="lingotek-color dashicons dashicons-no"></div>';
89
  } // source post is uploaded.
90
  elseif ( isset( $document->source ) && $document->source === $language->mo_id ) {
91
  echo wp_kses( 'importing' === $document->status ? Lingotek_Actions::importing_icon( $document ) : Lingotek_String_actions::uploaded_icon( $item['context'] ), $allowed_html );
92
  } // translations.
93
- elseif ( isset( $document->translations[ $language->locale ] ) || (isset( $document->source ) && 'current' === $document->status) && Lingotek::is_allowed_tms_locale($language->lingotek_locale)) {
94
  echo wp_kses( Lingotek_Actions::translation_icon( $document, $language ), $allowed_html );
95
  } // no translation.
96
- else { echo '<div class="lingotek-color dashicons dashicons-no"></div>';
 
97
  }
98
 
99
  $language_only = 'language_' . $language->slug;
100
- $errors = get_option( 'lingotek_log_errors' );
101
  if ( $language_only === $this->get_first_language_column() ) {
102
  if ( isset( $errors[ $item['context'] ] ) ) {
103
  $api_error = Lingotek_Actions::retrieve_api_error( $errors[ $item['context'] ] );
104
- echo Lingotek_Actions::display_error_icon( 'error', $api_error );
105
  }
106
  }
107
  }
@@ -140,9 +146,9 @@ class Lingotek_Strings_Table extends WP_List_Table {
140
  */
141
  function get_columns() {
142
  $columns = array(
143
- 'cb' => '<input type="checkbox" />', // checkbox.
144
- 'context' => __( 'Group', 'lingotek-translation' ),
145
- 'count' => __( 'Count', 'lingotek-translation' ),
146
  );
147
 
148
  foreach ( $GLOBALS['polylang']->model->get_languages_list() as $lang ) {
@@ -178,7 +184,7 @@ class Lingotek_Strings_Table extends WP_List_Table {
178
  * @param array $data data.
179
  */
180
  function prepare_items( $data = array() ) {
181
- $per_page = $this->get_items_per_page( 'lingotek_strings_per_page' );
182
  $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() );
183
 
184
  /**
@@ -189,24 +195,29 @@ class Lingotek_Strings_Table extends WP_List_Table {
189
  * @return int sort direction.
190
  */
191
  function usort_reorder( $a, $b ) {
192
- $order = filter_input( INPUT_GET, 'order' );
193
  $orderby = filter_input( INPUT_GET, 'orderby' );
194
- $result = strcmp( $a[ $orderby ], $b[ $orderby ] ); // determine sort order.
195
- return (empty( $order ) || 'asc' === $order ) ? $result : -$result; // send final sort direction to usort.
 
 
196
  };
197
 
198
- if ( ! empty( $orderby ) ) { // no sort by default.
 
199
  usort( $data, 'usort_reorder' );
200
  }
201
 
202
  $total_items = count( $data );
203
- $this->items = array_slice( $data, ($this->get_pagenum() - 1) * $per_page, $per_page );
204
-
205
- $this->set_pagination_args(array(
206
- 'total_items' => $total_items,
207
- 'per_page' => $per_page,
208
- 'total_pages' => ceil( $total_items / $per_page ),
209
- ));
 
 
210
  }
211
 
212
  /**
1
  <?php
2
 
3
  if ( ! class_exists( 'WP_List_Table' ) ) {
4
+ // since WP 3.1.
5
+ require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
6
  }
7
 
8
  /**
35
  * @param string $string_actions string actions.
36
  */
37
  function __construct( $string_actions ) {
38
+ parent::__construct(
39
+ array(
40
+ // Do not translate (used for css class).
41
+ 'plural' => 'lingotek-strings-translations',
42
+ 'ajax' => false,
43
+ )
44
+ );
45
+ $this->pllm = $GLOBALS['polylang']->model;
46
+ $this->lgtm = $GLOBALS['wp_lingotek']->model;
47
  $this->string_actions = $string_actions;
48
  }
49
 
63
 
64
  // language column.
65
  $language = $this->pllm->get_language( substr( $column_name, 9 ) );
66
+ // FIXME.
67
+ $document = $this->lgtm->get_group( 'string', $item['context'] );
68
 
69
+ $workflow_id = Lingotek_Model::get_profile_option( 'workflow_id', 'string', $language );
70
+ // TODO: put workflow_id here. It is currently not set up.
71
+ $workflow = Lingotek_Workflow_Factory::get_workflow_instance( $workflow_id );
72
+ $workflow->echo_strings_modal( $item['row'], $language->locale );
73
 
74
  $allowed_html = array(
75
+ 'a' => array(
76
+ 'class' => array(),
77
+ 'title' => array(),
78
+ 'href' => array(),
79
+ ),
80
+ 'img' => array(
81
+ 'src' => array(),
82
+ ),
83
+ 'div' => array(
84
+ 'title' => array(),
85
+ 'class' => array(),
86
+ ),
87
  );
88
  // post ready for upload.
89
  if ( $this->lgtm->can_upload( 'string', $item['context'] ) && $language->slug === $this->pllm->options['default_lang'] ) {
90
  echo wp_kses( $this->string_actions->upload_icon( $item['context'] ), $allowed_html );
91
+ } //end if
92
  elseif ( isset( $document->source ) && $document->is_disabled_target( $language ) ) {
93
  echo '<div class="lingotek-color dashicons dashicons-no"></div>';
94
  } // source post is uploaded.
95
  elseif ( isset( $document->source ) && $document->source === $language->mo_id ) {
96
  echo wp_kses( 'importing' === $document->status ? Lingotek_Actions::importing_icon( $document ) : Lingotek_String_actions::uploaded_icon( $item['context'] ), $allowed_html );
97
  } // translations.
98
+ elseif ( isset( $document->translations[ $language->locale ] ) || ( isset( $document->source ) && 'current' === $document->status ) && Lingotek::is_allowed_tms_locale( $language->lingotek_locale ) ) {
99
  echo wp_kses( Lingotek_Actions::translation_icon( $document, $language ), $allowed_html );
100
  } // no translation.
101
+ else {
102
+ echo '<div class="lingotek-color dashicons dashicons-no"></div>';
103
  }
104
 
105
  $language_only = 'language_' . $language->slug;
106
+ $errors = get_option( 'lingotek_log_errors' );
107
  if ( $language_only === $this->get_first_language_column() ) {
108
  if ( isset( $errors[ $item['context'] ] ) ) {
109
  $api_error = Lingotek_Actions::retrieve_api_error( $errors[ $item['context'] ] );
110
+ echo Lingotek_Actions::display_error_icon( 'error', $api_error );
111
  }
112
  }
113
  }
146
  */
147
  function get_columns() {
148
  $columns = array(
149
+ 'cb' => '<input type="checkbox" />',
150
+ 'context' => __( 'Group', 'lingotek-translation' ),
151
+ 'count' => __( 'Count', 'lingotek-translation' ),
152
  );
153
 
154
  foreach ( $GLOBALS['polylang']->model->get_languages_list() as $lang ) {
184
  * @param array $data data.
185
  */
186
  function prepare_items( $data = array() ) {
187
+ $per_page = $this->get_items_per_page( 'lingotek_strings_per_page' );
188
  $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() );
189
 
190
  /**
195
  * @return int sort direction.
196
  */
197
  function usort_reorder( $a, $b ) {
198
+ $order = filter_input( INPUT_GET, 'order' );
199
  $orderby = filter_input( INPUT_GET, 'orderby' );
200
+ // Determine sort order.
201
+ $result = strcmp( $a[ $orderby ], $b[ $orderby ] );
202
+ // Send final sort direction to usort.
203
+ return ( empty( $order ) || 'asc' === $order ) ? $result : -$result;
204
  };
205
 
206
+ // no sort by default.
207
+ if ( ! empty( $orderby ) ) {
208
  usort( $data, 'usort_reorder' );
209
  }
210
 
211
  $total_items = count( $data );
212
+ $this->items = array_slice( $data, ( $this->get_pagenum() - 1 ) * $per_page, $per_page );
213
+
214
+ $this->set_pagination_args(
215
+ array(
216
+ 'total_items' => $total_items,
217
+ 'per_page' => $per_page,
218
+ 'total_pages' => ceil( $total_items / $per_page ),
219
+ )
220
+ );
221
  }
222
 
223
  /**
admin/table-string.php CHANGED
@@ -20,11 +20,14 @@ class Lingotek_Table_String extends PLL_Table_String {
20
  $input_type = $item['multiline'] ?
21
  '<textarea name="translation[%1$s][%2$s]" id="%1$s-%2$s" disabled="disabled">%4$s</textarea>' :
22
  '<input type="text" name="translation[%1$s][%2$s]" id="%1$s-%2$s" value="%4$s" disabled="disabled" />';
23
- $out .= sprintf('<div class="translation"><label for="%1$s-%2$s">%3$s</label>' . $input_type . '</div>' . "\n",
 
24
  esc_attr( $key ),
25
  esc_attr( $item['row'] ),
26
  esc_html( $this->languages['languages'][ $key ] ),
27
- format_to_edit( $translation )); // don't interpret special chars.
 
 
28
  }
29
  return $out;
30
  }
@@ -49,7 +52,7 @@ class Lingotek_Table_String extends PLL_Table_String {
49
  // Load translations.
50
  foreach ( $listlanguages as $language ) {
51
  // filters by language if requested.
52
- if ( ($lg = get_user_meta( get_current_user_id(), 'pll_filter_content', true )) && $language->slug !== $lg ) {
53
  continue;
54
  }
55
 
@@ -57,25 +60,29 @@ class Lingotek_Table_String extends PLL_Table_String {
57
  $mo->import_from_db( $language );
58
  foreach ( $data as $key => $row ) {
59
  $data[ $key ]['translations'][ $language->slug ] = $mo->translate( $row['string'] );
60
- $data[ $key ]['row'] = $key; // store the row number for convenience.
 
61
  }
62
  }
63
 
64
- $per_page = $this->get_items_per_page( 'pll_strings_per_page' );
65
  $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() );
66
 
67
  $orderby = filter_input( INPUT_GET, 'orderby' );
68
- if ( ! empty( $orderby ) ) { // No sort by default.
 
69
  usort( $data, array( $this, 'usort_reorder' ) );
70
  }
71
 
72
  $total_items = count( $data );
73
  $this->items = array_slice( $data, ( $this->get_pagenum() - 1 ) * $per_page, $per_page );
74
 
75
- $this->set_pagination_args( array(
76
- 'total_items' => $total_items,
77
- 'per_page' => $per_page,
78
- 'total_pages' => ceil( $total_items / $per_page ),
79
- ) );
 
 
80
  }
81
  }
20
  $input_type = $item['multiline'] ?
21
  '<textarea name="translation[%1$s][%2$s]" id="%1$s-%2$s" disabled="disabled">%4$s</textarea>' :
22
  '<input type="text" name="translation[%1$s][%2$s]" id="%1$s-%2$s" value="%4$s" disabled="disabled" />';
23
+ $out .= sprintf(
24
+ '<div class="translation"><label for="%1$s-%2$s">%3$s</label>' . $input_type . '</div>' . "\n",
25
  esc_attr( $key ),
26
  esc_attr( $item['row'] ),
27
  esc_html( $this->languages['languages'][ $key ] ),
28
+ // Don't interpret special chars.
29
+ format_to_edit( $translation )
30
+ );
31
  }
32
  return $out;
33
  }
52
  // Load translations.
53
  foreach ( $listlanguages as $language ) {
54
  // filters by language if requested.
55
+ if ( ( $lg = get_user_meta( get_current_user_id(), 'pll_filter_content', true ) ) && $language->slug !== $lg ) {
56
  continue;
57
  }
58
 
60
  $mo->import_from_db( $language );
61
  foreach ( $data as $key => $row ) {
62
  $data[ $key ]['translations'][ $language->slug ] = $mo->translate( $row['string'] );
63
+ // Store the row number for convenience.
64
+ $data[ $key ]['row'] = $key;
65
  }
66
  }
67
 
68
+ $per_page = $this->get_items_per_page( 'pll_strings_per_page' );
69
  $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() );
70
 
71
  $orderby = filter_input( INPUT_GET, 'orderby' );
72
+ // No sort by default.
73
+ if ( ! empty( $orderby ) ) {
74
  usort( $data, array( $this, 'usort_reorder' ) );
75
  }
76
 
77
  $total_items = count( $data );
78
  $this->items = array_slice( $data, ( $this->get_pagenum() - 1 ) * $per_page, $per_page );
79
 
80
+ $this->set_pagination_args(
81
+ array(
82
+ 'total_items' => $total_items,
83
+ 'per_page' => $per_page,
84
+ 'total_pages' => ceil( $total_items / $per_page ),
85
+ )
86
+ );
87
  }
88
  }
admin/term-actions.php CHANGED
@@ -14,13 +14,14 @@ class Lingotek_Term_actions extends Lingotek_Actions {
14
  * @since 0.2
15
  */
16
  public function __construct() {
17
- parent::__construct('term');
18
 
19
- foreach ($this->pllm->get_translated_taxonomies() as $taxonomy)
20
- add_filter( $taxonomy . '_row_actions', array(&$this, 'term_row_actions'), 10, 2);
 
21
 
22
  // add_action('admin_footer-edit-tags.php', array(&$this, 'add_bulk_actions')); // FIXME admin_print_footer_scripts instead?
23
- add_action('load-edit-tags.php', array(&$this, 'manage_actions'));
24
  }
25
 
26
  /*
@@ -31,8 +32,8 @@ class Lingotek_Term_actions extends Lingotek_Actions {
31
  * @param int $term_id
32
  * @return object
33
  */
34
- protected function get_language($term_id) {
35
- return PLL()->model->term->get_language($term_id);
36
  }
37
 
38
  /*
@@ -42,11 +43,12 @@ class Lingotek_Term_actions extends Lingotek_Actions {
42
  *
43
  * @param int $id
44
  */
45
- public static function uploaded_icon($id) {
46
- $post_type = isset($GLOBALS['post_type']) ? $GLOBALS['post_type'] : $_REQUEST['post_type']; // 2nd case for quick edit
47
- $taxonomy = isset($GLOBALS['taxonomy']) ? $GLOBALS['taxonomy'] : $_REQUEST['taxonomy'];
48
- $link = get_edit_term_link($id, $taxonomy, $post_type);
49
- return self::display_icon('uploaded', $link);
 
50
  }
51
 
52
  /*
@@ -58,15 +60,16 @@ class Lingotek_Term_actions extends Lingotek_Actions {
58
  * @param object $term
59
  * @return array
60
  */
61
- public function term_row_actions($actions, $term) {
62
- if ($this->pllm->is_translated_taxonomy($term->taxonomy)) {
63
- $actions = $this->_row_actions($actions, $term->term_id);
64
-
65
- $language = PLL()->model->term->get_language($term->term_id);
66
- if (!empty($language)) {
67
- $profile = Lingotek_Model::get_profile($term->taxonomy, $language);
68
- if ('disabled' == $profile['profile'])
69
- unset($actions['lingotek-upload']);
 
70
  }
71
  }
72
  return $actions;
@@ -90,95 +93,103 @@ class Lingotek_Term_actions extends Lingotek_Actions {
90
  public function manage_actions() {
91
  global $taxnow, $post_type;
92
 
93
- if (!$this->pllm->is_translated_taxonomy($taxnow))
94
  return;
 
95
 
96
  // get the action
97
- $wp_list_table = _get_list_table('WP_Terms_List_Table');
98
- $action = $wp_list_table->current_action();
99
 
100
- if (empty($action))
101
  return;
 
102
 
103
- $redirect = remove_query_arg( array('action', 'action2', 'delete_tags'), wp_get_referer() );
104
- if (!$redirect)
105
- $redirect = admin_url("edit-tags.php?taxonomy=$taxnow&post_type=$post_type");
 
106
 
107
- switch($action) {
108
  case 'bulk-lingotek-upload':
109
- if (empty($_REQUEST['delete_tags']))
110
  return;
 
111
 
112
  $term_ids = array();
113
 
114
- foreach (array_map('intval', $_REQUEST['delete_tags']) as $term_id) {
115
  // safe upload
116
- if ($this->lgtm->can_upload('term', $term_id))
117
  $term_ids[] = $term_id;
 
118
 
119
  // the document is already translated so will be overwritten
120
- elseif(($document = $this->lgtm->get_group('term', $term_id)) && empty($document->source)) {
121
  // take care to upload only one post in a translation group
122
- $intersect = array_intersect($term_ids, PLL()->model->term->get_translations($term_id));
123
- if (empty($intersect)) {
124
  $term_ids[] = $term_id;
125
- $redirect = add_query_arg('lingotek_warning', 1, $redirect);
126
  }
127
  }
128
  }
129
 
130
  // check if translation is disabled
131
- if (!empty($term_ids)) {
132
- foreach ($term_ids as $key => $term_id) {
133
- $language = PLL()->model->term->get_language($term_id);
134
- $profile = Lingotek_Model::get_profile($taxnow, $language);
135
- if ('disabled' == $profile['profile'])
136
- unset($term_ids[$key]);
 
137
  }
138
  }
139
  case 'bulk-lingotek-request':
140
  case 'bulk-lingotek-download':
141
  case 'bulk-lingotek-status':
142
  case 'bulk-lingotek-delete':
143
- if (empty($_REQUEST['delete_tags']))
144
  return;
 
145
 
146
- if (empty($term_ids))
147
- $term_ids = array_map('intval', $_REQUEST['delete_tags']);
 
148
 
149
- check_admin_referer('bulk-tags');
150
 
151
- $redirect = add_query_arg($action, 1, $redirect);
152
- $redirect = add_query_arg('ids', implode(',', $term_ids), $redirect);
153
 
154
  break;
155
 
156
  case 'lingotek-upload':
157
- check_admin_referer('lingotek-upload');
158
- $id = filter_input( INPUT_GET, 'term');
159
- $document = $this->lgtm->get_group('term', $id);
160
- $this->lgtm->upload_post($id);
161
- $redirect = add_query_arg( 'id', filter_input( INPUT_GET, 'term'), $redirect);
162
- $redirect = add_query_arg( 'type', 'term', $redirect);
163
- $redirect = add_query_arg( 'source', $this->pllm->term->get_language($id)->locale, $redirect);
164
  break;
165
 
166
- case 'lingotek-copy':
167
  check_admin_referer( 'lingotek-copy' );
168
  $term_to_copy = get_term( (int) filter_input( INPUT_GET, 'term' ) );
169
- $target = filter_input( INPUT_GET, 'target' );
170
- $this->lgtm->copy_term( $term_to_copy, $target, $taxnow);
171
  break;
172
 
173
  default:
174
- if (!$this->_manage_actions($action))
175
- return; // do not redirect if this is not one of our actions
176
-
177
- }
 
178
 
179
- wp_redirect($redirect);
180
  exit();
181
-
182
  }
183
 
184
  /*
@@ -187,11 +198,12 @@ class Lingotek_Term_actions extends Lingotek_Actions {
187
  * @since 0.1
188
  */
189
  public function ajax_upload() {
190
- check_ajax_referer('lingotek_progress', '_lingotek_nonce');
191
- $id = (int)filter_input(INPUT_POST, 'id');
192
- $taxonomy = filter_input( INPUT_POST, 'taxonomy');
193
- if (taxonomy_exists($_POST['taxonomy']))
194
- $this->lgtm->upload_term($id, $taxonomy);
 
195
  die();
196
  }
197
  }
14
  * @since 0.2
15
  */
16
  public function __construct() {
17
+ parent::__construct( 'term' );
18
 
19
+ foreach ( $this->pllm->get_translated_taxonomies() as $taxonomy ) {
20
+ add_filter( $taxonomy . '_row_actions', array( &$this, 'term_row_actions' ), 10, 2 );
21
+ }
22
 
23
  // add_action('admin_footer-edit-tags.php', array(&$this, 'add_bulk_actions')); // FIXME admin_print_footer_scripts instead?
24
+ add_action( 'load-edit-tags.php', array( &$this, 'manage_actions' ) );
25
  }
26
 
27
  /*
32
  * @param int $term_id
33
  * @return object
34
  */
35
+ protected function get_language( $term_id ) {
36
+ return PLL()->model->term->get_language( $term_id );
37
  }
38
 
39
  /*
43
  *
44
  * @param int $id
45
  */
46
+ public static function uploaded_icon( $id ) {
47
+ // 2nd case for quick edit
48
+ $post_type = isset( $GLOBALS['post_type'] ) ? $GLOBALS['post_type'] : $_REQUEST['post_type'];
49
+ $taxonomy = isset( $GLOBALS['taxonomy'] ) ? $GLOBALS['taxonomy'] : $_REQUEST['taxonomy'];
50
+ $link = get_edit_term_link( $id, $taxonomy, $post_type );
51
+ return self::display_icon( 'uploaded', $link );
52
  }
53
 
54
  /*
60
  * @param object $term
61
  * @return array
62
  */
63
+ public function term_row_actions( $actions, $term ) {
64
+ if ( $this->pllm->is_translated_taxonomy( $term->taxonomy ) ) {
65
+ $actions = $this->_row_actions( $actions, $term->term_id );
66
+
67
+ $language = PLL()->model->term->get_language( $term->term_id );
68
+ if ( ! empty( $language ) ) {
69
+ $profile = Lingotek_Model::get_profile( $term->taxonomy, $language );
70
+ if ( 'disabled' == $profile['profile'] ) {
71
+ unset( $actions['lingotek-upload'] );
72
+ }
73
  }
74
  }
75
  return $actions;
93
  public function manage_actions() {
94
  global $taxnow, $post_type;
95
 
96
+ if ( ! $this->pllm->is_translated_taxonomy( $taxnow ) ) {
97
  return;
98
+ }
99
 
100
  // get the action
101
+ $wp_list_table = _get_list_table( 'WP_Terms_List_Table' );
102
+ $action = $wp_list_table->current_action();
103
 
104
+ if ( empty( $action ) ) {
105
  return;
106
+ }
107
 
108
+ $redirect = remove_query_arg( array( 'action', 'action2', 'delete_tags' ), wp_get_referer() );
109
+ if ( ! $redirect ) {
110
+ $redirect = admin_url( "edit-tags.php?taxonomy=$taxnow&post_type=$post_type" );
111
+ }
112
 
113
+ switch ( $action ) {
114
  case 'bulk-lingotek-upload':
115
+ if ( empty( $_REQUEST['delete_tags'] ) ) {
116
  return;
117
+ }
118
 
119
  $term_ids = array();
120
 
121
+ foreach ( array_map( 'intval', $_REQUEST['delete_tags'] ) as $term_id ) {
122
  // safe upload
123
+ if ( $this->lgtm->can_upload( 'term', $term_id ) ) {
124
  $term_ids[] = $term_id;
125
+ }
126
 
127
  // the document is already translated so will be overwritten
128
+ elseif ( ( $document = $this->lgtm->get_group( 'term', $term_id ) ) && empty( $document->source ) ) {
129
  // take care to upload only one post in a translation group
130
+ $intersect = array_intersect( $term_ids, PLL()->model->term->get_translations( $term_id ) );
131
+ if ( empty( $intersect ) ) {
132
  $term_ids[] = $term_id;
133
+ $redirect = add_query_arg( 'lingotek_warning', 1, $redirect );
134
  }
135
  }
136
  }
137
 
138
  // check if translation is disabled
139
+ if ( ! empty( $term_ids ) ) {
140
+ foreach ( $term_ids as $key => $term_id ) {
141
+ $language = PLL()->model->term->get_language( $term_id );
142
+ $profile = Lingotek_Model::get_profile( $taxnow, $language );
143
+ if ( 'disabled' == $profile['profile'] ) {
144
+ unset( $term_ids[ $key ] );
145
+ }
146
  }
147
  }
148
  case 'bulk-lingotek-request':
149
  case 'bulk-lingotek-download':
150
  case 'bulk-lingotek-status':
151
  case 'bulk-lingotek-delete':
152
+ if ( empty( $_REQUEST['delete_tags'] ) ) {
153
  return;
154
+ }
155
 
156
+ if ( empty( $term_ids ) ) {
157
+ $term_ids = array_map( 'intval', $_REQUEST['delete_tags'] );
158
+ }
159
 
160
+ check_admin_referer( 'bulk-tags' );
161
 
162
+ $redirect = add_query_arg( $action, 1, $redirect );
163
+ $redirect = add_query_arg( 'ids', implode( ',', $term_ids ), $redirect );
164
 
165
  break;
166
 
167
  case 'lingotek-upload':
168
+ check_admin_referer( 'lingotek-upload' );
169
+ $id = filter_input( INPUT_GET, 'term' );
170
+ $document = $this->lgtm->get_group( 'term', $id );
171
+ $this->lgtm->upload_post( $id );
172
+ $redirect = add_query_arg( 'id', filter_input( INPUT_GET, 'term' ), $redirect );
173
+ $redirect = add_query_arg( 'type', 'term', $redirect );
174
+ $redirect = add_query_arg( 'source', $this->pllm->term->get_language( $id )->locale, $redirect );
175
  break;
176
 
177
+ case 'lingotek-copy':
178
  check_admin_referer( 'lingotek-copy' );
179
  $term_to_copy = get_term( (int) filter_input( INPUT_GET, 'term' ) );
180
+ $target = filter_input( INPUT_GET, 'target' );
181
+ $this->lgtm->copy_term( $term_to_copy, $target, $taxnow );
182
  break;
183
 
184
  default:
185
+ if ( ! $this->_manage_actions( $action ) ) {
186
+ // do not redirect if this is not one of our actions.
187
+ return;
188
+ }
189
+ }//end switch
190
 
191
+ wp_redirect( $redirect );
192
  exit();
 
193
  }
194
 
195
  /*
198
  * @since 0.1
199
  */
200
  public function ajax_upload() {
201
+ check_ajax_referer( 'lingotek_progress', '_lingotek_nonce' );
202
+ $id = (int) filter_input( INPUT_POST, 'id' );
203
+ $taxonomy = filter_input( INPUT_POST, 'taxonomy' );
204
+ if ( taxonomy_exists( $_POST['taxonomy'] ) ) {
205
+ $this->lgtm->upload_term( $id, $taxonomy );
206
+ }
207
  die();
208
  }
209
  }
admin/tutorial/content.php CHANGED
@@ -19,132 +19,147 @@
19
  }
20
  </style>
21
  <h4>
22
- <?php _e('What Does The Lingotek Translation Plugin Do?', 'lingotek-translation') ?>
23
  <a id="cd-show-link-summary" class="dashicons dashicons-arrow-right" onclick="document.getElementById('ltk-summary').style.display = ''; document.getElementById('cd-hide-link-summary').style.display = ''; this.style.display = 'none'; return false;"></a>
24
  <a id="cd-hide-link-summary" class="dashicons dashicons-arrow-down" onclick="document.getElementById('ltk-summary').style.display = 'none'; document.getElementById('cd-show-link-summary').style.display = ''; this.style.display = 'none'; return false;" style="display: none;"></a>
25
  </h4>
26
- <p id="ltk-summary" style="display:none; margin-left: 25px;"><?php _e('Lingotek works in conjunction with the Polylang plugin (the plumbing to make WordPress multilingual ready) simplifying the process of creating and maintaining your multilingual website. You write posts, pages, and create categories and post tags as usual, and then define the language for each of them.', 'lingotek-translation') ?></p>
27
 
28
  <h4>
29
- <?php _e('Lingotek Translation General Overview', 'lingotek-translation') ?>
30
  <a id="cd-show-link-gen" class="dashicons dashicons-arrow-right" onclick="document.getElementById('gen-overview-tut').style.display = ''; document.getElementById('cd-hide-link-gen').style.display = ''; this.style.display = 'none'; return false;"></a>
31
  <a id="cd-hide-link-gen" class="dashicons dashicons-arrow-down" onclick="document.getElementById('gen-overview-tut').style.display = 'none'; document.getElementById('cd-show-link-gen').style.display = ''; this.style.display = 'none'; return false;" style="display: none;"></a>
32
  </h4>
33
  <div id="gen-overview-tut" style="display:none;margin-left: 25px;">
34
  <div>
35
- <h4><?php _e('1. Create content', 'lingotek-translation') ?></h4>
36
- <p><?php _e('Whether you write a blog post, create a page for your site, or have existing posts and pages, any of your Wordpress content can be uploaded to <i>Lingotek</i>.', 'lingotek-translation') ?>
37
- <?php _e('The examples shown below are for Pages but translation for other content types works the same way!', 'lingotek-translation') ?></p>
38
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/add-page.png'; ?>">
39
- <p class="img-caption"><?php _e('Create a new page for translation.', 'lingotek-translation') ?></p>
40
  </div>
41
  <div>
42
- <h4><?php _e('2. Upload content to Lingotek', 'lingotek-translation') ?></h4>
43
- <p><?php _e('Your Wordpress content can be uploaded to <i>Lingotek</i> with the simple push of a button.', 'lingotek-translation') ?></p>
44
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/ready-to-upload.png'; ?>">
45
- <p class="img-caption"><?php _e('Content has been created and is ready for upload to Lingotek.', 'lingotek-translation') ?></p>
46
  </div>
47
  <div>
48
- <h4><?php _e('3. Request translations for target languages', 'lingotek-translation') ?></h4>
49
- <p><?php _e('Request translation for a specific language by clicking on the orange plus icon, for all languages at once, or in bulk by using the <i>Bulk Actions</i> dropdown.', 'lingotek-translation') ?></p>
50
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/request-translations.png'; ?>">
51
- <p class="img-caption"><?php _e('The source content is uploaded and ready for target languages.', 'lingotek-translation') ?></p>
52
  </div>
53
  <div>
54
- <h4><?php _e('4. Translate your content', 'lingotek-translation') ?></h4>
55
- <p><?php _e('Your content will now be translated into your selected target languages by free machine translation or, if you contract with <i>Lingotek</i>, professional translation services.', 'lingotek-translation') ?></p>
56
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/translations-underway.png'; ?>">
57
- <p class="img-caption"><?php _e('Your translations are underway.', 'lingotek-translation') ?></p>
58
  </div>
59
  <div>
60
- <h4><?php _e('5. Download translations', 'lingotek-translation') ?></h4>
61
- <p><?php _e('Once your translations are complete they will be marked ready for download. You can download translations for all languages, each language individually, or in bulk (using the <i>Bulk Actions</i> dropdown).', 'lingotek-translation') ?></p>
62
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/translations-ready-for-download.png'; ?>">
63
- <p class="img-caption"><?php _e('Your translations are ready for download.', 'lingotek-translation') ?></p>
64
  </div>
65
  <div>
66
- <h4><?php _e('6. Your content is translated!', 'lingotek-translation') ?></h4>
67
- <p><?php _e('The orange pencil icons indicate that your translations are finished, downloaded, and current within your Wordpress site. Clicking on any one of the pencils will direct you to the Lingotek Workbench for that specific language. Here you can make updates and changes to your translations if necessary.', 'lingotek-translation') ?></p>
68
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/translations-downloaded.png'; ?>">
69
- <p class="img-caption"><?php _e('Your content has been translated.', 'lingotek-translation') ?></p>
70
  </div>
71
 
72
- <h2><?php _e('What do all the icons mean?', 'lingotek-translation') ?></h2>
73
 
74
  <table>
75
  <tr>
76
  <td><span class="lingotek-color dashicons dashicons-upload"></span></td>
77
- <th><?php _e('Upload Source', 'lingotek-translation') ?></th>
78
- <td><?php _e('There is content ready to be uploaded to Lingotek.', 'lingotek-translation') ?></td>
79
  </tr>
80
  <tr>
81
  <td><span class="lingotek-color dashicons dashicons-clock"></span></td>
82
- <th><?php _e('In Progress', 'lingotek-translation') ?></th>
83
- <td><?php _e('Content is importing to Lingotek or a target language is being added to source content.', 'lingotek-translation') ?></td>
84
  </tr>
85
  <tr>
86
  <td><span class="lingotek-color dashicons dashicons-yes"></span></td>
87
- <th><?php _e('Source Uploaded', 'lingotek-translation') ?></th>
88
- <td><?php _e('The source content has been uploaded to Lingotek.', 'lingotek-translation') ?></td>
89
  </tr>
90
  <tr>
91
  <td><span class="lingotek-color dashicons dashicons-plus"></span></td>
92
- <th><?php _e('Request Translation', 'lingotek-translation') ?></th>
93
- <td><?php _e('Request a translation of the source content. (Add a target language)', 'lingotek-translation') ?></td>
94
  </tr>
95
  <tr>
96
  <td><span class="lingotek-color dashicons dashicons-download"></span></td>
97
- <th><?php _e('Download Translation', 'lingotek-translation') ?></th>
98
- <td><?php _e('Download the translated content to Wordpress.', 'lingotek-translation') ?></td>
99
  </tr>
100
  <tr>
101
  <td><span class="lingotek-color dashicons dashicons-edit"></span></td>
102
- <th><?php _e('Translation Current', 'lingotek-translation') ?></th>
103
- <td><?php _e('The translation is complete. (Clicking on this icon will allow you to edit translations in the Lingotek Workbench)', 'lingotek-translation') ?></td>
104
  </tr>
105
  <tr>
106
  <td><span class="lingotek-color dashicons dashicons-warning"></span></td>
107
- <th><?php _e('Translation Cancelled', 'lingotek-translation') ?></th>
108
- <td><?php _e('The translation is cancelled. The source cannot be translated into this language again.', 'lingotek-translation') ?></td>
109
  </tr>
110
- <tr>
111
  <td><span class="lingotek-color dashicons dashicons-no"></span></td>
112
- <th><?php _e('Out of Sync', 'lingotek-translation') ?></th>
113
- <td><?php _e('You have made changes to source content. The source must be sent to Lingotek again for additional translation.', 'lingotek-translation') ?></td>
114
  </tr>
115
  </table>
116
  </div>
117
  <h4 id="ltk-prof-trans-header">
118
- <?php _e('Lingotek Professional Translation Overview', 'lingotek-translation') ?>
119
- <a id="cd-show-link" class="dashicons dashicons-arrow-right" onclick="document.getElementById('pro-translation-tut').style.display = ''; document.getElementById('cd-hide-link').style.display = ''; this.style.display = 'none'; return false;" style="<?php if ('ltk-prof' === filter_input(INPUT_GET, 'tutorial')) { echo 'display: none;'; } ?>"></a>
120
- <a id="cd-hide-link" class="dashicons dashicons-arrow-down" onclick="document.getElementById('pro-translation-tut').style.display = 'none'; document.getElementById('cd-show-link').style.display = ''; this.style.display = 'none'; return false;" style="<?php if ('ltk-prof' !== filter_input(INPUT_GET, 'tutorial')) { echo 'display: none;'; } ?>"></a>
 
 
 
 
 
 
 
 
 
 
121
  </h4>
122
- <div id="pro-translation-tut" style="<?php if ('ltk-prof' != filter_input(INPUT_GET, 'tutorial')) { echo 'display: none;'; } ?> margin-left: 25px;">
123
- <h4><?php _e('What Is Lingotek Professional Translation?', 'lingotek-translation') ?></h4>
124
- <p><?php _e('Lingotek Professional Translation is a workflow that allows you to connect with audiences around the globe using Lingotek\'s network of 5000+ professional, in-country, translators. Professional Translation ensures that your audiences will feel the sentiment of your content.', 'lingotek-translation') ?></p>
125
- <h4><?php _e('How To Use', 'lingotek-translation') ?></h4>
126
- <p><?php _e('Use the "Lingotek Professional Translation" workflow to enable this feature. This can be done from any of the following area in the Lingotek plugin settings:', 'lingotek-translation') ?></p>
 
 
 
 
 
127
  <ul>
128
- <li><strong><?php _e('Translation > Manage > Translation Profiles', 'lingotek-translation') ?></strong></li>
129
- <li><strong><?php _e('Translation > Settings > Defaults', 'lingotek-translation') ?></strong></li>
130
  </ul>
131
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/combined-selection.png'; ?>">
132
- <p><?php _e('After selecting this workflow a dialog box will pop up prompting you to enter a payment method. Clicking LATER will close the dialog box and allow you to come back later to add a payment method.', 'lingotek-translation') ?></p>
133
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/selection-workflow-from-list.png'; ?>">
134
- <p><?php _e('Clicking the ADD PAYMENT METHOD button will redirect you to the Lingotek Secure Payment Portal.', 'lingotek-translation') ?></p>
135
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/redirected-to-payment-portal-screen.png'; ?>">
136
- <p><?php _e('From the Payment Portal you will enter your payment information. Then you will be redirected back to your WordPress site.', 'lingotek-translation') ?></p>
137
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/redirected-to-payment-portal.png'; ?>">
138
- <p><?php _e('After the workflow has been set you can access the professional translation request menu by clicking on the orange plus icon located on any page that contains your posts.', 'lingotek-translation') ?></p>
139
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/request-translations.png'; ?>">
140
- <p><?php _e('When requesting a document for translation with the Lingotek Professional Translation workflow enabled you will see one of two dialog boxes. If you don\'t have a payment method set up you will see the following dialog box allowing you to view translation quotes on your selected documents.' , 'lingotek-translation') ?></p>
141
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/quote-calculator.png'; ?>">
142
- <p><?php _e('If you do have a payment method enabled you will see the following dialog box that will allow you to purchase your professional translations.', 'lingotek-translation') ?></p>
143
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/higher-res-buy-now.png'; ?>">
144
- <p><?php _e('After purchasing one or more professional translations you will see a success message and will receive a payment confirmation email.', 'lingotek-translation') ?></p>
145
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/purchased.png'; ?>">
146
- <p><?php _e('The status of your translation will change to the Translator icon while your document is being processed and translated.', 'lingotek-translation') ?></p>
147
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/professional-translation-icon.png'; ?>">
148
- <p><?php _e('You can set up or edit your payment method from the Translation > Settings > Account page.', 'lingotek-translation') ?></p>
149
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/change-account-settings.png'; ?>">
150
  </div>
19
  }
20
  </style>
21
  <h4>
22
+ <?php _e( 'What Does The Lingotek Translation Plugin Do?', 'lingotek-translation' ); ?>
23
  <a id="cd-show-link-summary" class="dashicons dashicons-arrow-right" onclick="document.getElementById('ltk-summary').style.display = ''; document.getElementById('cd-hide-link-summary').style.display = ''; this.style.display = 'none'; return false;"></a>
24
  <a id="cd-hide-link-summary" class="dashicons dashicons-arrow-down" onclick="document.getElementById('ltk-summary').style.display = 'none'; document.getElementById('cd-show-link-summary').style.display = ''; this.style.display = 'none'; return false;" style="display: none;"></a>
25
  </h4>
26
+ <p id="ltk-summary" style="display:none; margin-left: 25px;"><?php _e( 'Lingotek works in conjunction with the Polylang plugin (the plumbing to make WordPress multilingual ready) simplifying the process of creating and maintaining your multilingual website. You write posts, pages, and create categories and post tags as usual, and then define the language for each of them.', 'lingotek-translation' ); ?></p>
27
 
28
  <h4>
29
+ <?php _e( 'Lingotek Translation General Overview', 'lingotek-translation' ); ?>
30
  <a id="cd-show-link-gen" class="dashicons dashicons-arrow-right" onclick="document.getElementById('gen-overview-tut').style.display = ''; document.getElementById('cd-hide-link-gen').style.display = ''; this.style.display = 'none'; return false;"></a>
31
  <a id="cd-hide-link-gen" class="dashicons dashicons-arrow-down" onclick="document.getElementById('gen-overview-tut').style.display = 'none'; document.getElementById('cd-show-link-gen').style.display = ''; this.style.display = 'none'; return false;" style="display: none;"></a>
32
  </h4>
33
  <div id="gen-overview-tut" style="display:none;margin-left: 25px;">
34
  <div>
35
+ <h4><?php _e( '1. Create content', 'lingotek-translation' ); ?></h4>
36
+ <p><?php _e( 'Whether you write a blog post, create a page for your site, or have existing posts and pages, any of your WordPress content can be uploaded to <i>Lingotek</i>.', 'lingotek-translation' ); ?>
37
+ <?php _e( 'The examples shown below are for Pages but translation for other content types works the same way!', 'lingotek-translation' ); ?></p>
38
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/add-page.png'; ?>">
39
+ <p class="img-caption"><?php _e( 'Create a new page for translation.', 'lingotek-translation' ); ?></p>
40
  </div>
41
  <div>
42
+ <h4><?php _e( '2. Upload content to Lingotek', 'lingotek-translation' ); ?></h4>
43
+ <p><?php _e( 'Your WordPress content can be uploaded to <i>Lingotek</i> with the simple push of a button.', 'lingotek-translation' ); ?></p>
44
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/ready-to-upload.png'; ?>">
45
+ <p class="img-caption"><?php _e( 'Content has been created and is ready for upload to Lingotek.', 'lingotek-translation' ); ?></p>
46
  </div>
47
  <div>
48
+ <h4><?php _e( '3. Request translations for target languages', 'lingotek-translation' ); ?></h4>
49
+ <p><?php _e( 'Request translation for a specific language by clicking on the orange plus icon, for all languages at once, or in bulk by using the <i>Bulk Actions</i> dropdown.', 'lingotek-translation' ); ?></p>
50
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/request-translations.png'; ?>">
51
+ <p class="img-caption"><?php _e( 'The source content is uploaded and ready for target languages.', 'lingotek-translation' ); ?></p>
52
  </div>
53
  <div>
54
+ <h4><?php _e( '4. Translate your content', 'lingotek-translation' ); ?></h4>
55
+ <p><?php _e( 'Your content will now be translated into your selected target languages by free machine translation or, if you contract with <i>Lingotek</i>, professional translation services.', 'lingotek-translation' ); ?></p>
56
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/translations-underway.png'; ?>">
57
+ <p class="img-caption"><?php _e( 'Your translations are underway.', 'lingotek-translation' ); ?></p>
58
  </div>
59
  <div>
60
+ <h4><?php _e( '5. Download translations', 'lingotek-translation' ); ?></h4>
61
+ <p><?php _e( 'Once your translations are complete they will be marked ready for download. You can download translations for all languages, each language individually, or in bulk (using the <i>Bulk Actions</i> dropdown).', 'lingotek-translation' ); ?></p>
62
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/translations-ready-for-download.png'; ?>">
63
+ <p class="img-caption"><?php _e( 'Your translations are ready for download.', 'lingotek-translation' ); ?></p>
64
  </div>
65
  <div>
66
+ <h4><?php _e( '6. Your content is translated!', 'lingotek-translation' ); ?></h4>
67
+ <p><?php _e( 'The orange pencil icons indicate that your translations are finished, downloaded, and current within your WordPress site. Clicking on any one of the pencils will direct you to the Lingotek Workbench for that specific language. Here you can make updates and changes to your translations if necessary.', 'lingotek-translation' ); ?></p>
68
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/translations-downloaded.png'; ?>">
69
+ <p class="img-caption"><?php _e( 'Your content has been translated.', 'lingotek-translation' ); ?></p>
70
  </div>
71
 
72
+ <h2><?php _e( 'What do all the icons mean?', 'lingotek-translation' ); ?></h2>
73
 
74
  <table>
75
  <tr>
76
  <td><span class="lingotek-color dashicons dashicons-upload"></span></td>
77
+ <th><?php _e( 'Upload Source', 'lingotek-translation' ); ?></th>
78
+ <td><?php _e( 'There is content ready to be uploaded to Lingotek.', 'lingotek-translation' ); ?></td>
79
  </tr>
80
  <tr>
81
  <td><span class="lingotek-color dashicons dashicons-clock"></span></td>
82
+ <th><?php _e( 'In Progress', 'lingotek-translation' ); ?></th>
83
+ <td><?php _e( 'Content is importing to Lingotek or a target language is being added to source content.', 'lingotek-translation' ); ?></td>
84
  </tr>
85
  <tr>
86
  <td><span class="lingotek-color dashicons dashicons-yes"></span></td>
87
+ <th><?php _e( 'Source Uploaded', 'lingotek-translation' ); ?></th>
88
+ <td><?php _e( 'The source content has been uploaded to Lingotek.', 'lingotek-translation' ); ?></td>
89
  </tr>
90
  <tr>
91
  <td><span class="lingotek-color dashicons dashicons-plus"></span></td>
92
+ <th><?php _e( 'Request Translation', 'lingotek-translation' ); ?></th>
93
+ <td><?php _e( 'Request a translation of the source content. (Add a target language)', 'lingotek-translation' ); ?></td>
94
  </tr>
95
  <tr>
96
  <td><span class="lingotek-color dashicons dashicons-download"></span></td>
97
+ <th><?php _e( 'Download Translation', 'lingotek-translation' ); ?></th>
98
+ <td><?php _e( 'Download the translated content to WordPress.', 'lingotek-translation' ); ?></td>
99
  </tr>
100
  <tr>
101
  <td><span class="lingotek-color dashicons dashicons-edit"></span></td>
102
+ <th><?php _e( 'Translation Current', 'lingotek-translation' ); ?></th>
103
+ <td><?php _e( 'The translation is complete. (Clicking on this icon will allow you to edit translations in the Lingotek Workbench)', 'lingotek-translation' ); ?></td>
104
  </tr>
105
  <tr>
106
  <td><span class="lingotek-color dashicons dashicons-warning"></span></td>
107
+ <th><?php _e( 'Translation Cancelled', 'lingotek-translation' ); ?></th>
108
+ <td><?php _e( 'The translation is cancelled. The source cannot be translated into this language again.', 'lingotek-translation' ); ?></td>
109
  </tr>
110
+ <tr>
111
  <td><span class="lingotek-color dashicons dashicons-no"></span></td>
112
+ <th><?php _e( 'Out of Sync', 'lingotek-translation' ); ?></th>
113
+ <td><?php _e( 'You have made changes to source content. The source must be sent to Lingotek again for additional translation.', 'lingotek-translation' ); ?></td>
114
  </tr>
115
  </table>
116
  </div>
117
  <h4 id="ltk-prof-trans-header">
118
+ <?php _e( 'Lingotek Professional Translation Overview', 'lingotek-translation' ); ?>
119
+ <a id="cd-show-link" class="dashicons dashicons-arrow-right" onclick="document.getElementById('pro-translation-tut').style.display = ''; document.getElementById('cd-hide-link').style.display = ''; this.style.display = 'none'; return false;" style="
120
+ <?php
121
+ if ( 'ltk-prof' === filter_input( INPUT_GET, 'tutorial' ) ) {
122
+ echo 'display: none;'; }
123
+ ?>
124
+ "></a>
125
+ <a id="cd-hide-link" class="dashicons dashicons-arrow-down" onclick="document.getElementById('pro-translation-tut').style.display = 'none'; document.getElementById('cd-show-link').style.display = ''; this.style.display = 'none'; return false;" style="
126
+ <?php
127
+ if ( 'ltk-prof' !== filter_input( INPUT_GET, 'tutorial' ) ) {
128
+ echo 'display: none;'; }
129
+ ?>
130
+ "></a>
131
  </h4>
132
+ <div id="pro-translation-tut" style="
133
+ <?php
134
+ if ( 'ltk-prof' != filter_input( INPUT_GET, 'tutorial' ) ) {
135
+ echo 'display: none;'; }
136
+ ?>
137
+ margin-left: 25px;">
138
+ <h4><?php _e( 'What Is Lingotek Professional Translation?', 'lingotek-translation' ); ?></h4>
139
+ <p><?php _e( 'Lingotek Professional Translation is a workflow that allows you to connect with audiences around the globe using Lingotek\'s network of 5000+ professional, in-country, translators. Professional Translation ensures that your audiences will feel the sentiment of your content.', 'lingotek-translation' ); ?></p>
140
+ <h4><?php _e( 'How To Use', 'lingotek-translation' ); ?></h4>
141
+ <p><?php _e( 'Use the "Lingotek Professional Translation" workflow to enable this feature. This can be done from any of the following area in the Lingotek plugin settings:', 'lingotek-translation' ); ?></p>
142
  <ul>
143
+ <li><strong><?php _e( 'Translation > Manage > Translation Profiles', 'lingotek-translation' ); ?></strong></li>
144
+ <li><strong><?php _e( 'Translation > Settings > Defaults', 'lingotek-translation' ); ?></strong></li>
145
  </ul>
146
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/combined-selection.png'; ?>">
147
+ <p><?php _e( 'After selecting this workflow a dialog box will pop up prompting you to enter a payment method. Clicking LATER will close the dialog box and allow you to come back later to add a payment method.', 'lingotek-translation' ); ?></p>
148
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/selection-workflow-from-list.png'; ?>">
149
+ <p><?php _e( 'Clicking the ADD PAYMENT METHOD button will redirect you to the Lingotek Secure Payment Portal.', 'lingotek-translation' ); ?></p>
150
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/redirected-to-payment-portal-screen.png'; ?>">
151
+ <p><?php _e( 'From the Payment Portal you will enter your payment information. Then you will be redirected back to your WordPress site.', 'lingotek-translation' ); ?></p>
152
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/redirected-to-payment-portal.png'; ?>">
153
+ <p><?php _e( 'After the workflow has been set you can access the professional translation request menu by clicking on the orange plus icon located on any page that contains your posts.', 'lingotek-translation' ); ?></p>
154
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/request-translations.png'; ?>">
155
+ <p><?php _e( 'When requesting a document for translation with the Lingotek Professional Translation workflow enabled you will see one of two dialog boxes. If you don\'t have a payment method set up you will see the following dialog box allowing you to view translation quotes on your selected documents.', 'lingotek-translation' ); ?></p>
156
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/quote-calculator.png'; ?>">
157
+ <p><?php _e( 'If you do have a payment method enabled you will see the following dialog box that will allow you to purchase your professional translations.', 'lingotek-translation' ); ?></p>
158
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/higher-res-buy-now.png'; ?>">
159
+ <p><?php _e( 'After purchasing one or more professional translations you will see a success message and will receive a payment confirmation email.', 'lingotek-translation' ); ?></p>
160
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/purchased.png'; ?>">
161
+ <p><?php _e( 'The status of your translation will change to the Translator icon while your document is being processed and translated.', 'lingotek-translation' ); ?></p>
162
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/professional-translation-icon.png'; ?>">
163
+ <p><?php _e( 'You can set up or edit your payment method from the Translation > Settings > Account page.', 'lingotek-translation' ); ?></p>
164
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/change-account-settings.png'; ?>">
165
  </div>
admin/tutorial/credits.php CHANGED
@@ -1,123 +1,166 @@
1
  <?php
2
 
3
  $team = array(
4
- 'fred'=>array(
5
- 'name'=>'Frédéric Demarle',
6
- 'title'=>'Lead Polylang Developer',
7
- 'image_url'=>'https://www.gravatar.com/avatar/132157ff7a533c8e9a272795a1b5c2b9',
8
- 'url'=>'https://profiles.wordpress.org/chouby'),
9
- 'matt'=>array(
10
- 'name'=>'Matt Smith',
11
- 'title'=>'Lead Developer',
12
- 'image_url'=>'https://www.gravatar.com/avatar/d79b46c94a52b4679c308986ef05eac2',
13
- 'url'=>'https://profiles.wordpress.org/smithworx'),
14
- 'edward'=>array(
15
- 'name'=>'Edward Richards',
16
- 'title'=>'Lead Developer',
17
- 'image_url'=>'https://www.gravatar.com/avatar/a0ab415173b16d2ac476077d587bea96',
18
- 'url'=>'https://profiles.wordpress.org/erichie'),
19
- 'robert'=>array(
20
- 'name'=>'Robert Hanna',
21
- 'title'=>'Software Engineer',
22
- 'image_url'=>'https://www.gravatar.com/avatar/0583e77b41cefd00203ec0737cd38891',
23
- 'url'=>'https://profiles.wordpress.org/robertdhanna/'),
 
 
 
 
24
  );
25
 
26
  $team_contributors = array(
27
- 'calvin'=>array(
28
- 'name'=>'Calvin Scharffs',
29
- 'title'=>'Marketing Guru',
30
- 'image_url'=>'https://www.gravatar.com/avatar/d18e8bf783f63bf893e143cf04e0034d',
31
- 'url'=>'https://profiles.wordpress.org/cscharffs'),
32
- 'joey'=>array(
33
- 'name'=>'Joseph Hovik',
34
- 'title'=>'Developer',
35
- 'image_url'=>'https://www.gravatar.com/avatar/171f66a729d063bb6ee4e0e51135a120',
36
- 'url'=>'https://profiles.wordpress.org/jbhovik'),
37
- 'seth'=>array(
38
- 'name'=>'Seth White',
39
- 'title'=>'Developer',
40
- 'image_url'=>'https://www.gravatar.com/avatar/53706ce5472909827db3e582bb4bccf2',
41
- 'url'=>'https://profiles.wordpress.org/sethwhite'),
42
- 'brian'=>array(
43
- 'name'=>'Brian Isle',
44
- 'title'=>'Quality Assurance',
45
- 'image_url'=>'https://www.gravatar.com/avatar/5f43658c382412d8f120cb5595d9bf03',
46
- 'url'=>'https://profiles.wordpress.org/bisle'),
47
- 'brad'=>array(
48
- 'name'=>'Brad Ross',
49
- 'title'=>'Product Management',
50
- 'image_url'=>'https://www.gravatar.com/avatar/477601d2c0c8c8dd31c021e3bae3841c',
51
- 'url'=>'https://profiles.wordpress.org/bradross12/'),
52
- 'clark'=>array(
53
- 'name'=>'Clark Fuller',
54
- 'title'=>'Support',
55
- 'image_url'=>'https://www.gravatar.com/avatar/622c9cece3cd4ff8245e93892e1ea1cc',
56
- 'url'=>'https://profiles.wordpress.org/clarticus'),
57
- 'nathan'=>array(
58
- 'name'=>'Nathan Overlin',
59
- 'title'=>'Support',
60
- 'image_url'=>'https://www.gravatar.com/avatar/602038ac19d5295415269aedc8d6ebf4',
61
- 'url'=>'https://profiles.wordpress.org/noverlin'),
62
- 'laura'=>array(
63
- 'name'=>'Laura White',
64
- 'title'=>'Tech Writer',
65
- 'image_url'=>'https://www.gravatar.com/avatar/56c44e12c3431aca766d06c6019201ff',
66
- 'url'=>'https://profiles.wordpress.org/laurakaysc'),
 
 
 
 
 
 
 
 
67
  );
68
 
69
  $contributors = array(
70
- 'larry'=>array(
71
- 'name'=>'Larry Furr',
72
- 'title'=>'',
73
- 'image_url'=>'https://www.gravatar.com/avatar/77447d8ad56b4ba5ea8f3900b3245c41',
74
- 'url'=>'https://profiles.wordpress.org/furrever'),
 
75
  );
76
 
77
- shuffle($team);
78
- shuffle($team_contributors);
79
- shuffle($contributors);
80
 
81
  ?>
82
 
83
- <p class="about-description"><?php _e('The Lingotek plugin for WordPress is created with love.', 'lingotek-translation'); ?></p>
84
 
85
- <h4 class="wp-people-group"><?php _e('Project Leaders', 'lingotek-translation'); ?></h4>
86
 
87
  <ul class="wp-people-group">
88
  <?php
89
 
90
- foreach($team as $person_key=>$person){
91
- printf('<li class="wp-person" id="wp-person-%s">
 
92
  <a href="%s" target="_blank"><img src="%s?s=60&d=monsterid&r=G" srcset="%s?s=120&d=monsterid&r=G 2x" class="gravatar" alt="%s"></a>
93
  <a class="web" href="%s" target="_blank">%s</a>
94
  <span class="title">%s</span>
95
- </li>',$person_key,$person['url'],$person['image_url'],$person['image_url'],$person['name'],$person['url'],$person['name'],$person['title']);
 
 
 
 
 
 
 
 
 
96
  }
97
 
98
  ?>
99
  </ul>
100
 
101
- <h4 class="wp-people-group"><?php _e('Contributors', 'lingotek-translation'); ?></h4>
102
 
103
  <ul class="wp-people-group">
104
  <?php
105
 
106
- foreach($team_contributors as $person_key=>$person){
107
- printf('<li class="wp-person" id="wp-person-%s">
 
108
  <a href="%s" target="_blank"><img src="%s?s=60&d=monsterid&r=G" srcset="%s?s=120&d=monsterid&r=G 2x" class="gravatar" alt="%s"></a>
109
  <a class="web" href="%s" target="_blank">%s</a>
110
  <span class="title">%s</span>
111
- </li>',$person_key,$person['url'],$person['image_url'],$person['image_url'],$person['name'],$person['url'],$person['name'],$person['title']);
 
 
 
 
 
 
 
 
 
112
  }
113
 
114
- foreach($contributors as $person_key=>$person){
115
- printf('<li class="wp-person" id="wp-person-%s">
 
116
  <a href="%s" target="_blank"><img src="%s?s=60&d=monsterid&r=G" srcset="%s?s=120&d=monsterid&r=G 2x" class="gravatar" alt="%s"></a>
117
  <a class="web" href="%s" target="_blank">%s</a>
118
  <span class="title">%s</span>
119
- </li>',$person_key,$person['url'],$person['image_url'],$person['image_url'],$person['name'],$person['url'],$person['name'],$person['title']);
 
 
 
 
 
 
 
 
 
120
  }
121
 
122
  ?>
123
- </ul>
1
  <?php
2
 
3
  $team = array(
4
+ 'fred' => array(
5
+ 'name' => 'Frédéric Demarle',
6
+ 'title' => 'Lead Polylang Developer',
7
+ 'image_url' => 'https://www.gravatar.com/avatar/132157ff7a533c8e9a272795a1b5c2b9',
8
+ 'url' => 'https://profiles.wordpress.org/chouby',
9
+ ),
10
+ 'matt' => array(
11
+ 'name' => 'Matt Smith',
12
+ 'title' => 'Lead Developer',
13
+ 'image_url' => 'https://www.gravatar.com/avatar/d79b46c94a52b4679c308986ef05eac2',
14
+ 'url' => 'https://profiles.wordpress.org/smithworx',
15
+ ),
16
+ 'edward' => array(
17
+ 'name' => 'Edward Richards',
18
+ 'title' => 'Lead Developer',
19
+ 'image_url' => 'https://www.gravatar.com/avatar/a0ab415173b16d2ac476077d587bea96',
20
+ 'url' => 'https://profiles.wordpress.org/erichie',
21
+ ),
22
+ 'robert' => array(
23
+ 'name' => 'Robert Hanna',
24
+ 'title' => 'Software Engineer',
25
+ 'image_url' => 'https://www.gravatar.com/avatar/0583e77b41cefd00203ec0737cd38891',
26
+ 'url' => 'https://profiles.wordpress.org/robertdhanna/',
27
+ ),
28
  );
29
 
30
  $team_contributors = array(
31
+ 'calvin' => array(
32
+ 'name' => 'Calvin Scharffs',
33
+ 'title' => 'Marketing Guru',
34
+ 'image_url' => 'https://www.gravatar.com/avatar/d18e8bf783f63bf893e143cf04e0034d',
35
+ 'url' => 'https://profiles.wordpress.org/cscharffs',
36
+ ),
37
+ 'joey' => array(
38
+ 'name' => 'Joseph Hovik',
39
+ 'title' => 'Developer',
40
+ 'image_url' => 'https://www.gravatar.com/avatar/171f66a729d063bb6ee4e0e51135a120',
41
+ 'url' => 'https://profiles.wordpress.org/jbhovik',
42
+ ),
43
+ 'seth' => array(
44
+ 'name' => 'Seth White',
45
+ 'title' => 'Developer',
46
+ 'image_url' => 'https://www.gravatar.com/avatar/53706ce5472909827db3e582bb4bccf2',
47
+ 'url' => 'https://profiles.wordpress.org/sethwhite',
48
+ ),
49
+ 'brian' => array(
50
+ 'name' => 'Brian Isle',
51
+ 'title' => 'Quality Assurance',
52
+ 'image_url' => 'https://www.gravatar.com/avatar/5f43658c382412d8f120cb5595d9bf03',
53
+ 'url' => 'https://profiles.wordpress.org/bisle',
54
+ ),
55
+ 'brad' => array(
56
+ 'name' => 'Brad Ross',
57
+ 'title' => 'Product Management',
58
+ 'image_url' => 'https://www.gravatar.com/avatar/477601d2c0c8c8dd31c021e3bae3841c',
59
+ 'url' => 'https://profiles.wordpress.org/bradross12/',
60
+ ),
61
+ 'clark' => array(
62
+ 'name' => 'Clark Fuller',
63
+ 'title' => 'Support',
64
+ 'image_url' => 'https://www.gravatar.com/avatar/622c9cece3cd4ff8245e93892e1ea1cc',
65
+ 'url' => 'https://profiles.wordpress.org/clarticus',
66
+ ),
67
+ 'nathan' => array(
68
+ 'name' => 'Nathan Overlin',
69
+ 'title' => 'Support',
70
+ 'image_url' => 'https://www.gravatar.com/avatar/602038ac19d5295415269aedc8d6ebf4',
71
+ 'url' => 'https://profiles.wordpress.org/noverlin',
72
+ ),
73
+ 'laura' => array(
74
+ 'name' => 'Laura White',
75
+ 'title' => 'Tech Writer',
76
+ 'image_url' => 'https://www.gravatar.com/avatar/56c44e12c3431aca766d06c6019201ff',
77
+ 'url' => 'https://profiles.wordpress.org/laurakaysc',
78
+ ),
79
  );
80
 
81
  $contributors = array(
82
+ 'larry' => array(
83
+ 'name' => 'Larry Furr',
84
+ 'title' => '',
85
+ 'image_url' => 'https://www.gravatar.com/avatar/77447d8ad56b4ba5ea8f3900b3245c41',
86
+ 'url' => 'https://profiles.wordpress.org/furrever',
87
+ ),
88
  );
89
 
90
+ shuffle( $team );
91
+ shuffle( $team_contributors );
92
+ shuffle( $contributors );
93
 
94
  ?>
95
 
96
+ <p class="about-description"><?php _e( 'The Lingotek plugin for WordPress is created with love.', 'lingotek-translation' ); ?></p>
97
 
98
+ <h4 class="wp-people-group"><?php _e( 'Project Leaders', 'lingotek-translation' ); ?></h4>
99
 
100
  <ul class="wp-people-group">
101
  <?php
102
 
103
+ foreach ( $team as $person_key => $person ) {
104
+ printf(
105
+ '<li class="wp-person" id="wp-person-%s">
106
  <a href="%s" target="_blank"><img src="%s?s=60&d=monsterid&r=G" srcset="%s?s=120&d=monsterid&r=G 2x" class="gravatar" alt="%s"></a>
107
  <a class="web" href="%s" target="_blank">%s</a>
108
  <span class="title">%s</span>
109
+ </li>',
110
+ $person_key,
111
+ $person['url'],
112
+ $person['image_url'],
113
+ $person['image_url'],
114
+ $person['name'],
115
+ $person['url'],
116
+ $person['name'],
117
+ $person['title']
118
+ );
119
  }
120
 
121
  ?>
122
  </ul>
123
 
124
+ <h4 class="wp-people-group"><?php _e( 'Contributors', 'lingotek-translation' ); ?></h4>
125
 
126
  <ul class="wp-people-group">
127
  <?php
128
 
129
+ foreach ( $team_contributors as $person_key => $person ) {
130
+ printf(
131
+ '<li class="wp-person" id="wp-person-%s">
132
  <a href="%s" target="_blank"><img src="%s?s=60&d=monsterid&r=G" srcset="%s?s=120&d=monsterid&r=G 2x" class="gravatar" alt="%s"></a>
133
  <a class="web" href="%s" target="_blank">%s</a>
134
  <span class="title">%s</span>
135
+ </li>',
136
+ $person_key,
137
+ $person['url'],
138
+ $person['image_url'],
139
+ $person['image_url'],
140
+ $person['name'],
141
+ $person['url'],
142
+ $person['name'],
143
+ $person['title']
144
+ );
145
  }
146
 
147
+ foreach ( $contributors as $person_key => $person ) {
148
+ printf(
149
+ '<li class="wp-person" id="wp-person-%s">
150
  <a href="%s" target="_blank"><img src="%s?s=60&d=monsterid&r=G" srcset="%s?s=120&d=monsterid&r=G 2x" class="gravatar" alt="%s"></a>
151
  <a class="web" href="%s" target="_blank">%s</a>
152
  <span class="title">%s</span>
153
+ </li>',
154
+ $person_key,
155
+ $person['url'],
156
+ $person['image_url'],
157
+ $person['image_url'],
158
+ $person['name'],
159
+ $person['url'],
160
+ $person['name'],
161
+ $person['title']
162
+ );
163
  }
164
 
165
  ?>
166
+ </ul>
admin/tutorial/faq.php CHANGED
@@ -7,59 +7,59 @@
7
  }
8
  </style>
9
 
10
- <p class="about-description"><?php _e('Questions and answers...', 'lingotek-translation'); ?></p>
11
 
12
- <b><?php _e('How does this really work?', 'lingotek-translation') ?></b>
13
- <p><?php _e('<i>Polylang</i> puts in the framework to make WordPress multilingual and <i>Lingotek</i> leverages that framework to provide localization through machine translation and professional translation services.', 'lingotek-translation') ?></p>
14
 
15
- <b><?php _e('What does the Lingotek plugin do?', 'lingotek-translation') ?></b>
16
- <p><?php _e('<i>Lingotek</i> has teamed up with <i>Polylang</i> to offer a simple way to make your WordPress site truly multilingual. Manage all your multilingual content in the same site. No need to have a different site for each language!', 'lingotek-translation') ?></p>
17
 
18
- <b><?php _e('How can I add a language?', 'lingotek-translation') ?></b>
19
- <p><?php _e('On the <i>translation dashboard</i>, click on the <i>Translate my site into...</i> textbox and choose from the list or start typing to quickly find a language.', 'lingotek-translation') ?></p>
20
 
21
- <b><?php _e('How can I remove a language?', 'lingotek-translation') ?></b>
22
  <p>
23
- <?php _e('On the <i>translation dashboard</i>, click on the blue check mark for the language you would like to remove.', 'lingotek-translation') ?>
24
- <i><?php _e('Note: If you have translated content in a language you will not be able to remove that language until that content has been deleted.', 'lingotek-translation') ?></i>
25
  </p>
26
 
27
- <b><?php _e("Why can't I upload my existing content to Lingotek?", 'lingotek-translation') ?></b>
28
- <p><?php printf(__("You must assign a language to content that existed before you installed the <i>Polylang</i> and <i>Lingotek</i> plugins. You can do this manually or use the <a href='%s'><i>Lingotek Language Utility</i></a> to set all content that doesn't have an assigned language to the default language. This will allow you to upload your existing content to Lingotek.", 'lingotek-translation'), 'admin.php?page=lingotek-translation_settings&sm=utilities'); ?></p>
29
 
30
- <b><?php _e("Can I use my own translation agency with Lingotek?", 'lingotek-translation') ?></b>
31
- <p><?php _e( "Use your own translation agency or tap into Lingotek's network of more than 5,000+ in-country translators. Content transfer is fully automated between WordPress and Lingotek. You'll have full visibility into the translation process every step of the way. And once the translations are completed, they'll automatically download and publish to your website according to the preferences you've set." , 'lingotek-translation'); ?></p>
32
 
33
- <b><?php _e('How can I check the overall translation progress of my site?', 'lingotek-translation') ?></b>
34
- <p><?php _e('On the <i>translation dashboard</i>, the bars under <i>Completed Percentage</i> show the translation progress of content for each language. You can filter by content type or show progress for all content.', 'lingotek-translation') ?></p>
35
  <ul>
36
  <li>
37
- <b><?php _e('Why are there two different shades of blue in the progress bar?', 'lingotek-translation') ?></b>
38
- <p><?php _e('The <i>translation dashboard</i> not only shows how much of your content is translated, but also indicates the language that your source content was authored in.', 'lingotek-translation') ?></p>
39
  </li>
40
  <ul style="list-style-type:disc; padding-left:30px">
41
- <li><?php _e('<i>Dark Blue:</i> Indicates that this is a source language that the content was authored in.', 'lingotek-translation') ?></li>
42
- <li><?php _e('<i>Light Blue:</i> Indicates that this is a target language that the content was translated into.', 'lingotek-translation') ?></li>
43
  </ul>
44
  </ul>
45
 
46
- <b><?php _e('What happens when I <i>Disassociate Translations</i>?', 'lingotek-translation') ?></b>
47
- <p><?php _e('When content is disassociated, the connection between WordPress and <i>Lingotek</i> is safely removed so that translations can be solely managed inside of WordPress.', 'lingotek-translation') ?></p>
48
 
49
- <b><?php _e("How do I translate strings within widgets or general WordPress settings (e.g., Site Title, Tagline)?", 'lingotek-translation') ?></b>
50
- <p><?php printf(__( "Groups of strings can be sent for translation and managed using the <a href='%s'>String Groups</a> page. Individual strings may be viewed on the <a href='%s'>Strings</a> page." , 'lingotek-translation'),'admin.php?page=lingotek-translation_manage&sm=string-groups','admin.php?page=lingotek-translation_manage&sm=strings'); ?></p>
51
 
52
 
53
  <div class="changelog feature-section two-col">
54
  <div>
55
  <img class="workbench-image" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/workbench-full.png'; ?>">
56
- <h3><?php _e( 'Lingotek Workbench', 'lingotek-translation'); ?></h3>
57
- <p><?php _e( 'Lingotek Translation is the only WordPress plugin to integrate a Translation Management System directly into WordPress, thus allowing the WordPress community to use professional-grade translation technologies (e.g. machine translation, translation memory, CAT tool) without ever having to leave the comfort of the WordPress environment.', 'lingotek-translation'); ?></p>
58
  </div>
59
  <div class="last-feature">
60
  <a href="admin.php?page=lingotek-translation"><img src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/dashboard.png'; ?>"></a>
61
- <h3><?php _e( 'Translation Dashboard', 'lingotek-translation'); ?></h3>
62
- <p><?php _e( "The <i>translation dashboard</i> allows you to view your site languages, add and remove new languages, check the overall translation progress of your site, see site analytics, and connect with Lingotek support.", 'lingotek-translation'); ?></p>
63
  </div>
64
  </div>
65
 
7
  }
8
  </style>
9
 
10
+ <p class="about-description"><?php _e( 'Questions and answers...', 'lingotek-translation' ); ?></p>
11
 
12
+ <b><?php _e( 'How does this really work?', 'lingotek-translation' ); ?></b>
13
+ <p><?php _e( '<i>Polylang</i> puts in the framework to make WordPress multilingual and <i>Lingotek</i> leverages that framework to provide localization through machine translation and professional translation services.', 'lingotek-translation' ); ?></p>
14
 
15
+ <b><?php _e( 'What does the Lingotek plugin do?', 'lingotek-translation' ); ?></b>
16
+ <p><?php _e( '<i>Lingotek</i> has teamed up with <i>Polylang</i> to offer a simple way to make your WordPress site truly multilingual. Manage all your multilingual content in the same site. No need to have a different site for each language!', 'lingotek-translation' ); ?></p>
17
 
18
+ <b><?php _e( 'How can I add a language?', 'lingotek-translation' ); ?></b>
19
+ <p><?php _e( 'On the <i>translation dashboard</i>, click on the <i>Translate my site into...</i> textbox and choose from the list or start typing to quickly find a language.', 'lingotek-translation' ); ?></p>
20
 
21
+ <b><?php _e( 'How can I remove a language?', 'lingotek-translation' ); ?></b>
22
  <p>
23
+ <?php _e( 'On the <i>translation dashboard</i>, click on the blue check mark for the language you would like to remove.', 'lingotek-translation' ); ?>
24
+ <i><?php _e( 'Note: If you have translated content in a language you will not be able to remove that language until that content has been deleted.', 'lingotek-translation' ); ?></i>
25
  </p>
26
 
27
+ <b><?php _e( "Why can't I upload my existing content to Lingotek?", 'lingotek-translation' ); ?></b>
28
+ <p><?php printf( __( "You must assign a language to content that existed before you installed the <i>Polylang</i> and <i>Lingotek</i> plugins. You can do this manually or use the <a href='%s'><i>Lingotek Language Utility</i></a> to set all content that doesn't have an assigned language to the default language. This will allow you to upload your existing content to Lingotek.", 'lingotek-translation' ), 'admin.php?page=lingotek-translation_settings&sm=utilities' ); ?></p>
29
 
30
+ <b><?php _e( 'Can I use my own translation agency with Lingotek?', 'lingotek-translation' ); ?></b>
31
+ <p><?php _e( "Use your own translation agency or tap into Lingotek's network of more than 5,000+ in-country translators. Content transfer is fully automated between WordPress and Lingotek. You'll have full visibility into the translation process every step of the way. And once the translations are completed, they'll automatically download and publish to your website according to the preferences you've set.", 'lingotek-translation' ); ?></p>
32
 
33
+ <b><?php _e( 'How can I check the overall translation progress of my site?', 'lingotek-translation' ); ?></b>
34
+ <p><?php _e( 'On the <i>translation dashboard</i>, the bars under <i>Completed Percentage</i> show the translation progress of content for each language. You can filter by content type or show progress for all content.', 'lingotek-translation' ); ?></p>
35
  <ul>
36
  <li>
37
+ <b><?php _e( 'Why are there two different shades of blue in the progress bar?', 'lingotek-translation' ); ?></b>
38
+ <p><?php _e( 'The <i>translation dashboard</i> not only shows how much of your content is translated, but also indicates the language that your source content was authored in.', 'lingotek-translation' ); ?></p>
39
  </li>
40
  <ul style="list-style-type:disc; padding-left:30px">
41
+ <li><?php _e( '<i>Dark Blue:</i> Indicates that this is a source language that the content was authored in.', 'lingotek-translation' ); ?></li>
42
+ <li><?php _e( '<i>Light Blue:</i> Indicates that this is a target language that the content was translated into.', 'lingotek-translation' ); ?></li>
43
  </ul>
44
  </ul>
45
 
46
+ <b><?php _e( 'What happens when I <i>Disassociate Translations</i>?', 'lingotek-translation' ); ?></b>
47
+ <p><?php _e( 'When content is disassociated, the connection between WordPress and <i>Lingotek</i> is safely removed so that translations can be solely managed inside of WordPress.', 'lingotek-translation' ); ?></p>
48
 
49
+ <b><?php _e( 'How do I translate strings within widgets or general WordPress settings (e.g., Site Title, Tagline)?', 'lingotek-translation' ); ?></b>
50
+ <p><?php printf( __( "Groups of strings can be sent for translation and managed using the <a href='%1\$s'>String Groups</a> page. Individual strings may be viewed on the <a href='%2\$s'>Strings</a> page.", 'lingotek-translation' ), 'admin.php?page=lingotek-translation_manage&sm=string-groups', 'admin.php?page=lingotek-translation_manage&sm=strings' ); ?></p>
51
 
52
 
53
  <div class="changelog feature-section two-col">
54
  <div>
55
  <img class="workbench-image" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/workbench-full.png'; ?>">
56
+ <h3><?php _e( 'Lingotek Workbench', 'lingotek-translation' ); ?></h3>
57
+ <p><?php _e( 'Lingotek Translation is the only WordPress plugin to integrate a Translation Management System directly into WordPress, thus allowing the WordPress community to use professional-grade translation technologies (e.g. machine translation, translation memory, CAT tool) without ever having to leave the comfort of the WordPress environment.', 'lingotek-translation' ); ?></p>
58
  </div>
59
  <div class="last-feature">
60
  <a href="admin.php?page=lingotek-translation"><img src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/dashboard.png'; ?>"></a>
61
+ <h3><?php _e( 'Translation Dashboard', 'lingotek-translation' ); ?></h3>
62
+ <p><?php _e( 'The <i>translation dashboard</i> allows you to view your site languages, add and remove new languages, check the overall translation progress of your site, see site analytics, and connect with Lingotek support.', 'lingotek-translation' ); ?></p>
63
  </div>
64
  </div>
65
 
admin/tutorial/features.php CHANGED
@@ -8,13 +8,13 @@
8
  <div class="col">
9
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/automatic-translation.gif'; ?>">
10
  <h3><?php _e( 'Automatically translate content', 'lingotek-translation' ); ?></h3>
11
- <p><?php _e( "Machine translation is an excellent option if you're on a tight budget, looking for near-instant results, and are okay with less-than-perfect quality. The plugin allows you to quickly and automatically translate your site (the cost is covered by Lingotek for up to 100,000 characters).", 'lingotek-translation'); ?></p>
12
  </div>
13
  <div class="col">
14
  <img src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/professional-translation.png'; ?>">
15
- <h3><?php _e( 'Request professional translation', 'lingotek-translation'); ?></h3>
16
- <p><?php _e( "Use your own translation agency or tap into Lingotek's network of more than 5,000+ in-country translators. Content transfer is fully automated between WordPress and Lingotek. You'll have full visibility into the translation process every step of the way. And once the translations are completed, they'll automatically download and publish to your website according to the preferences you've set.", 'lingotek-translation'); ?></p>
17
- <a href="<?php echo admin_url( 'admin.php?page=lingotek-translation_tutorial&sm=content&tutorial=ltk-prof#ltk-prof-trans-header' ) ?>" class="button button-primary"><?php _e('Learn More', 'lingotek-translation'); ?></a>
18
  </div>
19
  </div>
20
 
@@ -23,17 +23,17 @@
23
  <div class="col">
24
  <img src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/polylang-compatible.png'; ?>">
25
  <h3><?php _e( 'Fully compatible with Polylang', 'lingotek-translation' ); ?></h3>
26
- <p><?php printf( __( 'Polylang and Lingotek work together seamlessly. Continue to use Polylang for content that you want to translate inside WordPress, while sending other content to be translated by Lingotek. The <b style="color: %s">orange</b> icons indicate Lingotek statuses/actions while the <b style="color: %s">blue</b> icons continue to represent Polylang actions.', 'lingotek-translation' ), 'darkorange', '#0473a8' ); ?></p>
27
  </div>
28
  <div class="col">
29
  <a href="admin.php?page=lingotek-translation_manage&amp;sm=profiles"><img src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/translation-profiles.png'; ?>"></a>
30
- <h3><?php _e( 'Use translation profiles', 'lingotek-translation'); ?></h3>
31
- <p><?php _e( 'One of the most time-consuming activities of any multilingual web-site project is managing the ongoing flow of changes and additions to site content and configurations. Translation profiles were created to allow you to create and save and re-use your translation settings.', 'lingotek-translation'); ?></p>
32
  </div>
33
  <div class="col">
34
  <a href="admin.php?page=lingotek-translation_manage&amp;sm=content"><img src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/content-types.png'; ?>"></a>
35
- <h3><?php _e( 'Content type profiles', 'lingotek-translation'); ?></h3>
36
- <p><?php _e( 'Content type profiles. Manually choosing which content to upload and download is rarely what a content administrator wants to do, and automating the upload of every change is not workable because there are various types of content. Each type of translatable content can be assigned to a customizable profile. For example, by default, we like to have Posts use an <i>Automatic</i> profile so that content will automatically be uploaded for translation and the resulting translations automatically be downloaded back into WordPress.', 'lingotek-translation'); ?></p>
37
  </div>
38
 
39
  </div>
@@ -42,18 +42,18 @@
42
  <div class="feature-section three-col">
43
  <div class="col">
44
  <a href="admin.php?page=lingotek-translation_manage&amp;sm=profiles"><img src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/translation-services.png'; ?>"></a>
45
- <h3><?php _e( 'Need Extra Services?', 'lingotek-translation'); ?></h3>
46
- <p><?php _e( 'Start the process of getting extra services.', 'lingotek-translation'); ?></p>
47
  <ul style="list-style-type: circle;">
48
- <li><?php _e('Do you need someone to run your localization project?', 'lingotek-translation'); ?></li>
49
- <li><?php _e('Do you need customized workflows?', 'lingotek-translation'); ?></li>
50
- <li><?php _e('Do you you have existing Translation Memories you would like to use?', 'lingotek-translation'); ?></li>
51
- <li><?php _e('Do you need help creating glossaries and terminologies?', 'lingotek-translation'); ?></li>
52
  </ul>
53
- <a href="http://www.lingotek.com/wordpress/extra_services" class="button button-primary" target="_blank"><?php _e('Request Services', 'lingotek-translation'); ?></a>
54
  </div>
55
  <div class="col">
56
  </div>
57
  <div class="col">
58
  </div>
59
- </div>
8
  <div class="col">
9
  <img class="lingotek-bordered" src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/automatic-translation.gif'; ?>">
10
  <h3><?php _e( 'Automatically translate content', 'lingotek-translation' ); ?></h3>
11
+ <p><?php _e( "Machine translation is an excellent option if you're on a tight budget, looking for near-instant results, and are okay with less-than-perfect quality. The plugin allows you to quickly and automatically translate your site (the cost is covered by Lingotek for up to 100,000 characters).", 'lingotek-translation' ); ?></p>
12
  </div>
13
  <div class="col">
14
  <img src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/professional-translation.png'; ?>">
15
+ <h3><?php _e( 'Request professional translation', 'lingotek-translation' ); ?></h3>
16
+ <p><?php _e( "Use your own translation agency or tap into Lingotek's network of more than 5,000+ in-country translators. Content transfer is fully automated between WordPress and Lingotek. You'll have full visibility into the translation process every step of the way. And once the translations are completed, they'll automatically download and publish to your website according to the preferences you've set.", 'lingotek-translation' ); ?></p>
17
+ <a href="<?php echo admin_url( 'admin.php?page=lingotek-translation_tutorial&sm=content&tutorial=ltk-prof#ltk-prof-trans-header' ); ?>" class="button button-primary"><?php _e( 'Learn More', 'lingotek-translation' ); ?></a>
18
  </div>
19
  </div>
20
 
23
  <div class="col">
24
  <img src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/polylang-compatible.png'; ?>">
25
  <h3><?php _e( 'Fully compatible with Polylang', 'lingotek-translation' ); ?></h3>
26
+ <p><?php printf( __( 'Polylang and Lingotek work together seamlessly. Continue to use Polylang for content that you want to translate inside WordPress, while sending other content to be translated by Lingotek. The <b style="color: %1$s">orange</b> icons indicate Lingotek statuses/actions while the <b style="color: %2$s">blue</b> icons continue to represent Polylang actions.', 'lingotek-translation' ), 'darkorange', '#0473a8' ); ?></p>
27
  </div>
28
  <div class="col">
29
  <a href="admin.php?page=lingotek-translation_manage&amp;sm=profiles"><img src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/translation-profiles.png'; ?>"></a>
30
+ <h3><?php _e( 'Use translation profiles', 'lingotek-translation' ); ?></h3>
31
+ <p><?php _e( 'One of the most time-consuming activities of any multilingual web-site project is managing the ongoing flow of changes and additions to site content and configurations. Translation profiles were created to allow you to create and save and re-use your translation settings.', 'lingotek-translation' ); ?></p>
32
  </div>
33
  <div class="col">
34
  <a href="admin.php?page=lingotek-translation_manage&amp;sm=content"><img src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/content-types.png'; ?>"></a>
35
+ <h3><?php _e( 'Content type profiles', 'lingotek-translation' ); ?></h3>
36
+ <p><?php _e( 'Content type profiles. Manually choosing which content to upload and download is rarely what a content administrator wants to do, and automating the upload of every change is not workable because there are various types of content. Each type of translatable content can be assigned to a customizable profile. For example, by default, we like to have Posts use an <i>Automatic</i> profile so that content will automatically be uploaded for translation and the resulting translations automatically be downloaded back into WordPress.', 'lingotek-translation' ); ?></p>
37
  </div>
38
 
39
  </div>
42
  <div class="feature-section three-col">
43
  <div class="col">
44
  <a href="admin.php?page=lingotek-translation_manage&amp;sm=profiles"><img src="<?php echo LINGOTEK_URL . '/admin/tutorial/img/translation-services.png'; ?>"></a>
45
+ <h3><?php _e( 'Need Extra Services?', 'lingotek-translation' ); ?></h3>
46
+ <p><?php _e( 'Start the process of getting extra services.', 'lingotek-translation' ); ?></p>
47
  <ul style="list-style-type: circle;">
48
+ <li><?php _e( 'Do you need someone to run your localization project?', 'lingotek-translation' ); ?></li>
49
+ <li><?php _e( 'Do you need customized workflows?', 'lingotek-translation' ); ?></li>
50
+ <li><?php _e( 'Do you you have existing Translation Memories you would like to use?', 'lingotek-translation' ); ?></li>
51
+ <li><?php _e( 'Do you need help creating glossaries and terminologies?', 'lingotek-translation' ); ?></li>
52
  </ul>
53
+ <a href="http://www.lingotek.com/wordpress/extra_services" class="button button-primary" target="_blank"><?php _e( 'Request Services', 'lingotek-translation' ); ?></a>
54
  </div>
55
  <div class="col">
56
  </div>
57
  <div class="col">
58
  </div>
59
+ </div>
admin/utilities.php CHANGED
@@ -6,7 +6,8 @@
6
  * @since 0.2
7
  */
8
  class Lingotek_Utilities {
9
- public $pllm, $lgtm; // Polylang and Lingotek models
 
10
 
11
  /*
12
  * Constructor
@@ -17,10 +18,10 @@ class Lingotek_Utilities {
17
  $this->pllm = $GLOBALS['polylang']->model;
18
  $this->lgtm = $GLOBALS['wp_lingotek']->model;
19
 
20
- add_action('admin_enqueue_scripts', array(&$this, 'admin_enqueue_scripts'));
21
- add_action('wp_ajax_lingotek_progress_disassociate' , array(&$this, 'ajax_utility_disassociate'));
22
- add_action('wp_ajax_lingotek_progress_disassociate_and_delete' , array(&$this, 'ajax_utility_disassociate'));
23
- add_action('wp_ajax_lingotek_progress_cancel', array(&$this, 'ajax_utility_cancel'));
24
  }
25
 
26
  /*
@@ -31,11 +32,11 @@ class Lingotek_Utilities {
31
  * @param array $utilities array of utility names to run
32
  * @return array
33
  */
34
- public function run_utilities($utilities){
35
  $results = array();
36
- if(!empty($utilities) && is_array($utilities)){
37
- foreach($utilities as $utility_name) {
38
- $results[] = $this->run_utility($utility_name);
39
  }
40
  }
41
  return $results;
@@ -49,11 +50,11 @@ class Lingotek_Utilities {
49
  * @param string $utilty_name
50
  * @return boolean $result
51
  */
52
- public function run_utility($utility_name) {
53
  $result = 0;
54
- switch ($utility_name) {
55
- case "set_default_language":
56
- case "utility_set_default_language":
57
  $result = $this->utility_set_default_language();
58
  break;
59
  default:
@@ -70,13 +71,15 @@ class Lingotek_Utilities {
70
  * @since 0.2
71
  */
72
  public function utility_set_default_language() {
73
- if ($nolang = $this->pllm->get_objects_with_no_lang()) {
74
- if (!empty($nolang['posts']))
75
- $this->pllm->set_language_in_mass('post', $nolang['posts'], $this->pllm->options['default_lang']);
76
- if (!empty($nolang['terms']))
77
- $this->pllm->set_language_in_mass('term', $nolang['terms'], $this->pllm->options['default_lang']);
 
 
78
  }
79
- add_settings_error('lingotek_utilities', 'utilities', __('The language update utility ran successfully.', 'lingotek-translation'), 'updated');
80
  return 0;
81
  }
82
 
@@ -87,15 +90,16 @@ class Lingotek_Utilities {
87
  *
88
  * @return array
89
  */
90
- static public function get_all_document_ids() {
91
- $terms = get_terms(array('post_translations', 'term_translations'));
92
- foreach ($terms as $term) {
93
- $desc_arr = unserialize($term->description);
94
- if (!empty($desc_arr['lingotek']))
95
  $ids[] = $term->slug;
 
96
  }
97
 
98
- return empty($ids) ? array() : $ids;
99
  }
100
 
101
  /*
@@ -104,31 +108,41 @@ class Lingotek_Utilities {
104
  * @since 0.2
105
  */
106
  public function admin_enqueue_scripts() {
107
- if (!empty($_POST['utility_disassociate'])) {
108
  $ids = self::get_all_document_ids();
109
- if (!empty($ids)) {
110
- wp_localize_script('lingotek_progress', 'lingotek_data', array(
111
- 'action' => 'disassociate' . ('on' == $_POST['utility_delete_documents'] ? '_and_delete' : ''),
112
- 'taxonomy' => '',
113
- 'sendback' => wp_get_referer(),
114
- 'ids' => $ids, // Lingotek document ids
115
- 'warning' => '',
116
- 'nonce' => wp_create_nonce('lingotek_progress')
117
- ));
 
 
 
 
 
118
  }
119
- } else if (!empty($_POST['utility_cancel'])){
120
  $ids = self::get_all_document_ids();
121
- if(!empty($ids)){
122
- wp_localize_script('lingotek_progress', 'lingotek_data', array(
123
- 'action' => 'cancel' . ($_POST['utility_cancel_documents']),
124
- 'taxonomy' => '',
125
- 'sendback' => wp_get_referer(),
126
- 'ids' => $ids, // Lingotek document ids
127
- 'warning' => '',
128
- 'nonce' => wp_create_nonce('lingotek_progress')
129
- ));
 
 
 
 
 
130
  }
131
- }
132
  }
133
 
134
  /*
@@ -137,16 +151,17 @@ class Lingotek_Utilities {
137
  * @since 0.2
138
  */
139
  public function ajax_utility_disassociate() {
140
- check_ajax_referer('lingotek_progress', '_lingotek_nonce');
141
- if ($group = $this->lgtm->get_group_by_id($_POST['id']))
142
- $group->delete('lingotek_progress_disassociate_and_delete' == $_POST['action']);
 
143
  die();
144
  }
145
 
146
  public function ajax_utility_cancel() {
147
- check_ajax_referer('lingotek_progress', '_lingotek_nonce');
148
- if ($group = $this->lgtm->get_group_by_id($_POST['id'])){
149
- $group->cancel('lingotek_progress_cancel' == $_POST['action']);
150
  }
151
  die();
152
  }
6
  * @since 0.2
7
  */
8
  class Lingotek_Utilities {
9
+ // Polylang and Lingotek models.
10
+ public $pllm, $lgtm;
11
 
12
  /*
13
  * Constructor
18
  $this->pllm = $GLOBALS['polylang']->model;
19
  $this->lgtm = $GLOBALS['wp_lingotek']->model;
20
 
21
+ add_action( 'admin_enqueue_scripts', array( &$this, 'admin_enqueue_scripts' ) );
22
+ add_action( 'wp_ajax_lingotek_progress_disassociate', array( &$this, 'ajax_utility_disassociate' ) );
23
+ add_action( 'wp_ajax_lingotek_progress_disassociate_and_delete', array( &$this, 'ajax_utility_disassociate' ) );
24
+ add_action( 'wp_ajax_lingotek_progress_cancel', array( &$this, 'ajax_utility_cancel' ) );
25
  }
26
 
27
  /*
32
  * @param array $utilities array of utility names to run
33
  * @return array
34
  */
35
+ public function run_utilities( $utilities ) {
36
  $results = array();
37
+ if ( ! empty( $utilities ) && is_array( $utilities ) ) {
38
+ foreach ( $utilities as $utility_name ) {
39
+ $results[] = $this->run_utility( $utility_name );
40
  }
41
  }
42
  return $results;
50
  * @param string $utilty_name
51
  * @return boolean $result
52
  */
53
+ public function run_utility( $utility_name ) {
54
  $result = 0;
55
+ switch ( $utility_name ) {
56
+ case 'set_default_language':
57
+ case 'utility_set_default_language':
58
  $result = $this->utility_set_default_language();
59
  break;
60
  default:
71
  * @since 0.2
72
  */
73
  public function utility_set_default_language() {
74
+ if ( $nolang = $this->pllm->get_objects_with_no_lang() ) {
75
+ if ( ! empty( $nolang['posts'] ) ) {
76
+ $this->pllm->set_language_in_mass( 'post', $nolang['posts'], $this->pllm->options['default_lang'] );
77
+ }
78
+ if ( ! empty( $nolang['terms'] ) ) {
79
+ $this->pllm->set_language_in_mass( 'term', $nolang['terms'], $this->pllm->options['default_lang'] );
80
+ }
81
  }
82
+ add_settings_error( 'lingotek_utilities', 'utilities', __( 'The language update utility ran successfully.', 'lingotek-translation' ), 'updated' );
83
  return 0;
84
  }
85
 
90
  *
91
  * @return array
92
  */
93
+ public static function get_all_document_ids() {
94
+ $terms = get_terms( array( 'post_translations', 'term_translations' ) );
95
+ foreach ( $terms as $term ) {
96
+ $desc_arr = unserialize( $term->description );
97
+ if ( ! empty( $desc_arr['lingotek'] ) ) {
98
  $ids[] = $term->slug;
99
+ }
100
  }
101
 
102
+ return empty( $ids ) ? array() : $ids;
103
  }
104
 
105
  /*
108
  * @since 0.2
109
  */
110
  public function admin_enqueue_scripts() {
111
+ if ( ! empty( $_POST['utility_disassociate'] ) ) {
112
  $ids = self::get_all_document_ids();
113
+ if ( ! empty( $ids ) ) {
114
+ wp_localize_script(
115
+ 'lingotek_progress',
116
+ 'lingotek_data',
117
+ array(
118
+ 'action' => 'disassociate' . ( 'on' == $_POST['utility_delete_documents'] ? '_and_delete' : '' ),
119
+ 'taxonomy' => '',
120
+ 'sendback' => wp_get_referer(),
121
+ // Lingotek document ids.
122
+ 'ids' => $ids,
123
+ 'warning' => '',
124
+ 'nonce' => wp_create_nonce( 'lingotek_progress' ),
125
+ )
126
+ );
127
  }
128
+ } elseif ( ! empty( $_POST['utility_cancel'] ) ) {
129
  $ids = self::get_all_document_ids();
130
+ if ( ! empty( $ids ) ) {
131
+ wp_localize_script(
132
+ 'lingotek_progress',
133
+ 'lingotek_data',
134
+ array(
135
+ 'action' => 'cancel' . ( $_POST['utility_cancel_documents'] ),
136
+ 'taxonomy' => '',
137
+ 'sendback' => wp_get_referer(),
138
+ // Lingotek document ids.
139
+ 'ids' => $ids,
140
+ 'warning' => '',
141
+ 'nonce' => wp_create_nonce( 'lingotek_progress' ),
142
+ )
143
+ );
144
  }
145
+ }//end if
146
  }
147
 
148
  /*
151
  * @since 0.2
152
  */
153
  public function ajax_utility_disassociate() {
154
+ check_ajax_referer( 'lingotek_progress', '_lingotek_nonce' );
155
+ if ( $group = $this->lgtm->get_group_by_id( $_POST['id'] ) ) {
156
+ $group->delete( 'lingotek_progress_disassociate_and_delete' == $_POST['action'] );
157
+ }
158
  die();
159
  }
160
 
161
  public function ajax_utility_cancel() {
162
+ check_ajax_referer( 'lingotek_progress', '_lingotek_nonce' );
163
+ if ( $group = $this->lgtm->get_group_by_id( $_POST['id'] ) ) {
164
+ $group->cancel( 'lingotek_progress_cancel' == $_POST['action'] );
165
  }
166
  die();
167
  }
admin/view-dashboard.php CHANGED
@@ -1,7 +1,7 @@
1
  <div class="wrap">
2
- <h2><?php _e('Dashboard', 'lingotek-translation'); ?></h2>
3
  <script>
4
- var cms_data = <?php echo json_encode($cms_data); ?>
5
  </script>
6
  <link rel="stylesheet" href="https://gmc.lingotek.com/v2/styles/ltk.css">
7
  <script src="https://gmc.lingotek.com/v2/ltk.min.js"></script>
1
  <div class="wrap">
2
+ <h2><?php _e( 'Dashboard', 'lingotek-translation' ); ?></h2>
3
  <script>
4
+ var cms_data = <?php echo json_encode( $cms_data ); ?>
5
  </script>
6
  <link rel="stylesheet" href="https://gmc.lingotek.com/v2/styles/ltk.css">
7
  <script src="https://gmc.lingotek.com/v2/ltk.min.js"></script>
admin/view-manage.php CHANGED
@@ -1,43 +1,48 @@
1
  <div class="wrap">
2
- <h2><?php _e('Manage', 'lingotek-translation'); ?></h2>
3
-
4
- <?php
5
-
6
- $menu_items = array(
7
- 'content' => __('Content Type Configuration', 'lingotek-translation'),
8
- 'profiles' => __('Translation Profiles', 'lingotek-translation'),
9
- 'custom-fields' => __('Custom Fields', 'lingotek-translation'),
10
- 'string-groups' => __('String Groups', 'lingotek-translation'),
11
- 'strings' => __('Strings', 'lingotek-translation'),
12
- );
13
-
14
- ?>
15
-
16
- <h3 class="nav-tab-wrapper">
17
- <?php
18
- $menu_item_index = 0;
19
- foreach ($menu_items as $menu_item_key => $menu_item_label) {
20
- $use_as_default = ($menu_item_index === 0 && !isset($_GET['sm'])) ? TRUE : FALSE;
21
- ?>
22
-
23
- <a class="nav-tab <?php if ($use_as_default || (isset($_GET['sm']) && $_GET['sm'] == $menu_item_key)): ?> nav-tab-active<?php endif; ?>"
24
- href="admin.php?page=<?php echo $_GET['page']; ?>&amp;sm=<?php echo $menu_item_key; ?>"><?php echo $menu_item_label; ?></a>
25
- <?php
26
- $menu_item_index++;
27
- }
28
- ?>
29
- </h3>
30
-
31
- <?php
32
- settings_errors();
33
- $submenu = isset($_GET['sm']) ? sanitize_text_field($_GET['sm']) : current(array_keys($menu_items));
34
- $dir = dirname(__FILE__) . '/manage/';
35
- $filename = $dir . 'view-' . $submenu . ".php";
36
- if (file_exists($filename))
37
- include $filename;
38
- else
39
- echo "TO-DO: create <i>" . 'manage/view-' . $submenu . ".php</i>";
40
- ?>
 
 
 
 
 
41
 
42
  </div>
43
 
1
  <div class="wrap">
2
+ <h2><?php _e( 'Manage', 'lingotek-translation' ); ?></h2>
3
+
4
+ <?php
5
+
6
+ $menu_items = array(
7
+ 'content' => __( 'Content Type Configuration', 'lingotek-translation' ),
8
+ 'profiles' => __( 'Translation Profiles', 'lingotek-translation' ),
9
+ 'custom-fields' => __( 'Custom Fields', 'lingotek-translation' ),
10
+ 'string-groups' => __( 'String Groups', 'lingotek-translation' ),
11
+ 'strings' => __( 'Strings', 'lingotek-translation' ),
12
+ );
13
+
14
+ ?>
15
+
16
+ <h3 class="nav-tab-wrapper">
17
+ <?php
18
+ $menu_item_index = 0;
19
+ foreach ( $menu_items as $menu_item_key => $menu_item_label ) {
20
+ $use_as_default = ( $menu_item_index === 0 && ! isset( $_GET['sm'] ) ) ? true : false;
21
+ ?>
22
+
23
+ <a class="nav-tab
24
+ <?php
25
+ if ( $use_as_default || ( isset( $_GET['sm'] ) && $_GET['sm'] == $menu_item_key ) ) :
26
+ ?>
27
+ nav-tab-active<?php endif; ?>"
28
+ href="admin.php?page=<?php echo $_GET['page']; ?>&amp;sm=<?php echo $menu_item_key; ?>"><?php echo $menu_item_label; ?></a>
29
+ <?php
30
+ $menu_item_index++;
31
+ }
32
+ ?>
33
+ </h3>
34
+
35
+ <?php
36
+ settings_errors();
37
+ $submenu = isset( $_GET['sm'] ) ? sanitize_text_field( $_GET['sm'] ) : current( array_keys( $menu_items ) );
38
+ $dir = dirname( __FILE__ ) . '/manage/';
39
+ $filename = $dir . 'view-' . $submenu . '.php';
40
+ if ( file_exists( $filename ) ) {
41
+ require $filename;
42
+ } else {
43
+ echo 'TO-DO: create <i>' . 'manage/view-' . $submenu . '.php</i>';
44
+ }
45
+ ?>
46
 
47
  </div>
48
 
admin/view-network.php CHANGED
@@ -1,105 +1,103 @@
1
  <?php
2
- $sites = wp_get_sites();
3
  $site_data = array();
4
 
5
- foreach ($sites as $site)
6
- {
7
- switch_to_blog($site['blog_id']);
8
- $details = get_blog_details($site['blog_id'])->blogname;
9
- $temp = array("blog_id" => $site['blog_id'], "blogname" => $details);
10
- array_push($site_data, $temp);
11
- $ltk = new Lingotek();
12
- $ltk->admin_init();
13
- restore_current_blog();
14
- }
15
-
16
- if (!empty($_POST)) {
17
- $source_site = $_POST['source'];
18
-
19
- if (isset($_POST['destination'])) {
20
- $destination_site = $_POST['destination'];
21
-
22
- foreach ($destination_site as $destination) {
23
-
24
- if (!empty($_POST['settings'])) {
25
- $selected_settings = $_POST['settings'];
 
 
 
 
 
 
26
 
27
- foreach ($selected_settings as $setting) {
28
- //Updates account options for access token and the base url to connect to Lingotek
29
- if ($setting == 'token') {
30
- $lingotek_option = 'lingotek_' . $setting;
31
 
32
- $source_options = get_blog_option($source_site, $lingotek_option);
33
- update_blog_option($destination, $lingotek_option, $source_options);
 
34
 
35
- $source_options = get_blog_option($source_site, 'lingotek_base_url');
36
- update_blog_option($destination, 'lingotek_base_url', $source_options);
37
- }
38
 
39
- //Updates the chosen option
40
- $lingotek_option = 'lingotek_' . $setting;
41
-
42
- $source_options = get_blog_option($source_site, $lingotek_option);
43
- update_blog_option($destination, $lingotek_option, $source_options);
44
- }
45
  }
46
-
47
- //Creates a new project based on the name of the selected site
48
- if (isset($_POST['new_project'])) {
49
- $options = get_blog_option($destination, 'lingotek_defaults');
50
- $client = new Lingotek_API();
51
- $title = htmlspecialchars_decode(get_blog_details($destination)->blogname, ENT_QUOTES);
52
-
53
- if ($new_id = $client->create_project($title, $community_id = get_blog_option($destination, 'lingotek_community'))) {
54
- $options['project_id'] = $new_id;
55
- // Adds correct callback URL for new project
56
- $args = array('callback_url' => add_query_arg('lingotek', 1, get_blog_details($destination)->siteurl));
57
- $response = $client->patch($client->get_api_url() . '/project/' . $new_id, $args);
58
- update_blog_option($destination, 'lingotek_defaults', $options);
59
- }
60
- }
61
-
62
- if (isset($_POST['preferences'])) {
63
- switch_to_blog($source_site);
64
- $preferences = Lingotek_Model::get_prefs();
65
- update_blog_option($destination, 'lingotek_prefs', $preferences);
66
- restore_current_blog();
67
  }
 
68
 
69
- if (isset($_POST['utility_set_default_language'])) {
70
- switch_to_blog($destination);
71
- $GLOBALS['wp_lingotek']->utilities->run_utility('utility_set_default_language');
72
- restore_current_blog();
73
- }
74
-
75
  }
76
 
77
- if (isset($_POST['utility_set_default_language'])) {
78
- add_settings_error('network', 'utilities', __('The language utility ran successfully.', 'lingotek-translation'), 'updated');
 
 
79
  }
80
- add_settings_error('network', 'destination', __('Your chosen settings have updated successfully for all selected sites.', 'lingotek-translation'), 'updated');
 
 
 
81
  }
82
- else {
83
- add_settings_error('network', 'destination', __('Please choose at least one destination site.', 'lingotek-translation'), 'error');
 
 
 
 
 
 
 
 
 
84
  }
85
-
86
- //Refreshes community resources so that the defaults are set when you visit the sites translation settings
87
- if (isset($_POST['new_project']) && isset($_POST['destination'])) {
88
- $this->set_community_resources(get_option('lingotek_community'));
89
- foreach ($destination_site as $destination) {
90
- $source_options = get_option('lingotek_community_resources');
91
- update_blog_option($destination, 'lingotek_community_resources', $source_options);
92
- }
93
- $num = count($destination_site);
94
- if ($num > 1) {
95
- add_settings_error('network', 'projects', __('Your new projects were successfully created.', 'lingotek-translation'), 'updated');
96
- }
97
- else {
98
- add_settings_error('network', 'projects', __('Your new project was successfully created.', 'lingotek-translation'), 'updated');
99
- }
100
  }
101
  }
102
- settings_errors('network');
 
103
  ?>
104
 
105
  <style>
@@ -109,59 +107,66 @@
109
  </style>
110
 
111
  <div class="wrap">
112
- <h2><?php _e('Lingotek Network Settings', 'lingotek-translation'); ?></h2>
113
- <p><?php _e('Copy Lingotek settings from the source site to multiple sites', 'lingotek-translation'); ?></p>
114
 
115
  <form id="network-settings" method="post" action="admin.php?page=lingotek-translation_network" class="validate" onsubmit="return confirm('Are you sure you want to submit this request? It will overwrite any current settings you have for the destination sites.');">
116
 
117
  <table class="form-table">
118
  <tr>
119
- <th><?php echo _e('Source Site', 'lingotek-translation'); ?></th>
120
  <td>
121
- <select name="source" id="source"><?php foreach ($site_data as $site) {
122
- echo "\n\t<option value='" . esc_attr($site['blog_id']) . "'>" . $site['blogname'] . '</option>';
123
- } ?>
 
 
 
 
124
  </select>
125
  </td>
126
  </tr>
127
  <tr>
128
- <th><?php echo _e('Destination Site', 'lingotek-translation'); ?></th>
129
  <td>
130
- <select multiple="multiple" name="destination[]" id="destination"><?php foreach ($site_data as $site) {
131
- echo "\n\t<option value='" . esc_attr($site['blog_id']) . "'>" . $site['blogname'] . '</option>';
132
- } ?>
 
 
 
133
  </select>
134
  </td>
135
  </tr>
136
  <tr>
137
- <th><?php echo _e('Settings to copy', 'lingotek-translation'); ?></th>
138
  <td>
139
- <input checked type="checkbox" id="account" name="settings[]" value="token"><label for="account"><?php echo _e('Account', 'lingotek-translation'); ?></label>
140
- <input checked type="checkbox" id="community" name="settings[]" value="community"><label for="community"><?php echo _e('Community', 'lingotek-translation'); ?></label>
141
- <input checked type="checkbox" id="defaults" name="settings[]" value="defaults"><label for="defaults"><?php echo _e('Defaults', 'lingotek-translation'); ?></label>
142
- <input checked type="checkbox" id="resources" name="settings[]" value="community_resources"><label for="resources"><?php echo _e('Resources', 'lingotek-translation'); ?></label>
143
- <input checked type="checkbox" id="profiles" name="settings[]" value="profiles"><label for="profiles"><?php echo _e('Profiles', 'lingotek-translation'); ?></label>
144
- <input checked type="checkbox" id="content_types" name="settings[]" value="content_type"><label for="content_types"><?php echo _e('Content Types', 'lingotek-translation'); ?></label>
145
- <input checked type="checkbox" id="preferences" name="preferences" value="preferences"><label for="preferences"><?php echo _e('Preferences', 'lingotek-translation'); ?></label>
146
  </td>
147
  </tr>
148
  <tr>
149
- <th><?php echo _e('New Project', 'lingotek-translation'); ?></th>
150
  <td>
151
- <input checked type="checkbox" name="new_project" id="new_project" ><label for="new_project"><?php echo _e('Create a new project using the name of the selected site (Recommended for a newly created site)', 'lingotek-translation'); ?></label>
152
  </td>
153
  </tr>
154
  <tr>
155
- <th><?php echo _e('Language', 'lingotek-translation'); ?></th>
156
  <td>
157
- <input checked type="checkbox" name="utility_set_default_language" id="utility_set_default_language" ><label for="utility_set_default_language"><?php echo _e('Set <i>default language</i> as the language for all existing content that has not been assigned a language.', 'lingotek-translation'); ?></label>
158
  </td>
159
  </tr>
160
  </table>
161
 
162
  <p>
163
- <?php submit_button(__('Update Options', 'lingotek-translation'), 'primary', 'submit', false); ?>
164
  </p>
165
 
166
  </form>
167
- </div>
1
  <?php
2
+ $sites = wp_get_sites();
3
  $site_data = array();
4
 
5
+ foreach ( $sites as $site ) {
6
+ switch_to_blog( $site['blog_id'] );
7
+ $details = get_blog_details( $site['blog_id'] )->blogname;
8
+ $temp = array(
9
+ 'blog_id' => $site['blog_id'],
10
+ 'blogname' => $details,
11
+ );
12
+ array_push( $site_data, $temp );
13
+ $ltk = new Lingotek();
14
+ $ltk->admin_init();
15
+ restore_current_blog();
16
+ }
17
+
18
+ if ( ! empty( $_POST ) ) {
19
+ $source_site = $_POST['source'];
20
+
21
+ if ( isset( $_POST['destination'] ) ) {
22
+ $destination_site = $_POST['destination'];
23
+
24
+ foreach ( $destination_site as $destination ) {
25
+ if ( ! empty( $_POST['settings'] ) ) {
26
+ $selected_settings = $_POST['settings'];
27
+
28
+ foreach ( $selected_settings as $setting ) {
29
+ //Updates account options for access token and the base url to connect to Lingotek
30
+ if ( $setting == 'token' ) {
31
+ $lingotek_option = 'lingotek_' . $setting;
32
 
33
+ $source_options = get_blog_option( $source_site, $lingotek_option );
34
+ update_blog_option( $destination, $lingotek_option, $source_options );
 
 
35
 
36
+ $source_options = get_blog_option( $source_site, 'lingotek_base_url' );
37
+ update_blog_option( $destination, 'lingotek_base_url', $source_options );
38
+ }
39
 
40
+ //Updates the chosen option
41
+ $lingotek_option = 'lingotek_' . $setting;
 
42
 
43
+ $source_options = get_blog_option( $source_site, $lingotek_option );
44
+ update_blog_option( $destination, $lingotek_option, $source_options );
 
 
 
 
45
  }
46
+ }//end if
47
+
48
+ //Creates a new project based on the name of the selected site
49
+ if ( isset( $_POST['new_project'] ) ) {
50
+ $options = get_blog_option( $destination, 'lingotek_defaults', array() );
51
+ $client = new Lingotek_API();
52
+ $title = htmlspecialchars_decode( get_blog_details( $destination )->blogname, ENT_QUOTES );
53
+
54
+ if ( $new_id = $client->create_project( $title, $community_id = get_blog_option( $destination, 'lingotek_community' ) ) ) {
55
+ $options['project_id'] = $new_id;
56
+ // Adds correct callback URL for new project
57
+ $args = array( 'callback_url' => add_query_arg( 'lingotek', 1, get_blog_details( $destination )->siteurl ) );
58
+ $response = $client->patch( $client->get_api_url() . '/project/' . $new_id, $args );
59
+ update_blog_option( $destination, 'lingotek_defaults', $options );
 
 
 
 
 
 
 
60
  }
61
+ }
62
 
63
+ if ( isset( $_POST['preferences'] ) ) {
64
+ switch_to_blog( $source_site );
65
+ $preferences = Lingotek_Model::get_prefs();
66
+ update_blog_option( $destination, 'lingotek_prefs', $preferences );
67
+ restore_current_blog();
 
68
  }
69
 
70
+ if ( isset( $_POST['utility_set_default_language'] ) ) {
71
+ switch_to_blog( $destination );
72
+ $GLOBALS['wp_lingotek']->utilities->run_utility( 'utility_set_default_language' );
73
+ restore_current_blog();
74
  }
75
+ }//end foreach
76
+
77
+ if ( isset( $_POST['utility_set_default_language'] ) ) {
78
+ add_settings_error( 'network', 'utilities', __( 'The language utility ran successfully.', 'lingotek-translation' ), 'updated' );
79
  }
80
+ add_settings_error( 'network', 'destination', __( 'Your chosen settings have updated successfully for all selected sites.', 'lingotek-translation' ), 'updated' );
81
+ } else {
82
+ add_settings_error( 'network', 'destination', __( 'Please choose at least one destination site.', 'lingotek-translation' ), 'error' );
83
+ }//end if
84
+
85
+ //Refreshes community resources so that the defaults are set when you visit the sites translation settings
86
+ if ( isset( $_POST['new_project'] ) && isset( $_POST['destination'] ) ) {
87
+ $this->set_community_resources( get_option( 'lingotek_community' ) );
88
+ foreach ( $destination_site as $destination ) {
89
+ $source_options = get_option( 'lingotek_community_resources' );
90
+ update_blog_option( $destination, 'lingotek_community_resources', $source_options );
91
  }
92
+ $num = count( $destination_site );
93
+ if ( $num > 1 ) {
94
+ add_settings_error( 'network', 'projects', __( 'Your new projects were successfully created.', 'lingotek-translation' ), 'updated' );
95
+ } else {
96
+ add_settings_error( 'network', 'projects', __( 'Your new project was successfully created.', 'lingotek-translation' ), 'updated' );
 
 
 
 
 
 
 
 
 
 
97
  }
98
  }
99
+ }//end if
100
+ settings_errors( 'network' );
101
  ?>
102
 
103
  <style>
107
  </style>
108
 
109
  <div class="wrap">
110
+ <h2><?php _e( 'Lingotek Network Settings', 'lingotek-translation' ); ?></h2>
111
+ <p><?php _e( 'Copy Lingotek settings from the source site to multiple sites', 'lingotek-translation' ); ?></p>
112
 
113
  <form id="network-settings" method="post" action="admin.php?page=lingotek-translation_network" class="validate" onsubmit="return confirm('Are you sure you want to submit this request? It will overwrite any current settings you have for the destination sites.');">
114
 
115
  <table class="form-table">
116
  <tr>
117
+ <th><?php echo _e( 'Source Site', 'lingotek-translation' ); ?></th>
118
  <td>
119
+ <select name="source" id="source">
120
+ <?php
121
+ foreach ( $site_data as $site ) {
122
+ echo "\n\t<option value='" . esc_attr( $site['blog_id'] ) . "'>" . $site['blogname'] . '</option>';
123
+ }
124
+ ?>
125
+
126
  </select>
127
  </td>
128
  </tr>
129
  <tr>
130
+ <th><?php echo _e( 'Destination Site', 'lingotek-translation' ); ?></th>
131
  <td>
132
+ <select multiple="multiple" name="destination[]" id="destination">
133
+ <?php
134
+ foreach ( $site_data as $site ) {
135
+ echo "\n\t<option value='" . esc_attr( $site['blog_id'] ) . "'>" . $site['blogname'] . '</option>';
136
+ }
137
+ ?>
138
  </select>
139
  </td>
140
  </tr>
141
  <tr>
142
+ <th><?php echo _e( 'Settings to copy', 'lingotek-translation' ); ?></th>
143
  <td>
144
+ <input checked type="checkbox" id="account" name="settings[]" value="token"><label for="account"><?php echo _e( 'Account', 'lingotek-translation' ); ?></label>
145
+ <input checked type="checkbox" id="community" name="settings[]" value="community"><label for="community"><?php echo _e( 'Community', 'lingotek-translation' ); ?></label>
146
+ <input checked type="checkbox" id="defaults" name="settings[]" value="defaults"><label for="defaults"><?php echo _e( 'Defaults', 'lingotek-translation' ); ?></label>
147
+ <input checked type="checkbox" id="resources" name="settings[]" value="community_resources"><label for="resources"><?php echo _e( 'Resources', 'lingotek-translation' ); ?></label>
148
+ <input checked type="checkbox" id="profiles" name="settings[]" value="profiles"><label for="profiles"><?php echo _e( 'Profiles', 'lingotek-translation' ); ?></label>
149
+ <input checked type="checkbox" id="content_types" name="settings[]" value="content_type"><label for="content_types"><?php echo _e( 'Content Types', 'lingotek-translation' ); ?></label>
150
+ <input checked type="checkbox" id="preferences" name="preferences" value="preferences"><label for="preferences"><?php echo _e( 'Preferences', 'lingotek-translation' ); ?></label>
151
  </td>
152
  </tr>
153
  <tr>
154
+ <th><?php echo _e( 'New Project', 'lingotek-translation' ); ?></th>
155
  <td>
156
+ <input checked type="checkbox" name="new_project" id="new_project" ><label for="new_project"><?php echo _e( 'Create a new project using the name of the selected site (Recommended for a newly created site)', 'lingotek-translation' ); ?></label>
157
  </td>
158
  </tr>
159
  <tr>
160
+ <th><?php echo _e( 'Language', 'lingotek-translation' ); ?></th>
161
  <td>
162
+ <input checked type="checkbox" name="utility_set_default_language" id="utility_set_default_language" ><label for="utility_set_default_language"><?php echo _e( 'Set <i>default language</i> as the language for all existing content that has not been assigned a language.', 'lingotek-translation' ); ?></label>
163
  </td>
164
  </tr>
165
  </table>
166
 
167
  <p>
168
+ <?php submit_button( __( 'Update Options', 'lingotek-translation' ), 'primary', 'submit', false ); ?>
169
  </p>
170
 
171
  </form>
172
+ </div>
admin/view-tutorial.php CHANGED
@@ -1,49 +1,54 @@
1
  <?php
2
 
3
  $menu_items = array(
4
- 'features' => __("Features", 'lingotek-translation'),
5
- 'content' => __('Tutorial', 'lingotek-translation'),
6
- 'faq' => __('FAQ', 'lingotek-translation'),
7
- 'credits' => __('Credits', 'lingotek-translation'),
8
  );
9
 
10
- ?>
11
 
12
 
13
  <div class="wrap about-wrap">
14
 
15
- <h1><?php printf( __( 'Welcome to Lingotek' , 'lingotek-translation') ); ?></h1>
16
 
17
- <div class="about-text"><?php printf( __( 'Thank you for updating! Lingotek offers convenient cloud-based localization and translation.' , 'lingotek-translation'), LINGOTEK_VERSION ); ?></div>
18
 
19
 
20
- <div class="wp-badge" style="background: url(<?php echo LINGOTEK_URL ?>/img/lingotek-chevrons-blue.png) center 24px/85px 80px no-repeat #fff; color: #666;"><?php printf( __( 'Version %s' , 'lingotek-translation'), LINGOTEK_VERSION ); ?></div>
21
 
22
  <h2 class="nav-tab-wrapper">
23
  <?php
24
- $menu_item_index = 0;
25
- foreach ($menu_items as $menu_item_key => $menu_item_label) {
26
- $use_as_default = ($menu_item_index === 0 && !isset($_GET['sm'])) ? TRUE : FALSE;
27
- ?>
28
-
29
- <a class="nav-tab <?php if ($use_as_default || (isset($_GET['sm']) && $_GET['sm'] == $menu_item_key)): ?> nav-tab-active<?php endif; ?>"
30
- href="admin.php?page=<?php echo $_GET['page']; ?>&sm=<?php echo $menu_item_key; ?>"><?php echo $menu_item_label; ?></a>
31
- <?php
32
- $menu_item_index++;
33
- }
34
- ?>
 
 
 
 
35
  </h2>
36
 
37
 
38
  <?php
39
- settings_errors();
40
- $submenu = isset($_GET['sm']) ? sanitize_text_field($_GET['sm']) : current(array_keys($menu_items));
41
- $dir = dirname(__FILE__) . '/tutorial/';
42
- $filename = $dir . $submenu . ".php";
43
- if (file_exists($filename))
44
- include $filename;
45
- else
46
- echo "TO-DO: create <i>" . 'tutorial/' . $submenu . ".php</i>";
 
47
  ?>
48
 
49
  </div>
1
  <?php
2
 
3
  $menu_items = array(
4
+ 'features' => __( 'Features', 'lingotek-translation' ),
5
+ 'content' => __( 'Tutorial', 'lingotek-translation' ),
6
+ 'faq' => __( 'FAQ', 'lingotek-translation' ),
7
+ 'credits' => __( 'Credits', 'lingotek-translation' ),
8
  );
9
 
10
+ ?>
11
 
12
 
13
  <div class="wrap about-wrap">
14
 
15
+ <h1><?php printf( __( 'Welcome to Lingotek', 'lingotek-translation' ) ); ?></h1>
16
 
17
+ <div class="about-text"><?php printf( __( 'Thank you for updating! Lingotek offers convenient cloud-based localization and translation.', 'lingotek-translation' ), LINGOTEK_VERSION ); ?></div>
18
 
19
 
20
+ <div class="wp-badge" style="background: url(<?php echo LINGOTEK_URL; ?>/img/lingotek-chevrons-blue.png) center 24px/85px 80px no-repeat #fff; color: #666;"><?php printf( __( 'Version %s', 'lingotek-translation' ), LINGOTEK_VERSION ); ?></div>
21
 
22
  <h2 class="nav-tab-wrapper">
23
  <?php
24
+ $menu_item_index = 0;
25
+ foreach ( $menu_items as $menu_item_key => $menu_item_label ) {
26
+ $use_as_default = ( $menu_item_index === 0 && ! isset( $_GET['sm'] ) ) ? true : false;
27
+ ?>
28
+
29
+ <a class="nav-tab
30
+ <?php
31
+ if ( $use_as_default || ( isset( $_GET['sm'] ) && $_GET['sm'] == $menu_item_key ) ) :
32
+ ?>
33
+ nav-tab-active<?php endif; ?>"
34
+ href="admin.php?page=<?php echo $_GET['page']; ?>&sm=<?php echo $menu_item_key; ?>"><?php echo $menu_item_label; ?></a>
35
+ <?php
36
+ $menu_item_index++;
37
+ }
38
+ ?>
39
  </h2>
40
 
41
 
42
  <?php
43
+ settings_errors();
44
+ $submenu = isset( $_GET['sm'] ) ? sanitize_text_field( $_GET['sm'] ) : current( array_keys( $menu_items ) );
45
+ $dir = dirname( __FILE__ ) . '/tutorial/';
46
+ $filename = $dir . $submenu . '.php';
47
+ if ( file_exists( $filename ) ) {
48
+ require $filename;
49
+ } else {
50
+ echo 'TO-DO: create <i>' . 'tutorial/' . $submenu . '.php</i>';
51
+ }
52
  ?>
53
 
54
  </div>
admin/workflows/credit-card-to-path.php CHANGED
@@ -2,47 +2,47 @@
2
 
3
  class Lingotek_Credit_Card_To_Path {
4
 
5
- private $cc_type_map = array();
6
- private $default_cc = 'Default';
7
- private static $instance = null;
8
-
9
-
10
- public static function get_url($cc_type) {
11
- self::check_instantiated();
12
- return self::$instance->get_cc_type_asset_url($cc_type);
13
- }
14
-
15
- public static function get_cc_map() {
16
- self::check_instantiated();
17
- return self::$instance->cc_type_map;
18
- }
19
-
20
- public static function get_cc_type_asset_url($cc_type) {
21
- self::check_instantiated();
22
- return isset( self::$instance->cc_type_map[ $cc_type ] ) ? self::$instance->cc_type_map[ $cc_type ] : self::$instance->cc_type_map[ self::$instance->default_cc ];
23
- }
24
-
25
- public static function get_default_cc_key() {
26
- self::check_instantiated();
27
- return self::$instance->default_cc;
28
- }
29
-
30
-
31
- private function __construct() {
32
- $this->cc_type_map = array(
33
- 'MasterCard' => LINGOTEK_URL . '/img/credit-cards/mastercard.svg',
34
- 'AmericanExpress' => LINGOTEK_URL . '/img/credit-cards/amex.svg',
35
- 'Discover' => LINGOTEK_URL . '/img/credit-cards/discover.svg',
36
- 'JCB' => LINGOTEK_URL . '/img/credit-cards/jcb.svg',
37
- 'DinersClub' => LINGOTEK_URL . '/img/credit-cards/diners.svg',
38
- 'Visa' => LINGOTEK_URL . '/img/credit-cards/visa.svg',
39
- $this->default_cc => LINGOTEK_URL . '/img/credit-cards/default.svg',
40
- );
41
- }
42
-
43
- private static function check_instantiated() {
44
- if (! self::$instance) {
45
- self::$instance = new Lingotek_Credit_Card_To_Path();
46
- }
47
- }
48
- }
2
 
3
  class Lingotek_Credit_Card_To_Path {
4
 
5
+ private $cc_type_map = array();
6
+ private $default_cc = 'Default';
7
+ private static $instance = null;
8
+
9
+
10
+ public static function get_url( $cc_type ) {
11
+ self::check_instantiated();
12
+ return self::$instance->get_cc_type_asset_url( $cc_type );
13
+ }
14
+
15
+ public static function get_cc_map() {
16
+ self::check_instantiated();
17
+ return self::$instance->cc_type_map;
18
+ }
19
+
20
+ public static function get_cc_type_asset_url( $cc_type ) {
21
+ self::check_instantiated();
22
+ return isset( self::$instance->cc_type_map[ $cc_type ] ) ? self::$instance->cc_type_map[ $cc_type ] : self::$instance->cc_type_map[ self::$instance->default_cc ];
23
+ }
24
+
25
+ public static function get_default_cc_key() {
26
+ self::check_instantiated();
27
+ return self::$instance->default_cc;
28
+ }
29
+
30
+
31
+ private function __construct() {
32
+ $this->cc_type_map = array(
33
+ 'MasterCard' => LINGOTEK_URL . '/img/credit-cards/mastercard.svg',
34
+ 'AmericanExpress' => LINGOTEK_URL . '/img/credit-cards/amex.svg',
35
+ 'Discover' => LINGOTEK_URL . '/img/credit-cards/discover.svg',
36
+ 'JCB' => LINGOTEK_URL . '/img/credit-cards/jcb.svg',
37
+ 'DinersClub' => LINGOTEK_URL . '/img/credit-cards/diners.svg',
38
+ 'Visa' => LINGOTEK_URL . '/img/credit-cards/visa.svg',
39
+ $this->default_cc => LINGOTEK_URL . '/img/credit-cards/default.svg',
40
+ );
41
+ }
42
+
43
+ private static function check_instantiated() {
44
+ if ( ! self::$instance ) {
45
+ self::$instance = new Lingotek_Credit_Card_To_Path();
46
+ }
47
+ }
48
+ }
admin/workflows/professional-translation-workflow.php CHANGED
@@ -1,8 +1,7 @@
1
  <?php
2
-
3
  /**
4
  * Overrides uploads for Posts, Pages and Terms in order to display a modal and handle redirecting to bridge for payment.
5
- * The base class contains better documentation on what each individual function means.
6
  */
7
  class Lingotek_Professional_Translation_Workflow extends Lingotek_Workflow {
8
 
@@ -12,71 +11,70 @@ class Lingotek_Professional_Translation_Workflow extends Lingotek_Workflow {
12
  /**
13
  * Writes a modal to the output buffer that contains information about this workflow.
14
  *
15
- * @param string $id the workflow id.
 
16
  */
17
- public function echo_info_modal( $item_id = null, $item_type = null ) {
18
- if (Lingotek_Professional_Translation_Workflow::is_allowed_user()) {
19
  if ( ! self::$info_modal_launched ) {
20
  self::$info_modal_launched = true;
21
-
22
- wp_enqueue_script( 'lingotek_professional_workflow_defaults', LINGOTEK_URL . '/js/workflow/professional-workflow-defaults.js' );
23
 
24
  $client = new Lingotek_API();
25
 
26
  $payment_info = $client->get_user_payment_information();
27
 
28
  $vars = array(
29
- 'workflow_id' => $this->workflow_id,
30
- 'bridge_payment' => BRIDGE_URL . '/#/payment/portal',
31
  'translation_icon' => LINGOTEK_URL . '/img/translation-logo.png',
32
- 'loading_gif' => LINGOTEK_URL . '/img/loading.gif',
33
- 'icon_url' => LINGOTEK_URL . '/img/lingotek-logo-white.png',
34
- 'payment_info' => $payment_info
35
  );
36
  wp_localize_script( 'lingotek_professional_workflow_defaults', 'professional_vars', $vars );
37
 
38
  wp_enqueue_style( 'lingotek_professional_workflow_style', LINGOTEK_URL . '/css/workflow/professional-workflow-style.css', array(), LINGOTEK_VERSION );
39
  $args = array(
40
  'parent_elements' => $this->get_payment_portal_html(),
41
- 'body' => __( "
42
-
43
- <div class='Youve-Selected-Prof'>You've Selected Professional Translation</div><br>
44
-
45
- <div class='By-Selecting-this-op'>
46
- By selecting this option as your workflow you will be able to request professional translations through Lingotek’s Languages Services.
47
- Please click the \"ADD PAYMENT METHOD\" button to use this service.
48
- </div><br><br><br>
49
-
50
- <div class='Note-By-using-the-'>
51
- Note: By using the 'Lingotek Professional Translation' workflow you will be asked to confirm payment before the professional translation request is processed.
52
- </div>
53
-
54
- <button type='button' id='no-" . esc_attr( $this->workflow_id ) . "' class='background-test float-bottom-right-next-to-default'>
55
- <span class='ADD-PAYMENT-LATER'>LATER</span>
56
- </button>
57
- <button type='button' id='yes-" . esc_attr( $this->workflow_id ) . "' class='prefessional-action-button-default float-bottom-right'>
58
- <span class='ADD-PAYMENT'>ADD PAYMENT METHOD</span>
59
- </button>
60
- </div>
61
-
62
- ", 'lingotek-translation' ),
63
- 'id' => $this->workflow_id,
64
  );
65
  $this->_echo_modal( $args );
66
- }
67
- }
68
  }
69
 
70
  /**
71
  * Writes a modal to the output buffer that tells the user how much it is going to cost.
72
  *
73
- * @param string $id the workflow id.
 
 
74
  */
75
  public function echo_posts_modal( $item_id = null, $wp_locale = null, $item_type = null ) {
76
- $this->add_item_id($item_id, $wp_locale);
77
- if (Lingotek_Professional_Translation_Workflow::is_allowed_user()) {
78
  if ( ! self::$post_modal_launched ) {
79
- self::$post_modal_launched = true;
80
  $this->echo_upload_warning_modal();
81
  $this->echo_request_modal( 'post' );
82
  }
@@ -88,12 +86,13 @@ class Lingotek_Professional_Translation_Workflow extends Lingotek_Workflow {
88
  /**
89
  * Writes a modal to the output buffer that tells the user how much it is going to cost.
90
  *
91
- * @param string $id the workflow id.
 
 
92
  */
93
  public function echo_terms_modal( $item_id = null, $wp_locale = null, $item_type = null ) {
94
- $this->add_item_id($item_id, $wp_locale);
95
- if (Lingotek_Professional_Translation_Workflow::is_allowed_user())
96
- {
97
  if ( ! self::$terms_modal_launched ) {
98
  self::$terms_modal_launched = true;
99
  $this->echo_upload_warning_modal();
@@ -106,12 +105,13 @@ class Lingotek_Professional_Translation_Workflow extends Lingotek_Workflow {
106
  /**
107
  * Writes a modal to the output buffer that tells the user how much it is going to cost.
108
  *
109
- * @param string $id the workflow id.
 
 
110
  */
111
  public function echo_strings_modal( $item_id = null, $wp_locale = null, $item_type = null ) {
112
- $this->add_item_id($item_id, $wp_locale);
113
- if (Lingotek_Professional_Translation_Workflow::is_allowed_user())
114
- {
115
  if ( ! self::$strings_modal_launched ) {
116
  self::$strings_modal_launched = true;
117
  $this->echo_upload_warning_modal();
@@ -123,56 +123,54 @@ class Lingotek_Professional_Translation_Workflow extends Lingotek_Workflow {
123
 
124
  /**
125
  * Writes a modal to the output buffer that tells the user if certain translations will
126
- * be overwritten by a given action.
127
- *
128
- * @param string $id the workflow id.
129
  */
130
  private function echo_upload_warning_modal() {
131
- $id = $this->workflow_id . '-warning';
132
  $args = array(
133
  'header' => __( 'Confirm Document Upload', 'lingotek-translation' ),
134
- 'body' => __( "
 
135
  <div id='warning-wrapper'>
136
  <div class='professional-upload-warning-header-container'>
137
  <span class='professional-upload-warning-header'>By uploading these changes, your professional translations may be lost.</span>
138
  </div>
139
-
140
  <div class='professional-upload-warning-body-container'>
141
  <span class='professional-upload-warning-body'>
142
  By editing this document and then re-uploading it to Lingotek any professional translations that you have not downloaded yet will be lost. Additionally, any professional translations that are in-progress for this document will be lost.
143
  </span>
144
  </div>
145
-
146
  <div class='professional-warning-checkbox-container'><input id='professional-warning-checkbox' type='checkbox' name='confirm-request' value='professional-warning-upload></div>
147
  <div class='professional-warning-checkbox-text-container'><span class='professional-warning-checkbox-text'> I understand that translations that have not been downloaded or that are in progress will be lost and money paid for that translation will be forfeited by re-uploading them to Lingotek.</span></div>
148
 
149
  <button type='button' id='cancel-warning-" . esc_attr( $id ) . "' class='professional-cancel-button float-bottom-right-next-to'>
150
  <span class='ADD-PAYMENT-LATER'>CANCEL</span>
151
  </button>
152
- <div class='float-bottom-right' style='bottom:5%;'><img id='professional-warning-loading-spinner' style='display:none;' src='". esc_url_raw( LINGOTEK_URL ) ."/img/loading_mini.gif' /></div>
153
  <button type='button' id='ok-warning-" . esc_attr( $id ) . "' class='professional-okay-warning-button-disabled float-bottom-right' disabled='true'>
154
  <span id='professional-warning-okay-text' class='ADD-PAYMENT-DISABLED'>PROCEED</span>
155
  </button>
156
 
157
- </div>", 'lingotek-translation' ),
158
- 'id' => $id,
159
  );
160
  $this->_echo_modal( $args );
161
  }
162
 
163
  /**
164
- * Writes a modal to the output buffer that is launched when the user clicks on the 'request translation'
165
- * option.
166
  *
167
- * @param string $id the workflow id.
168
  */
169
  public function echo_request_modal( $type ) {
170
- if (Lingotek_Professional_Translation_Workflow::is_allowed_user())
171
- {
172
  $this->load_request_scripts_and_styles( $type );
173
- $id = $this->workflow_id . '-request';
174
  $args = array(
175
- 'header' => __( 'Confirm Request Translation', 'lingotek-translation' ),
176
  'parent_elements' => "
177
  <img class='loading-element loading-translations-image' src='" . esc_url_raw( LINGOTEK_URL ) . "/img/translation-logo.png'/>
178
  <div class='loading-element loading-progress-bar-outer'>
@@ -181,167 +179,148 @@ class Lingotek_Professional_Translation_Workflow extends Lingotek_Workflow {
181
  <span class='loading-element loading-progress-percent'>65%</span>
182
  <div class='loading-element Analyzing-translations'>Analyzing translations and gathering quotes...</div>
183
  ",
184
- 'body' => __( "
185
- <div id='wrapper'>
186
- <div id='content'><br>
187
- <div id='professional-table-content'>
188
- <span class='Congratulations-You payment-method-setup'>You have elected to use our Professional Translation Services.<br><br></span>
189
- <div class='You-can-now-connect payment-method-setup'>
190
- You can now connect with audiences around the globe using Lingotek's network of 5000+ professional, in-country, translators. Professional Translation ensures that your audiences will feel the sentiment of your content.
191
- </div>
192
-
193
- <span class='Congratulations-You payment-not-setup'>Welcome to Lingotek's Translation Quote Calculator<br><br></span>
194
- <div class='You-can-now-connect payment-not-setup'>
195
- Using the quote calculator below you can get an idea of how much your translations will cost. You will need to add a payment method to the Lingotek Secure Payment Portal In order to purchase these translations.
196
- </div>
197
- <br>
198
- <div class='minimum-per-language-warning minimum-warning'>
199
- <img src='". esc_url_raw( LINGOTEK_URL ) ."/img/minimum-warning.svg' />
200
- <span >*$59.99 minimum per language.</span>
201
- <span ltk-data-tooltip='This minimum ensures that we can retain the best professional linguists for your translation job.'><img src='". esc_url_raw( LINGOTEK_URL ) ."/img/minimum-help.svg' /></span>
202
- </div>
203
- <br class='payment-not-setup'>
204
- <span class='Translation-Request payment-not-setup'>Translation Quotes<br><br></span>
205
- <br class='payment-method-setup'>
206
- <span class='Translation-Request payment-method-setup'>Translation Request Summary<br><br></span>
207
- <div id='table-wrapper'>
208
- <table class='request-table'>
209
- <tr class='bordered-bottom'><th style='display: table-cell;' class='table-header'>Title</th><th style='display: table-cell;' class='table-header' id='words-column'>Words</th><th style='text-align:center;'><a href='#' id='next-language-set'> <img id='next-language-image' src='" . esc_url_raw( LINGOTEK_URL ) . "/img/right-arrow.svg' /> </a> </th><th class='table-header table-total invisible'>Total</th></tr>
210
- </table>
211
- </div>
212
- </div>
213
- <div id='professional-terms-and-conditions'>
214
- <span class='terms-and-conditions-header'>Lingotek Terms and Conditions</span><br><br>
215
- <div class='terms-and-conditions-content'>
216
-
217
-
218
-
219
-
220
-
221
-
222
-
223
-
224
-
225
-
226
- <img id='terms-of-service-loading-ltk' src='". esc_url_raw( LINGOTEK_URL ) ."/img/loading.gif'/>
227
-
228
-
229
-
230
-
231
-
232
-
233
-
234
-
235
-
236
- </div>
237
- <button type='button' id='close-terms-and-conditions'>
238
- <span class='CLOSE-TERMS-CONDITIONS'>CLOSE</span>
239
- </button>
240
  </div>
241
- </div>
242
- <div id='sidebar'>
243
- <span class='Payment-Method payment-method-setup'>Payment Method</span><br class='payment-method-setup'><br class='payment-method-setup'>
244
- <span class='payment-method-setup credit-card-header'>Credit Card</span><br class='payment-method-setup'><br class='payment-method-setup'>
245
- <div class='payment-method-setup professional-card-border'>
246
- <div class='payment-method-setup blue-radio-button-div'><img id='blue-radio-button' class='payment-method-setup' src='" . esc_url_raw( LINGOTEK_URL ) . "/img/blue-radio-button.svg'/></div>
247
- <div class='payment-method-setup credit-card-dots-div'><img id='credit-card-dots' class='payment-method-setup' src='" . esc_url_raw( LINGOTEK_URL ) . "/img/credit-dots.svg'/></div>
248
- <div class='payment-method-setup last-four-digits-div'><span id='last-four-digits' class='payment-method-setup'>XXXX</span></div>
249
- <div class='payment-method-setup credit-card-image-div'><img id='credit-card-image' class='payment-method-setup' src='" . Lingotek_Credit_Card_To_Path::get_cc_type_asset_url( Lingotek_Credit_Card_To_Path::get_default_cc_key() ) . "'/></div>
250
  </div>
251
- <br class='payment-method-setup'>
252
- <br class='payment-method-setup'>
253
-
254
-
255
- <span class='Payment-Method payment-not-setup'>Benefits of Professional Translation</span><br class='payment-not-setup'>
256
- <ul class='translation-summary-list payment-not-setup'>
257
- <li><span class='translation-summary-list-text'>Translations will be translated by professional in-country linguists.</span></li>
258
- <li><span class='translation-summary-list-text'>Receive your translations in just a few days.</span></li>
259
- <li><span class='translation-summary-list-text'>100% customer satisfaction guarantee.</span></li>
260
- </ul>
261
- <br class='payment-not-setup'>
262
- <span class='Translation-Request-Right payment-method-setup'>Translation Request Summary</span>
263
- <span class='Translation-Request-Right payment-not-setup'>Translation Quote Summary</span>
264
- <ul class='translation-summary-list translation-summary-list-ltk'>
265
-
266
- </ul>
267
- <div class='minimum-disclaimer'>*Minimum charge $59.99 per language</div>
268
  <br>
269
- <div style='float:right;'>
270
- <span class='request-total'>TOTAL: </span><span class='lingotek-total-amount'></span>
 
 
271
  </div>
272
-
273
- <div class='ltk-request-payment-disclaimer payment-method-setup'>
274
- Note: By clicking the 'Buy Now' button your translations will be requested and you will be charged for the amount shown above.
 
 
 
 
 
275
  </div>
276
-
277
-
278
- <br class='payment-not-setup'><br class='payment-not-setup'><br class='payment-not-setup'>
279
- <div class='disclaimer-request payment-not-setup'>
280
- Note: By clicking the 'Add Payment Method' button you will be redirected to the Lingotek Secure Payment Portal.
281
- Please note that none of the selections you have made in the table will be saved.
282
  </div>
283
- <br class='payment-method-setup'><br class='payment-method-setup'>
284
-
285
- <div class='delivery-estimation'>Estimated delivery: <span class='business-days'>3 - 5 business days.</span><span ltk-data-tooltip='This is an estimate, not a guaranteed delivery time.'><img src='". esc_url_raw( LINGOTEK_URL ) ."/img/minimum-help.svg' /></span></div>
286
- <div class='request-checkbox payment-method-setup'><input id='accept-terms-and-conditions-input' type='checkbox' name='confirm-request' value='request-translation><span class='terms-conditions'> I agree to the <a id='terms-and-conditions-href' href='#'>Lingotek Terms and Conditions</a></span></div>
287
- <br class='payment-method-setup'>
288
-
289
- <button type='button' id='yes-" . esc_attr( $id ) . "-add-payment' class='professional-action-button float-center payment-not-setup' style='float:left'>
290
- <span id='professional-add-payment' class='ADD-PAYMENT payment-not-setup'>ADD PAYMENT METHOD</span>
291
- </button>
292
- <button type='button' id='yes-" . esc_attr( $id ) . "-buy-now' class='professional-action-button-disabled float-center payment-method-setup' style='float:left; bottom:-2%;' disabled='true'>
293
- <span id='professional-buy-now' class='ADD-PAYMENT-DISABLED payment-method-setup'>BUY NOW</span>
294
  </button>
295
  </div>
296
- <div id='cleared'></div>
297
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
298
 
 
 
 
 
 
 
 
 
 
 
 
299
 
300
- <div id='requesting-translation-screen' class='requesting-element'>
301
- <img class='requesting-element payment-portal-image' src='". esc_url_raw( LINGOTEK_URL ) ."/img/translation-logo.png'/>
302
- <img class='requesting-element payment-portal-loading' src='". esc_url_raw( LINGOTEK_URL ) ."/img/loading.gif'/>
303
- <div class='requesting-element Analyzing-translations'>Requesting Translations</div>
304
- </div>
305
-
306
- <div id='requesting-translation-success-screen' class='professional-translation-request-success-element'>
307
- <img class='professional-translation-request-success-element payment-portal-image' src='". esc_url_raw( LINGOTEK_URL ) ."/img/translation-logo.png'/>
308
- <img class='professional-translation-request-success-element green-check-success' src='" . esc_url_raw( LINGOTEK_URL ) . "/img/checkmark-green.svg'/>
309
- <div class='professional-translation-request-success-element professional-translation-view-invoice' style='height: 28px;'>Your translations have been successfully requested.</div>
310
- <div class='professional-translation-request-success-element professional-translation-view-invoice'>You will be receiving a confirmation email shortly.</div>
311
- <div class='professional-translation-request-success-element professional-translation-view-invoice'>Your credit card will be charged <span id='professional-translation-cost-success' class='professional-translation-request-success-element'></span></div>
312
- <button type='button' id='professional-post-transaction-button' class='professional-translation-request-success-element professional-view-invoice-btn float-center'>
313
- <span id='professional-post-transaction' class='ADD-PAYMENT professional-translation-request-success-element'>OK</span>
314
  </button>
315
- </div>
316
-
317
-
318
-
319
- <div id='requesting-translation-error-screen' class='professional-translation-request-error-element'>
320
- <img class='professional-translation-request-error-element payment-portal-image' src='". esc_url_raw( LINGOTEK_URL ) ."/img/translation-logo.png'/>
321
- <img class='professional-translation-request-error-element green-check-success' src='" . esc_url_raw( LINGOTEK_URL ) . "/img/error.svg'/>
322
- <div id='error-requesting-translation-ltk' class='professional-translation-request-error-element professional-translation-view-invoice'>There was an error requesting your translation.</div>
323
- <div id='error-requesting-translation-ltk-2' class='professional-translation-request-error-element professional-translation-view-invoice'>Please refresh the page and try again.</div>
324
- <button type='button' id='professional-post-transaction-button' class='professional-translation-request-error-element professional-view-invoice-btn float-center'>
325
- <span id='professional-post-transaction-failure' class='ADD-PAYMENT professional-translation-request-error-element'>Ok</span>
326
  </button>
327
  </div>
328
-
329
- </div>
330
- ".$this->get_payment_portal_html()."
331
-
332
- ", 'lingotek-translation' ),
333
- 'id' => $id,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
334
  );
335
  $this->_echo_modal( $args );
336
- }
337
  }
338
 
339
  /**
340
- * This method will be used to roll out the Professional Translation workflow to a select number of users.
341
- * The method will be called before anything is sent to the client.
342
- */
343
- public static function is_allowed_user()
344
- {
345
  return true;
346
  }
347
 
@@ -354,17 +333,19 @@ class Lingotek_Professional_Translation_Workflow extends Lingotek_Workflow {
354
  private static $pre_uploaded = array();
355
 
356
  /**
357
- * We disassociate the document before uploading to avoid automatic requesting of translations.
358
  *
359
- * @param string $item_id
360
  * @param string $type
361
  * @return void
362
  */
363
- public function pre_upload_to_lingotek($item_id, $type) {
364
- $lgtm = new Lingotek_Model();
365
- if ($document = $lgtm->get_group($type, $item_id)) {
366
- if (isset(self::$pre_uploaded[$document->document_id])) { return; }
367
- self::$pre_uploaded[$document->document_id] = true;
 
 
368
  $document->delete();
369
  }
370
  }
@@ -379,11 +360,11 @@ class Lingotek_Professional_Translation_Workflow extends Lingotek_Workflow {
379
  * @return void
380
  */
381
  public function save_post_hook() {
382
- if (! self::$save_post_hook_executed) {
383
  self::$save_post_hook_executed = true;
384
- $post_vars = filter_input_array(INPUT_POST);
385
-
386
- if ('inline-save' === $post_vars['action']) {
387
  echo '<script>location.reload();</script>';
388
  }
389
  }
@@ -398,11 +379,11 @@ class Lingotek_Professional_Translation_Workflow extends Lingotek_Workflow {
398
  * @return void
399
  */
400
  public function save_term_hook() {
401
- if (! self::$save_terms_hook_executed) {
402
  self::$save_terms_hook_executed = true;
403
- $post_vars = filter_input_array(INPUT_POST);
404
-
405
- if ('inline-save-tax' === $post_vars['action']) {
406
  echo '<script>location.reload();</script>';
407
  }
408
  }
@@ -413,19 +394,22 @@ class Lingotek_Professional_Translation_Workflow extends Lingotek_Workflow {
413
  *
414
  * @return boolean
415
  */
416
- public function has_custom_request_procedure() { return true; }
 
417
 
418
  /**
419
  * We don't want documents being uploaded automatically because of the chance
420
  * that a user may lose translations that they have paid for if they haven't finished or downloaded.
421
  *
422
- * @return void
423
  */
424
- public function auto_upload_allowed() { return false; }
 
 
425
 
426
 
427
- public function get_custom_in_progress_icon() {
428
- return '<div title="Professional translation in progress" class="lingotek-professional-icon"><img src="'. LINGOTEK_URL . '/img/human-translation.svg" /></div>';
429
  }
430
 
431
  /**
@@ -434,68 +418,64 @@ class Lingotek_Professional_Translation_Workflow extends Lingotek_Workflow {
434
  * @param string $type
435
  * @return void
436
  */
437
- private function load_request_scripts_and_styles($type)
438
- {
439
  add_thickbox();
440
- wp_enqueue_script( 'lingotek_professional_workflow', LINGOTEK_URL . '/js/workflow/professional-workflow.js', array(), LINGOTEK_VERSION );
441
  wp_enqueue_style( 'lingotek_professional_workflow_style', LINGOTEK_URL . '/css/workflow/professional-workflow-style.css', array(), LINGOTEK_VERSION );
442
 
443
  $client = new Lingotek_API();
444
 
445
  $language_mappings = $client->get_language_mappings();
446
- $locales_list = PLL()->model->get_languages_list();
447
 
448
  $enabled_langs = array();
449
- foreach ($locales_list as $locale)
450
- {
451
- $lingotek_gmc_locale = str_replace('-', '_', $locale->lingotek_locale);
452
- $enabled_langs[$locale->locale] = array(
453
  'lingotek_locale' => $locale->lingotek_locale,
454
- 'language' => isset($language_mappings[$lingotek_gmc_locale])
455
- ? $language_mappings[$lingotek_gmc_locale]['language_name']
456
  : null,
457
- 'country_name' => isset($language_mappings[$lingotek_gmc_locale])
458
- ? $language_mappings[$lingotek_gmc_locale]['country_name']
459
  : null,
460
  );
461
  }
462
-
463
  $vars = array(
464
- 'workflow_id' => $this->workflow_id,
465
- 'icon_url' => LINGOTEK_URL . '/img/lingotek-logo-white.png',
466
- 'question_mark_icon_url' => LINGOTEK_URL . '/img/questionmark.svg',
467
  'bridge_payment_redirect' => BRIDGE_URL . '/#/payment/portal',
468
- 'enabled_langs' => $enabled_langs,
469
- 'curr_item_type' => $type,
470
- 'cc_type_map' => Lingotek_Credit_Card_To_Path::get_cc_map(),
471
- 'default_cc_type' => Lingotek_Credit_Card_To_Path::get_default_cc_key(),
472
- 'nonce' => wp_create_nonce( 'lingotek_professional' )
473
  );
474
  wp_localize_script( 'lingotek_professional_workflow', 'workflow_vars', $vars );
475
  }
476
 
477
 
478
  /**
479
- * As the table is being built (for posts, pages, terms, etc.) we only want to attach listeners to locales that have the professional
480
  * workflow enabled. This list is build as the table is being rendered.
481
  *
482
  * @param string $item_id
483
  * @param string $wp_locale
484
  * @return void
485
  */
486
-
487
  private function add_item_id( $item_id, $wp_locale ) {
488
- self::$item_id_list[$item_id][] = $wp_locale;
489
  }
490
 
491
  /**
492
- * Because a new workflow object is created every time a new locale is rendered on the table we can't preserve the list in a single object.
493
  * Instead, we store that list statically and update the list that will eventually be sent to the front end everytime a workflow object is destroyed.
494
  *
495
  * @return void
496
  */
497
- private function flush_list()
498
- {
499
  $vars = array(
500
  'ids' => self::$item_id_list,
501
  );
@@ -505,14 +485,13 @@ class Lingotek_Professional_Translation_Workflow extends Lingotek_Workflow {
505
  /**
506
  * Returns the HTML that displays the payment portal loading screen.
507
  *
508
- * @return void
509
  */
510
- private function get_payment_portal_html()
511
- {
512
  return "
513
  <div id='payment-portal-wrapper' class='payment-portal-element'>
514
- <img class='payment-portal-element payment-portal-image' src='". esc_url_raw( LINGOTEK_URL ) ."/img/translation-logo.png'/>
515
- <img class='payment-portal-element payment-portal-loading' src='". esc_url_raw( LINGOTEK_URL ) ."/img/loading.gif'/>
516
  <span class='payment-portal-element You-are-now-being-re'>You are now being redirected to the Lingotek Secure Payment Portal...</span>
517
  </div>
518
  ";
1
  <?php
 
2
  /**
3
  * Overrides uploads for Posts, Pages and Terms in order to display a modal and handle redirecting to bridge for payment.
4
+ * The base class contains better documentation on what each individual function means.
5
  */
6
  class Lingotek_Professional_Translation_Workflow extends Lingotek_Workflow {
7
 
11
  /**
12
  * Writes a modal to the output buffer that contains information about this workflow.
13
  *
14
+ * @param string $item_id The workflow id.
15
+ * @param string $item_type
16
  */
17
+ public function lingotek_translation_professional_translation_info_modal( $item_id = null, $item_type = null ) {
18
+ if ( self::is_allowed_user() ) {
19
  if ( ! self::$info_modal_launched ) {
20
  self::$info_modal_launched = true;
21
+
22
+ wp_enqueue_script( 'lingotek_professional_workflow_defaults', LINGOTEK_URL . '/js/workflow/professional-workflow-defaults.js', array(), LINGOTEK_VERSION, false );
23
 
24
  $client = new Lingotek_API();
25
 
26
  $payment_info = $client->get_user_payment_information();
27
 
28
  $vars = array(
29
+ 'workflow_id' => $this->workflow_id,
30
+ 'bridge_payment' => BRIDGE_URL . '/#/payment/portal',
31
  'translation_icon' => LINGOTEK_URL . '/img/translation-logo.png',
32
+ 'loading_gif' => LINGOTEK_URL . '/img/loading.gif',
33
+ 'icon_url' => LINGOTEK_URL . '/img/lingotek-logo-white.png',
34
+ 'payment_info' => $payment_info,
35
  );
36
  wp_localize_script( 'lingotek_professional_workflow_defaults', 'professional_vars', $vars );
37
 
38
  wp_enqueue_style( 'lingotek_professional_workflow_style', LINGOTEK_URL . '/css/workflow/professional-workflow-style.css', array(), LINGOTEK_VERSION );
39
  $args = array(
40
  'parent_elements' => $this->get_payment_portal_html(),
41
+ 'body' =>
42
+ "
43
+ <div class='Youve-Selected-Prof'>You've Selected Professional Translation</div><br>
44
+ <div class='By-Selecting-this-op'>
45
+ By selecting this option as your workflow you will be able to request professional translations through Lingotek’s Languages Services.
46
+ Please click the \"ADD PAYMENT METHOD\" button to use this service.
47
+ </div><br><br><br>
48
+ <div class='Note-By-using-the-'>
49
+ Note: By using the 'Lingotek Professional Translation' workflow you will be asked to confirm payment before the professional translation request is processed.
50
+ </div>
51
+ <button type='button' id='no-" . esc_attr( $this->workflow_id ) . "' class='background-test float-bottom-right-next-to-default'>
52
+ <span class='ADD-PAYMENT-LATER'>LATER</span>
53
+ </button>
54
+ <button type='button' id='yes-" . esc_attr( $this->workflow_id ) . "' class='prefessional-action-button-default float-bottom-right'>
55
+ <span class='ADD-PAYMENT'>ADD PAYMENT METHOD</span>
56
+ </button>
57
+ </div>
58
+ ",
59
+ 'id' => $this->workflow_id,
 
 
 
 
60
  );
61
  $this->_echo_modal( $args );
62
+ }//end if
63
+ }//end if
64
  }
65
 
66
  /**
67
  * Writes a modal to the output buffer that tells the user how much it is going to cost.
68
  *
69
+ * @param string $item_id The workflow id.
70
+ * @param string $wp_locale
71
+ * @param string $item_type
72
  */
73
  public function echo_posts_modal( $item_id = null, $wp_locale = null, $item_type = null ) {
74
+ $this->add_item_id( $item_id, $wp_locale );
75
+ if ( self::is_allowed_user() ) {
76
  if ( ! self::$post_modal_launched ) {
77
+ self::$post_modal_launched = true;
78
  $this->echo_upload_warning_modal();
79
  $this->echo_request_modal( 'post' );
80
  }
86
  /**
87
  * Writes a modal to the output buffer that tells the user how much it is going to cost.
88
  *
89
+ * @param string $item_id The workflow id.
90
+ * @param string $wp_locale
91
+ * @param string $item_type
92
  */
93
  public function echo_terms_modal( $item_id = null, $wp_locale = null, $item_type = null ) {
94
+ $this->add_item_id( $item_id, $wp_locale );
95
+ if ( self::is_allowed_user() ) {
 
96
  if ( ! self::$terms_modal_launched ) {
97
  self::$terms_modal_launched = true;
98
  $this->echo_upload_warning_modal();
105
  /**
106
  * Writes a modal to the output buffer that tells the user how much it is going to cost.
107
  *
108
+ * @param string $item_id The workflow id.
109
+ * @param string $wp_locale
110
+ * @param string $item_type
111
  */
112
  public function echo_strings_modal( $item_id = null, $wp_locale = null, $item_type = null ) {
113
+ $this->add_item_id( $item_id, $wp_locale );
114
+ if ( self::is_allowed_user() ) {
 
115
  if ( ! self::$strings_modal_launched ) {
116
  self::$strings_modal_launched = true;
117
  $this->echo_upload_warning_modal();
123
 
124
  /**
125
  * Writes a modal to the output buffer that tells the user if certain translations will
126
+ * be overwritten by a given action.
 
 
127
  */
128
  private function echo_upload_warning_modal() {
129
+ $id = $this->workflow_id . '-warning';
130
  $args = array(
131
  'header' => __( 'Confirm Document Upload', 'lingotek-translation' ),
132
+ 'body' =>
133
+ "
134
  <div id='warning-wrapper'>
135
  <div class='professional-upload-warning-header-container'>
136
  <span class='professional-upload-warning-header'>By uploading these changes, your professional translations may be lost.</span>
137
  </div>
138
+
139
  <div class='professional-upload-warning-body-container'>
140
  <span class='professional-upload-warning-body'>
141
  By editing this document and then re-uploading it to Lingotek any professional translations that you have not downloaded yet will be lost. Additionally, any professional translations that are in-progress for this document will be lost.
142
  </span>
143
  </div>
144
+
145
  <div class='professional-warning-checkbox-container'><input id='professional-warning-checkbox' type='checkbox' name='confirm-request' value='professional-warning-upload></div>
146
  <div class='professional-warning-checkbox-text-container'><span class='professional-warning-checkbox-text'> I understand that translations that have not been downloaded or that are in progress will be lost and money paid for that translation will be forfeited by re-uploading them to Lingotek.</span></div>
147
 
148
  <button type='button' id='cancel-warning-" . esc_attr( $id ) . "' class='professional-cancel-button float-bottom-right-next-to'>
149
  <span class='ADD-PAYMENT-LATER'>CANCEL</span>
150
  </button>
151
+ <div class='float-bottom-right' style='bottom:5%;'><img id='professional-warning-loading-spinner' style='display:none;' src='" . esc_url_raw( LINGOTEK_URL ) . "/img/loading_mini.gif' /></div>
152
  <button type='button' id='ok-warning-" . esc_attr( $id ) . "' class='professional-okay-warning-button-disabled float-bottom-right' disabled='true'>
153
  <span id='professional-warning-okay-text' class='ADD-PAYMENT-DISABLED'>PROCEED</span>
154
  </button>
155
 
156
+ </div>",
157
+ 'id' => $id,
158
  );
159
  $this->_echo_modal( $args );
160
  }
161
 
162
  /**
163
+ * Writes a modal to the output buffer that is launched when the user clicks on the 'request translation'
164
+ * option.
165
  *
166
+ * @param string $type
167
  */
168
  public function echo_request_modal( $type ) {
169
+ if ( self::is_allowed_user() ) {
 
170
  $this->load_request_scripts_and_styles( $type );
171
+ $id = $this->workflow_id . '-request';
172
  $args = array(
173
+ 'header' => __( 'Confirm Request Translation', 'lingotek-translation' ),
174
  'parent_elements' => "
175
  <img class='loading-element loading-translations-image' src='" . esc_url_raw( LINGOTEK_URL ) . "/img/translation-logo.png'/>
176
  <div class='loading-element loading-progress-bar-outer'>
179
  <span class='loading-element loading-progress-percent'>65%</span>
180
  <div class='loading-element Analyzing-translations'>Analyzing translations and gathering quotes...</div>
181
  ",
182
+ 'body' =>
183
+ "
184
+ <div id='wrapper'>
185
+ <div id='content'><br>
186
+ <div id='professional-table-content'>
187
+ <span class='Congratulations-You payment-method-setup'>You have elected to use our Professional Translation Services.<br><br></span>
188
+ <div class='You-can-now-connect payment-method-setup'>
189
+ You can now connect with audiences around the globe using Lingotek's network of 5000+ professional, in-country, translators. Professional Translation ensures that your audiences will feel the sentiment of your content.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
190
  </div>
191
+
192
+ <span class='Congratulations-You payment-not-setup'>Welcome to Lingotek's Translation Quote Calculator<br><br></span>
193
+ <div class='You-can-now-connect payment-not-setup'>
194
+ Using the quote calculator below you can get an idea of how much your translations will cost. You will need to add a payment method to the Lingotek Secure Payment Portal In order to purchase these translations.
 
 
 
 
 
195
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
196
  <br>
197
+ <div class='minimum-per-language-warning minimum-warning'>
198
+ <img src='" . esc_url_raw( LINGOTEK_URL ) . "/img/minimum-warning.svg' />
199
+ <span >*$59.99 minimum per language.</span>
200
+ <span ltk-data-tooltip='This minimum ensures that we can retain the best professional linguists for your translation job.'><img src='" . esc_url_raw( LINGOTEK_URL ) . "/img/minimum-help.svg' /></span>
201
  </div>
202
+ <br class='payment-not-setup'>
203
+ <span class='Translation-Request payment-not-setup'>Translation Quotes<br><br></span>
204
+ <br class='payment-method-setup'>
205
+ <span class='Translation-Request payment-method-setup'>Translation Request Summary<br><br></span>
206
+ <div id='table-wrapper'>
207
+ <table class='request-table'>
208
+ <tr class='bordered-bottom'><th style='display: table-cell;' class='table-header'>Title</th><th style='display: table-cell;' class='table-header' id='words-column'>Words</th><th style='text-align:center;'><a href='#' id='next-language-set'> <img id='next-language-image' src='" . esc_url_raw( LINGOTEK_URL ) . "/img/right-arrow.svg' /> </a> </th><th class='table-header table-total invisible'>Total</th></tr>
209
+ </table>
210
  </div>
211
+ </div>
212
+ <div id='professional-terms-and-conditions'>
213
+ <span class='terms-and-conditions-header'>Lingotek Terms and Conditions</span><br><br>
214
+ <div class='terms-and-conditions-content'>
215
+ <img id='terms-of-service-loading-ltk' src='" . esc_url_raw( LINGOTEK_URL ) . "/img/loading.gif'/>
 
216
  </div>
217
+ <button type='button' id='close-terms-and-conditions'>
218
+ <span class='CLOSE-TERMS-CONDITIONS'>CLOSE</span>
 
 
 
 
 
 
 
 
 
219
  </button>
220
  </div>
 
221
  </div>
222
+ <div id='sidebar'>
223
+ <span class='Payment-Method payment-method-setup'>Payment Method</span><br class='payment-method-setup'><br class='payment-method-setup'>
224
+ <span class='payment-method-setup credit-card-header'>Credit Card</span><br class='payment-method-setup'><br class='payment-method-setup'>
225
+ <div class='payment-method-setup professional-card-border'>
226
+ <div class='payment-method-setup blue-radio-button-div'><img id='blue-radio-button' class='payment-method-setup' src='" . esc_url_raw( LINGOTEK_URL ) . "/img/blue-radio-button.svg'/></div>
227
+ <div class='payment-method-setup credit-card-dots-div'><img id='credit-card-dots' class='payment-method-setup' src='" . esc_url_raw( LINGOTEK_URL ) . "/img/credit-dots.svg'/></div>
228
+ <div class='payment-method-setup last-four-digits-div'><span id='last-four-digits' class='payment-method-setup'>XXXX</span></div>
229
+ <div class='payment-method-setup credit-card-image-div'><img id='credit-card-image' class='payment-method-setup' src='" . Lingotek_Credit_Card_To_Path::get_cc_type_asset_url( Lingotek_Credit_Card_To_Path::get_default_cc_key() ) . "'/></div>
230
+ </div>
231
+ <br class='payment-method-setup'>
232
+ <br class='payment-method-setup'>
233
+
234
+
235
+ <span class='Payment-Method payment-not-setup'>Benefits of Professional Translation</span><br class='payment-not-setup'>
236
+ <ul class='translation-summary-list payment-not-setup'>
237
+ <li><span class='translation-summary-list-text'>Translations will be translated by professional in-country linguists.</span></li>
238
+ <li><span class='translation-summary-list-text'>Receive your translations in just a few days.</span></li>
239
+ <li><span class='translation-summary-list-text'>100% customer satisfaction guarantee.</span></li>
240
+ </ul>
241
+ <br class='payment-not-setup'>
242
+ <span class='Translation-Request-Right payment-method-setup'>Translation Request Summary</span>
243
+ <span class='Translation-Request-Right payment-not-setup'>Translation Quote Summary</span>
244
+ <ul class='translation-summary-list translation-summary-list-ltk'>
245
+
246
+ </ul>
247
+ <div class='minimum-disclaimer'>*Minimum charge $59.99 per language</div>
248
+ <br>
249
+ <div style='float:right;'>
250
+ <span class='request-total'>TOTAL: </span><span class='lingotek-total-amount'></span>
251
+ </div>
252
 
253
+ <div class='ltk-request-payment-disclaimer payment-method-setup'>
254
+ Note: By clicking the 'Buy Now' button your translations will be requested and you will be charged for the amount shown above.
255
+ </div>
256
+
257
+
258
+ <br class='payment-not-setup'><br class='payment-not-setup'><br class='payment-not-setup'>
259
+ <div class='disclaimer-request payment-not-setup'>
260
+ Note: By clicking the 'Add Payment Method' button you will be redirected to the Lingotek Secure Payment Portal.
261
+ Please note that none of the selections you have made in the table will be saved.
262
+ </div>
263
+ <br class='payment-method-setup'><br class='payment-method-setup'>
264
 
265
+ <div class='delivery-estimation'>Estimated delivery: <span class='business-days'>3 - 5 business days.</span><span ltk-data-tooltip='This is an estimate, not a guaranteed delivery time.'><img src='" . esc_url_raw( LINGOTEK_URL ) . "/img/minimum-help.svg' /></span></div>
266
+ <div class='request-checkbox payment-method-setup'><input id='accept-terms-and-conditions-input' type='checkbox' name='confirm-request' value='request-translation><span class='terms-conditions'> I agree to the <a id='terms-and-conditions-href' href='#'>Lingotek Terms and Conditions</a></span></div>
267
+ <br class='payment-method-setup'>
268
+
269
+ <button type='button' id='yes-" . esc_attr( $id ) . "-add-payment' class='professional-action-button float-center payment-not-setup' style='float:left'>
270
+ <span id='professional-add-payment' class='ADD-PAYMENT payment-not-setup'>ADD PAYMENT METHOD</span>
 
 
 
 
 
 
 
 
271
  </button>
272
+ <button type='button' id='yes-" . esc_attr( $id ) . "-buy-now' class='professional-action-button-disabled float-center payment-method-setup' style='float:left; bottom:-2%;' disabled='true'>
273
+ <span id='professional-buy-now' class='ADD-PAYMENT-DISABLED payment-method-setup'>BUY NOW</span>
 
 
 
 
 
 
 
 
 
274
  </button>
275
  </div>
276
+ <div id='cleared'></div>
277
+ </div>
278
+
279
+
280
+ <div id='requesting-translation-screen' class='requesting-element'>
281
+ <img class='requesting-element payment-portal-image' src='" . esc_url_raw( LINGOTEK_URL ) . "/img/translation-logo.png'/>
282
+ <img class='requesting-element payment-portal-loading' src='" . esc_url_raw( LINGOTEK_URL ) . "/img/loading.gif'/>
283
+ <div class='requesting-element Analyzing-translations'>Requesting Translations</div>
284
+ </div>
285
+
286
+ <div id='requesting-translation-success-screen' class='professional-translation-request-success-element'>
287
+ <img class='professional-translation-request-success-element payment-portal-image' src='" . esc_url_raw( LINGOTEK_URL ) . "/img/translation-logo.png'/>
288
+ <img class='professional-translation-request-success-element green-check-success' src='" . esc_url_raw( LINGOTEK_URL ) . "/img/checkmark-green.svg'/>
289
+ <div class='professional-translation-request-success-element professional-translation-view-invoice' style='height: 28px;'>Your translations have been successfully requested.</div>
290
+ <div class='professional-translation-request-success-element professional-translation-view-invoice'>You will be receiving a confirmation email shortly.</div>
291
+ <div class='professional-translation-request-success-element professional-translation-view-invoice'>Your credit card will be charged <span id='professional-translation-cost-success' class='professional-translation-request-success-element'></span></div>
292
+ <button type='button' id='professional-post-transaction-button' class='professional-translation-request-success-element professional-view-invoice-btn float-center'>
293
+ <span id='professional-post-transaction' class='ADD-PAYMENT professional-translation-request-success-element'>OK</span>
294
+ </button>
295
+ </div>
296
+
297
+
298
+
299
+ <div id='requesting-translation-error-screen' class='professional-translation-request-error-element'>
300
+ <img class='professional-translation-request-error-element payment-portal-image' src='" . esc_url_raw( LINGOTEK_URL ) . "/img/translation-logo.png'/>
301
+ <img class='professional-translation-request-error-element green-check-success' src='" . esc_url_raw( LINGOTEK_URL ) . "/img/error.svg'/>
302
+ <div id='error-requesting-translation-ltk' class='professional-translation-request-error-element professional-translation-view-invoice'>There was an error requesting your translation.</div>
303
+ <div id='error-requesting-translation-ltk-2' class='professional-translation-request-error-element professional-translation-view-invoice'>Please refresh the page and try again.</div>
304
+ <button type='button' id='professional-post-transaction-button' class='professional-translation-request-error-element professional-view-invoice-btn float-center'>
305
+ <span id='professional-post-transaction-failure' class='ADD-PAYMENT professional-translation-request-error-element'>Ok</span>
306
+ </button>
307
+ </div>
308
+
309
+ </div>
310
+ " . $this->get_payment_portal_html() . '
311
+
312
+ ',
313
+ 'id' => $id,
314
  );
315
  $this->_echo_modal( $args );
316
+ }//end if
317
  }
318
 
319
  /**
320
+ * This method will be used to roll out the Professional Translation workflow to a select number of users.
321
+ * The method will be called before anything is sent to the client.
322
+ */
323
+ public static function is_allowed_user() {
 
324
  return true;
325
  }
326
 
333
  private static $pre_uploaded = array();
334
 
335
  /**
336
+ * We disassociate the document before uploading to avoid automatic requesting of translations.
337
  *
338
+ * @param string $item_id The workflow id.
339
  * @param string $type
340
  * @return void
341
  */
342
+ public function pre_upload_to_lingotek( $item_id, $type ) {
343
+ $lgtm = new Lingotek_Model();
344
+ $document = $lgtm->get_group( $type, $item_id );
345
+ if ( $document ) {
346
+ if ( isset( self::$pre_uploaded[ $document->document_id ] ) ) {
347
+ return; }
348
+ self::$pre_uploaded[ $document->document_id ] = true;
349
  $document->delete();
350
  }
351
  }
360
  * @return void
361
  */
362
  public function save_post_hook() {
363
+ if ( ! self::$save_post_hook_executed ) {
364
  self::$save_post_hook_executed = true;
365
+ $post_vars = filter_input_array( INPUT_POST );
366
+
367
+ if ( 'inline-save' === $post_vars['action'] ) {
368
  echo '<script>location.reload();</script>';
369
  }
370
  }
379
  * @return void
380
  */
381
  public function save_term_hook() {
382
+ if ( ! self::$save_terms_hook_executed ) {
383
  self::$save_terms_hook_executed = true;
384
+ $post_vars = filter_input_array( INPUT_POST );
385
+
386
+ if ( 'inline-save-tax' === $post_vars['action'] ) {
387
  echo '<script>location.reload();</script>';
388
  }
389
  }
394
  *
395
  * @return boolean
396
  */
397
+ public function has_custom_request_procedure() {
398
+ return true; }
399
 
400
  /**
401
  * We don't want documents being uploaded automatically because of the chance
402
  * that a user may lose translations that they have paid for if they haven't finished or downloaded.
403
  *
404
+ * @return bool
405
  */
406
+ public function auto_upload_allowed() {
407
+ return false;
408
+ }
409
 
410
 
411
+ public function get_custom_in_progress_icon() {
412
+ return '<div title="Professional translation in progress" class="lingotek-professional-icon"><img src="' . LINGOTEK_URL . '/img/human-translation.svg" /></div>';
413
  }
414
 
415
  /**
418
  * @param string $type
419
  * @return void
420
  */
421
+ private function load_request_scripts_and_styles( $type ) {
 
422
  add_thickbox();
423
+ wp_enqueue_script( 'lingotek_professional_workflow', LINGOTEK_URL . '/js/workflow/professional-workflow.js', array(), LINGOTEK_VERSION, false );
424
  wp_enqueue_style( 'lingotek_professional_workflow_style', LINGOTEK_URL . '/css/workflow/professional-workflow-style.css', array(), LINGOTEK_VERSION );
425
 
426
  $client = new Lingotek_API();
427
 
428
  $language_mappings = $client->get_language_mappings();
429
+ $locales_list = PLL()->model->get_languages_list();
430
 
431
  $enabled_langs = array();
432
+ foreach ( $locales_list as $locale ) {
433
+ $lingotek_gmc_locale = str_replace( '-', '_', $locale->lingotek_locale );
434
+ $enabled_langs[ $locale->locale ] = array(
 
435
  'lingotek_locale' => $locale->lingotek_locale,
436
+ 'language' => isset( $language_mappings[ $lingotek_gmc_locale ] )
437
+ ? $language_mappings[ $lingotek_gmc_locale ]['language_name']
438
  : null,
439
+ 'country_name' => isset( $language_mappings[ $lingotek_gmc_locale ] )
440
+ ? $language_mappings[ $lingotek_gmc_locale ]['country_name']
441
  : null,
442
  );
443
  }
444
+
445
  $vars = array(
446
+ 'workflow_id' => $this->workflow_id,
447
+ 'icon_url' => LINGOTEK_URL . '/img/lingotek-logo-white.png',
448
+ 'question_mark_icon_url' => LINGOTEK_URL . '/img/questionmark.svg',
449
  'bridge_payment_redirect' => BRIDGE_URL . '/#/payment/portal',
450
+ 'enabled_langs' => $enabled_langs,
451
+ 'curr_item_type' => $type,
452
+ 'cc_type_map' => Lingotek_Credit_Card_To_Path::get_cc_map(),
453
+ 'default_cc_type' => Lingotek_Credit_Card_To_Path::get_default_cc_key(),
454
+ 'nonce' => wp_create_nonce( 'lingotek_professional' ),
455
  );
456
  wp_localize_script( 'lingotek_professional_workflow', 'workflow_vars', $vars );
457
  }
458
 
459
 
460
  /**
461
+ * As the table is being built (for posts, pages, terms, etc.) we only want to attach listeners to locales that have the professional
462
  * workflow enabled. This list is build as the table is being rendered.
463
  *
464
  * @param string $item_id
465
  * @param string $wp_locale
466
  * @return void
467
  */
 
468
  private function add_item_id( $item_id, $wp_locale ) {
469
+ self::$item_id_list[ $item_id ][] = $wp_locale;
470
  }
471
 
472
  /**
473
+ * Because a new workflow object is created every time a new locale is rendered on the table we can't preserve the list in a single object.
474
  * Instead, we store that list statically and update the list that will eventually be sent to the front end everytime a workflow object is destroyed.
475
  *
476
  * @return void
477
  */
478
+ private function flush_list() {
 
479
  $vars = array(
480
  'ids' => self::$item_id_list,
481
  );
485
  /**
486
  * Returns the HTML that displays the payment portal loading screen.
487
  *
488
+ * @return string
489
  */
490
+ private function get_payment_portal_html() {
 
491
  return "
492
  <div id='payment-portal-wrapper' class='payment-portal-element'>
493
+ <img class='payment-portal-element payment-portal-image' src='" . esc_url_raw( LINGOTEK_URL ) . "/img/translation-logo.png'/>
494
+ <img class='payment-portal-element payment-portal-loading' src='" . esc_url_raw( LINGOTEK_URL ) . "/img/loading.gif'/>
495
  <span class='payment-portal-element You-are-now-being-re'>You are now being redirected to the Lingotek Secure Payment Portal...</span>
496
  </div>
497
  ";
admin/workflows/workflow-factory.php CHANGED
@@ -26,7 +26,8 @@ class Lingotek_Workflow_Factory {
26
  * @var array
27
  */
28
  private static $map = array(
29
- 'ltk-professional-translation' => 'Lingotek_Professional_Translation_Workflow', // prod.
 
30
  );
31
 
32
  /**
@@ -36,12 +37,9 @@ class Lingotek_Workflow_Factory {
36
  * @param string $workflow_id the Id of the given workflow.
37
  */
38
  public static function get_workflow_instance( $workflow_id ) {
39
- if ( ! isset( self::$map[ $workflow_id ] ) )
40
- {
41
  return new Lingotek_Workflow();
42
- }
43
- else
44
- {
45
  self::class_load( self::$map[ $workflow_id ] );
46
  return new self::$map[ $workflow_id ]( $workflow_id );
47
  }
@@ -50,11 +48,11 @@ class Lingotek_Workflow_Factory {
50
  /**
51
  * Echos the information modals describing various details about the workflow.
52
  */
53
- public static function echo_info_modals() {
54
  add_thickbox();
55
  foreach ( self::$map as $id => $class ) {
56
  $workflow = new $class( $id );
57
- $workflow->echo_info_modal();
58
  }
59
  }
60
 
@@ -64,7 +62,9 @@ class Lingotek_Workflow_Factory {
64
  * @param string $class class name to be loaded.
65
  */
66
  private static function class_load( $class ) {
67
- if ( ! isset( $class ) ) { return; }
68
- if ( ! class_exists( $class ) ) { require_once( LINGOTEK_WORKFLOWS . '/' . Lingotek::convert_class_to_file( $class ) . '.php' ); }
 
 
69
  }
70
  }
26
  * @var array
27
  */
28
  private static $map = array(
29
+ // Prod.
30
+ 'ltk-professional-translation' => 'Lingotek_Professional_Translation_Workflow',
31
  );
32
 
33
  /**
37
  * @param string $workflow_id the Id of the given workflow.
38
  */
39
  public static function get_workflow_instance( $workflow_id ) {
40
+ if ( ! isset( self::$map[ $workflow_id ] ) ) {
 
41
  return new Lingotek_Workflow();
42
+ } else {
 
 
43
  self::class_load( self::$map[ $workflow_id ] );
44
  return new self::$map[ $workflow_id ]( $workflow_id );
45
  }
48
  /**
49
  * Echos the information modals describing various details about the workflow.
50
  */
51
+ public static function lingotek_translation_professional_translation_info_modals() {
52
  add_thickbox();
53
  foreach ( self::$map as $id => $class ) {
54
  $workflow = new $class( $id );
55
+ $workflow->lingotek_translation_professional_translation_info_modal();
56
  }
57
  }
58
 
62
  * @param string $class class name to be loaded.
63
  */
64
  private static function class_load( $class ) {
65
+ if ( ! isset( $class ) ) {
66
+ return; }
67
+ if ( ! class_exists( $class ) ) {
68
+ require_once LINGOTEK_WORKFLOWS . '/' . Lingotek::convert_class_to_file( $class ) . '.php'; }
69
  }
70
  }
admin/workflows/workflow.php CHANGED
@@ -6,83 +6,83 @@
6
  class Lingotek_Workflow {
7
 
8
  private $allowed_html = array(
9
- 'div' => array(
10
- 'id' => array(),
11
- 'style' => array(),
12
- 'class' => array(),
13
  ),
14
- 'hr' => array(
15
  'width' => array(),
16
- 'size' => array(),
17
  ),
18
- 'h2' => array(
19
  'style' => array(),
20
  ),
21
- 'br' => array(
22
  'class' => array(),
23
  ),
24
- 'b' => array(),
25
- 'p' => array(
26
- 'id' => array(),
27
  'style' => array(),
28
  ),
29
- 'a' => array(
30
- 'id' => array(),
31
- 'href' => array(),
32
  'style' => array(),
33
- 'class' => array()
34
  ),
35
- 'img' => array(
36
- 'id' => array(),
37
- 'src' => array(),
38
  'style' => array(),
39
  'class' => array(),
40
  ),
41
- 'span' => array(
42
- 'id' => array(),
43
- 'style' => array(),
44
- 'class' => array(),
45
- 'ltk-data-tooltip' => array()
46
  ),
47
  'button' => array(
48
- 'type' => array(),
49
- 'style' => array(),
50
- 'class' => array(),
51
- 'id' => array(),
52
  'disabled' => array(),
53
  ),
54
- 'table' => array(
55
  'class' => array(),
56
  ),
57
- 'tbody' => array(
58
- 'class' => array()
59
  ),
60
- 'thead' => array(
61
  'class' => array(),
62
- 'id' => array(),
63
  ),
64
- 'tr' => array(
65
  'class' => array(),
66
- 'id' => array(),
67
- ),
68
- 'th' => array(
69
- 'id' => array(),
70
  'class' => array(),
71
  'style' => array(),
72
  ),
73
- 'td' => array(
74
- 'class' => array()
75
  ),
76
- 'ul' => array(
77
- 'class' => array()
78
  ),
79
- 'li' => array(),
80
- 'input' => array(
81
- 'id' => array(),
82
- 'type' => array(),
83
- 'name' => array(),
84
  'value' => array(),
85
- 'class' => array()
86
  ),
87
  );
88
 
@@ -128,8 +128,8 @@ class Lingotek_Workflow {
128
  protected static $loading_modal_launched = false;
129
 
130
  /**
131
- * This flag can be set to keep track of whether
132
- * the save post action has already occured (for example, if multiple workflow objects are being instantiated and
133
  * you don't want them to do the same thing twice.)
134
  *
135
  * @var boolean
@@ -155,7 +155,7 @@ class Lingotek_Workflow {
155
  *
156
  * @param string $workflow_id
157
  */
158
- public function __construct($workflow_id = null) {
159
  $this->workflow_id = $workflow_id;
160
  }
161
 
@@ -168,7 +168,7 @@ class Lingotek_Workflow {
168
  *
169
  * @param string $id the workflow id.
170
  */
171
- public function echo_info_modal( $item_id = null, $item_type = null ) {}
172
 
173
  /**
174
  * This method is called when the Posts or Pages columns are being rendered.
@@ -183,8 +183,8 @@ class Lingotek_Workflow {
183
  * This method is called when the Terms table is being rendered.
184
  *
185
  * @param string $item_id
186
- * @param string $wp_locale
187
- * @param string $item_type
188
  */
189
  public function echo_terms_modal( $item_id = null, $wp_locale = null, $item_type = null ) {}
190
 
@@ -209,11 +209,11 @@ class Lingotek_Workflow {
209
  * @param string $type
210
  * @return void
211
  */
212
- public function pre_upload_to_lingotek($item_id, $type) {}
213
 
214
  /**
215
  * Workflows have the option to hook into the save post action. This action is executed
216
- * BEFORE a document is uploaded to TMS or changed. NOTE: The document may not be uploaded or saved. This
217
  * method is called when the save post action is triggered.
218
  *
219
  * @return void
@@ -222,7 +222,7 @@ class Lingotek_Workflow {
222
 
223
  /**
224
  * Workflows have the option to hook into the save term action. This action is executed
225
- * BEFORE a document is uploaded to TMS or changed. NOTE: The document may not be uploaded or saved. This
226
  * method is called when the save post action is triggered.
227
  *
228
  * @return void
@@ -235,11 +235,12 @@ class Lingotek_Workflow {
235
  *
236
  * @return boolean
237
  */
238
- public function has_custom_request_procedure() { return false; }
 
239
 
240
  /**
241
  * If a workflow wants to perform a custom request this method will be called after the has_custom_request_procedure() has
242
- * been called if it returns TRUE. As of now this method (do_custom_request()) only gets called for single requests.
243
  * bulk requests are ignored if any of the locale items are linked to a workflow that returns true on has_custom_request_procedure().
244
  *
245
  * @return void
@@ -251,10 +252,12 @@ class Lingotek_Workflow {
251
  *
252
  * @return void
253
  */
254
- public function auto_upload_allowed() { return true; }
 
255
 
256
 
257
- public function get_custom_in_progress_icon() { return false; }
 
258
  /**
259
  * This method acts as a template for building the modals. The arguments passed
260
  * are inserted into the html string and then echo'd. If any extra html elements
@@ -268,26 +271,27 @@ class Lingotek_Workflow {
268
  * This allows us to use the 'display' CSS attribute. WP
269
  * blacklists it by default.
270
  */
271
- add_filter( 'safe_style_css', array(&$this, 'add_modal_styles'));
272
 
273
- $id = isset( $args['id'] ) ? '-' . $args['id'] : '';
274
  $parent_elements = isset( $args['parent_elements'] ) ? $args['parent_elements'] : '';
275
- echo wp_kses( "<div id='modal-window-id" . esc_attr( $id ) . "' style='display:none;' >"
276
- . wp_kses( $parent_elements, $this->allowed_html ) .
277
- "<div id='modal-body" . esc_attr( $id ) . "' style='height:100%;position: relative;'>" . wp_kses( $args['body'], $this->allowed_html ) . "</div>" .
 
278
  // <br>
279
- // <a id='yes" . esc_attr( $id ) . "' class='lingotek-color dashicons' href='#' style='position:absolute; float:left; bottom:30px;'>Continue</a>
280
  // <div style='float:right; padding-right:55px;'>
281
- // <a id='no" . esc_attr( $id ) . "' class='lingotek-color dashicons' href='#' style='position:absolute; float:right; bottom:30px;'>Cancel</a>
282
- "</div>
283
- </div>", $this->allowed_html);
 
 
284
  }
285
 
286
 
287
- public function add_modal_styles()
288
- {
289
-
290
- $styles = array();
291
  $styles[] = 'display';
292
  $styles[] = 'position';
293
  $styles[] = 'bottom';
6
  class Lingotek_Workflow {
7
 
8
  private $allowed_html = array(
9
+ 'div' => array(
10
+ 'id' => array(),
11
+ 'style' => array(),
12
+ 'class' => array(),
13
  ),
14
+ 'hr' => array(
15
  'width' => array(),
16
+ 'size' => array(),
17
  ),
18
+ 'h2' => array(
19
  'style' => array(),
20
  ),
21
+ 'br' => array(
22
  'class' => array(),
23
  ),
24
+ 'b' => array(),
25
+ 'p' => array(
26
+ 'id' => array(),
27
  'style' => array(),
28
  ),
29
+ 'a' => array(
30
+ 'id' => array(),
31
+ 'href' => array(),
32
  'style' => array(),
33
+ 'class' => array(),
34
  ),
35
+ 'img' => array(
36
+ 'id' => array(),
37
+ 'src' => array(),
38
  'style' => array(),
39
  'class' => array(),
40
  ),
41
+ 'span' => array(
42
+ 'id' => array(),
43
+ 'style' => array(),
44
+ 'class' => array(),
45
+ 'ltk-data-tooltip' => array(),
46
  ),
47
  'button' => array(
48
+ 'type' => array(),
49
+ 'style' => array(),
50
+ 'class' => array(),
51
+ 'id' => array(),
52
  'disabled' => array(),
53
  ),
54
+ 'table' => array(
55
  'class' => array(),
56
  ),
57
+ 'tbody' => array(
58
+ 'class' => array(),
59
  ),
60
+ 'thead' => array(
61
  'class' => array(),
62
+ 'id' => array(),
63
  ),
64
+ 'tr' => array(
65
  'class' => array(),
66
+ 'id' => array(),
67
+ ),
68
+ 'th' => array(
69
+ 'id' => array(),
70
  'class' => array(),
71
  'style' => array(),
72
  ),
73
+ 'td' => array(
74
+ 'class' => array(),
75
  ),
76
+ 'ul' => array(
77
+ 'class' => array(),
78
  ),
79
+ 'li' => array(),
80
+ 'input' => array(
81
+ 'id' => array(),
82
+ 'type' => array(),
83
+ 'name' => array(),
84
  'value' => array(),
85
+ 'class' => array(),
86
  ),
87
  );
88
 
128
  protected static $loading_modal_launched = false;
129
 
130
  /**
131
+ * This flag can be set to keep track of whether
132
+ * the save post action has already occured (for example, if multiple workflow objects are being instantiated and
133
  * you don't want them to do the same thing twice.)
134
  *
135
  * @var boolean
155
  *
156
  * @param string $workflow_id
157
  */
158
+ public function __construct( $workflow_id = null ) {
159
  $this->workflow_id = $workflow_id;
160
  }
161
 
168
  *
169
  * @param string $id the workflow id.
170
  */
171
+ public function lingotek_translation_professional_translation_info_modal( $item_id = null, $item_type = null ) {}
172
 
173
  /**
174
  * This method is called when the Posts or Pages columns are being rendered.
183
  * This method is called when the Terms table is being rendered.
184
  *
185
  * @param string $item_id
186
+ * @param string $wp_locale
187
+ * @param string $item_type
188
  */
189
  public function echo_terms_modal( $item_id = null, $wp_locale = null, $item_type = null ) {}
190
 
209
  * @param string $type
210
  * @return void
211
  */
212
+ public function pre_upload_to_lingotek( $item_id, $type ) {}
213
 
214
  /**
215
  * Workflows have the option to hook into the save post action. This action is executed
216
+ * BEFORE a document is uploaded to TMS or changed. NOTE: The document may not be uploaded or saved. This
217
  * method is called when the save post action is triggered.
218
  *
219
  * @return void
222
 
223
  /**
224
  * Workflows have the option to hook into the save term action. This action is executed
225
+ * BEFORE a document is uploaded to TMS or changed. NOTE: The document may not be uploaded or saved. This
226
  * method is called when the save post action is triggered.
227
  *
228
  * @return void
235
  *
236
  * @return boolean
237
  */
238
+ public function has_custom_request_procedure() {
239
+ return false; }
240
 
241
  /**
242
  * If a workflow wants to perform a custom request this method will be called after the has_custom_request_procedure() has
243
+ * been called if it returns TRUE. As of now this method (do_custom_request()) only gets called for single requests.
244
  * bulk requests are ignored if any of the locale items are linked to a workflow that returns true on has_custom_request_procedure().
245
  *
246
  * @return void
252
  *
253
  * @return void
254
  */
255
+ public function auto_upload_allowed() {
256
+ return true; }
257
 
258
 
259
+ public function get_custom_in_progress_icon() {
260
+ return false; }
261
  /**
262
  * This method acts as a template for building the modals. The arguments passed
263
  * are inserted into the html string and then echo'd. If any extra html elements
271
  * This allows us to use the 'display' CSS attribute. WP
272
  * blacklists it by default.
273
  */
274
+ add_filter( 'safe_style_css', array( &$this, 'add_modal_styles' ) );
275
 
276
+ $id = isset( $args['id'] ) ? '-' . $args['id'] : '';
277
  $parent_elements = isset( $args['parent_elements'] ) ? $args['parent_elements'] : '';
278
+ echo wp_kses(
279
+ "<div id='modal-window-id" . esc_attr( $id ) . "' style='display:none;' >"
280
+ . wp_kses( $parent_elements, $this->allowed_html ) .
281
+ "<div id='modal-body" . esc_attr( $id ) . "' style='height:100%;position: relative;'>" . wp_kses( $args['body'], $this->allowed_html ) . '</div>' .
282
  // <br>
283
+ // <a id='yes" . esc_attr( $id ) . "' class='lingotek-color dashicons' href='#' style='position:absolute; float:left; bottom:30px;'>Continue</a>
284
  // <div style='float:right; padding-right:55px;'>
285
+ // <a id='no" . esc_attr( $id ) . "' class='lingotek-color dashicons' href='#' style='position:absolute; float:right; bottom:30px;'>Cancel</a>
286
+ '</div>
287
+ </div>',
288
+ $this->allowed_html
289
+ );
290
  }
291
 
292
 
293
+ public function add_modal_styles() {
294
+ $styles = array();
 
 
295
  $styles[] = 'display';
296
  $styles[] = 'position';
297
  $styles[] = 'bottom';
admin/wp-import.php CHANGED
@@ -13,12 +13,12 @@ class Lingotek_WP_Import extends PLL_WP_Import {
13
  * @since 1.0.6
14
  */
15
  public function process_posts() {
16
- if (empty($this->post_translations)) {
17
- foreach ($this->posts as &$post) {
18
- foreach ($post['terms'] as $key => &$term) {
19
- if (!empty($post['terms'])) {
20
- if (in_array('post_translations', $term)) {
21
- unset($post['terms'][$key]);
22
  }
23
  }
24
  }
@@ -28,4 +28,4 @@ class Lingotek_WP_Import extends PLL_WP_Import {
28
  }
29
  }
30
 
31
- ?>
13
  * @since 1.0.6
14
  */
15
  public function process_posts() {
16
+ if ( empty( $this->post_translations ) ) {
17
+ foreach ( $this->posts as &$post ) {
18
+ foreach ( $post['terms'] as $key => &$term ) {
19
+ if ( ! empty( $post['terms'] ) ) {
20
+ if ( in_array( 'post_translations', $term, true ) ) {
21
+ unset( $post['terms'][ $key ] );
22
  }
23
  }
24
  }
28
  }
29
  }
30
 
31
+
bin/githook-pre-commit.sh ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+
3
+ PROJECT=`git rev-parse --show-toplevel`
4
+ STAGED_FILES_CMD=`git diff --cached --name-only --diff-filter=ACMR HEAD | grep \\\\.php`
5
+ # This is valid for roots/bedrock, not for standard WordPress.
6
+ DOCKER_BASE_PATH='/var/www/html/web/app/plugins/lingotek-translation/'
7
+
8
+ # Determine if a file list is passed
9
+ if [ "$#" -eq 1 ]
10
+ then
11
+ SFILES = "$*"
12
+ fi
13
+ SFILES=${SFILES:-$STAGED_FILES_CMD}
14
+
15
+ echo "Checking PHP Lint..."
16
+ for FILE in $SFILES
17
+ do
18
+ ddev exec bash -c "php -l -d display_errors=0 $DOCKER_BASE_PATH/$FILE"
19
+ if [ $? != 0 ]
20
+ then
21
+ echo "Fix the error before commit."
22
+ exit 1
23
+ fi
24
+ FILES="$FILES $PROJECT/$FILE"
25
+ done
26
+
27
+ if [ "$FILES" != "" ]
28
+ then
29
+ echo "Running Code Sniffer..."
30
+ phpcs --standard=phpcs.xml --encoding=utf-8 $FILES
31
+ if [ $? != 0 ]
32
+ then
33
+ echo 'We are allowing the commit, but take into account the warnings above.'
34
+ #echo "Fix the error before commit."
35
+ #exit 1
36
+ fi
37
+ fi
bin/githook-prepare-commit-msg.sh ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+
3
+ # Get git repository information
4
+ commit_msg_file=$1
5
+ commit_type=$2
6
+ commit_branch=`git symbolic-ref --short HEAD`
7
+ raw_ticket_num=`echo $commit_branch | grep -oh -E '^[a-zA-Z]+-{0,1}[0-9]+'`
8
+ ticket_num=`echo $raw_ticket_num | sed -E 's,^([a-zA-Z]+)([0-9]+).*,\1-\2,1'`
9
+
10
+ if [ "${commit_type}" = "merge" ];then
11
+ exit 0
12
+ fi
13
+ # Check if branch begins with a valid ticket number
14
+ if [ -z "$ticket_num" ];
15
+ then
16
+ read -p \
17
+ "Please enter the ticket number in the format XX-####: " \
18
+ ticket_num </dev/tty
19
+ fi
20
+
21
+ VALID_TICKET=`echo $ticket_num | grep -oh -E '^[a-zA-Z]+-[0-9]+'`
22
+
23
+ # Check user-entered value or previously captured ticket number to make sure it conforms
24
+ if [ -z "$VALID_TICKET" ];
25
+ then
26
+ echo 'Invalid ticket number. Please try to commit again'
27
+ exit 1
28
+ fi
29
+
30
+ # Create commit message
31
+ issue_string="Issue #$ticket_num:"
32
+ # Keep all newlines in captured commit message
33
+ IFS=
34
+ raw_commit_msg="$(cat $commit_msg_file)"
35
+ commit_msg="$issue_string $raw_commit_msg"
36
+ echo $commit_msg > $commit_msg_file
37
+
38
+ if [ "$commit_type" = "message" ];
39
+ then
40
+ commit_msg="$issue_string $raw_commit_msg"
41
+ else
42
+ commit_msg=`echo -e "$issue_string\n\n$raw_commit_msg"`
43
+ fi
44
+
45
+ # Store new commit message
46
+ echo $commit_msg > $commit_msg_file
bin/install-git-hooks.sh ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+
3
+ # Switch to git root directory
4
+ git_root=`git rev-parse --show-toplevel`
5
+ cd $git_root
6
+
7
+ # Add hook if necessary
8
+ if [ ! -f .git/hooks/prepare-commit-msg ];
9
+ then
10
+ echo 'Adding commit message hook.'
11
+ cp ./bin/githook-prepare-commit-msg.sh .git/hooks/prepare-commit-msg \
12
+ && echo '***Commit message hook added successfully.***'
13
+ else
14
+ echo 'Commit message hook already in place. Not overwriting.'
15
+ fi
16
+
17
+ if [ ! -f .git/hooks/pre-commit ];
18
+ then
19
+ echo 'Adding pre-comit hook.'
20
+ cp ./bin/githook-pre-commit.sh .git/hooks/pre-commit \
21
+ && echo '***Pre-commit hook added successfully.***'
22
+ else
23
+ echo 'Pre-commit hook already in place. Not overwriting.'
24
+ fi
25
+
bin/install-wp-tests.sh ADDED
@@ -0,0 +1,181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+
3
+ if [ $# -lt 3 ]; then
4
+ echo "usage: $0 <db-name> <db-user> <db-pass> [db-host] [wp-version] [skip-database-creation]"
5
+ exit 1
6
+ fi
7
+
8
+ DB_NAME=$1
9
+ DB_USER=$2
10
+ DB_PASS=$3
11
+ DB_HOST=${4-localhost}
12
+ WP_VERSION=${5-latest}
13
+ SKIP_DB_CREATE=${6-false}
14
+
15
+ TMPDIR=${TMPDIR-/tmp}
16
+ TMPDIR=$(echo $TMPDIR | sed -e "s/\/$//")
17
+ WP_TESTS_DIR=${WP_TESTS_DIR-$TMPDIR/wordpress-tests-lib}
18
+ WP_CORE_DIR=${WP_CORE_DIR-$TMPDIR/wordpress}
19
+
20
+ download() {
21
+ if [ `which curl` ]; then
22
+ curl -s "$1" > "$2";
23
+ elif [ `which wget` ]; then
24
+ wget -nv -O "$2" "$1"
25
+ fi
26
+ }
27
+
28
+ if [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+\-(beta|RC)[0-9]+$ ]]; then
29
+ WP_BRANCH=${WP_VERSION%\-*}
30
+ WP_TESTS_TAG="branches/$WP_BRANCH"
31
+
32
+ elif [[ $WP_VERSION =~ ^[0-9]+\.[0-9]+$ ]]; then
33
+ WP_TESTS_TAG="branches/$WP_VERSION"
34
+ elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0-9]+ ]]; then
35
+ if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then
36
+ # version x.x.0 means the first release of the major version, so strip off the .0 and download version x.x
37
+ WP_TESTS_TAG="tags/${WP_VERSION%??}"
38
+ else
39
+ WP_TESTS_TAG="tags/$WP_VERSION"
40
+ fi
41
+ elif [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
42
+ WP_TESTS_TAG="trunk"
43
+ else
44
+ # http serves a single offer, whereas https serves multiple. we only want one
45
+ download http://api.wordpress.org/core/version-check/1.7/ /tmp/wp-latest.json
46
+ grep '[0-9]+\.[0-9]+(\.[0-9]+)?' /tmp/wp-latest.json
47
+ LATEST_VERSION=$(grep -o '"version":"[^"]*' /tmp/wp-latest.json | sed 's/"version":"//')
48
+ if [[ -z "$LATEST_VERSION" ]]; then
49
+ echo "Latest WordPress version could not be found"
50
+ exit 1
51
+ fi
52
+ WP_TESTS_TAG="tags/$LATEST_VERSION"
53
+ fi
54
+ set -ex
55
+
56
+ install_wp() {
57
+
58
+ if [ -d $WP_CORE_DIR ]; then
59
+ return;
60
+ fi
61
+
62
+ mkdir -p $WP_CORE_DIR
63
+
64
+ if [[ $WP_VERSION == 'nightly' || $WP_VERSION == 'trunk' ]]; then
65
+ mkdir -p $TMPDIR/wordpress-trunk
66
+ rm -rf $TMPDIR/wordpress-trunk/*
67
+ svn export --quiet https://core.svn.wordpress.org/trunk $TMPDIR/wordpress-trunk/wordpress
68
+ mv $TMPDIR/wordpress-trunk/wordpress/* $WP_CORE_DIR
69
+ else
70
+ if [ $WP_VERSION == 'latest' ]; then
71
+ local ARCHIVE_NAME='latest'
72
+ elif [[ $WP_VERSION =~ [0-9]+\.[0-9]+ ]]; then
73
+ # https serves multiple offers, whereas http serves single.
74
+ download https://api.wordpress.org/core/version-check/1.7/ $TMPDIR/wp-latest.json
75
+ if [[ $WP_VERSION =~ [0-9]+\.[0-9]+\.[0] ]]; then
76
+ # version x.x.0 means the first release of the major version, so strip off the .0 and download version x.x
77
+ LATEST_VERSION=${WP_VERSION%??}
78
+ else
79
+ # otherwise, scan the releases and get the most up to date minor version of the major release
80
+ local VERSION_ESCAPED=`echo $WP_VERSION | sed 's/\./\\\\./g'`
81
+ LATEST_VERSION=$(grep -o '"version":"'$VERSION_ESCAPED'[^"]*' $TMPDIR/wp-latest.json | sed 's/"version":"//' | head -1)
82
+ fi
83
+ if [[ -z "$LATEST_VERSION" ]]; then
84
+ local ARCHIVE_NAME="wordpress-$WP_VERSION"
85
+ else
86
+ local ARCHIVE_NAME="wordpress-$LATEST_VERSION"
87
+ fi
88
+ else
89
+ local ARCHIVE_NAME="wordpress-$WP_VERSION"
90
+ fi
91
+ download https://wordpress.org/${ARCHIVE_NAME}.tar.gz $TMPDIR/wordpress.tar.gz
92
+ tar --strip-components=1 -zxmf $TMPDIR/wordpress.tar.gz -C $WP_CORE_DIR
93
+ fi
94
+
95
+ download https://raw.github.com/markoheijnen/wp-mysqli/master/db.php $WP_CORE_DIR/wp-content/db.php
96
+ }
97
+
98
+ install_test_suite() {
99
+ # portable in-place argument for both GNU sed and Mac OSX sed
100
+ if [[ $(uname -s) == 'Darwin' ]]; then
101
+ local ioption='-i.bak'
102
+ else
103
+ local ioption='-i'
104
+ fi
105
+
106
+ # set up testing suite if it doesn't yet exist
107
+ if [ ! -d $WP_TESTS_DIR ]; then
108
+ # set up testing suite
109
+ mkdir -p $WP_TESTS_DIR
110
+ rm -rf $WP_TESTS_DIR/{includes,data}
111
+ svn export --quiet --ignore-externals https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/includes/ $WP_TESTS_DIR/includes
112
+ svn export --quiet --ignore-externals https://develop.svn.wordpress.org/${WP_TESTS_TAG}/tests/phpunit/data/ $WP_TESTS_DIR/data
113
+ fi
114
+
115
+ if [ ! -f wp-tests-config.php ]; then
116
+ download https://develop.svn.wordpress.org/${WP_TESTS_TAG}/wp-tests-config-sample.php "$WP_TESTS_DIR"/wp-tests-config.php
117
+ # remove all forward slashes in the end
118
+ WP_CORE_DIR=$(echo $WP_CORE_DIR | sed "s:/\+$::")
119
+ sed $ioption "s:dirname( __FILE__ ) . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php
120
+ sed $ioption "s:__DIR__ . '/src/':'$WP_CORE_DIR/':" "$WP_TESTS_DIR"/wp-tests-config.php
121
+ sed $ioption "s/youremptytestdbnamehere/$DB_NAME/" "$WP_TESTS_DIR"/wp-tests-config.php
122
+ sed $ioption "s/yourusernamehere/$DB_USER/" "$WP_TESTS_DIR"/wp-tests-config.php
123
+ sed $ioption "s/yourpasswordhere/$DB_PASS/" "$WP_TESTS_DIR"/wp-tests-config.php
124
+ sed $ioption "s|localhost|${DB_HOST}|" "$WP_TESTS_DIR"/wp-tests-config.php
125
+ fi
126
+
127
+ }
128
+
129
+ recreate_db() {
130
+ shopt -s nocasematch
131
+ if [[ $1 =~ ^(y|yes)$ ]]
132
+ then
133
+ mysqladmin drop $DB_NAME -f --user="$DB_USER" --password="$DB_PASS"$EXTRA
134
+ create_db
135
+ echo "Recreated the database ($DB_NAME)."
136
+ else
137
+ echo "Leaving the existing database ($DB_NAME) in place."
138
+ fi
139
+ shopt -u nocasematch
140
+ }
141
+
142
+ create_db() {
143
+ mysqladmin create $DB_NAME --user="$DB_USER" --password="$DB_PASS"$EXTRA
144
+ }
145
+
146
+ install_db() {
147
+
148
+ if [ ${SKIP_DB_CREATE} = "true" ]; then
149
+ return 0
150
+ fi
151
+
152
+ # parse DB_HOST for port or socket references
153
+ local PARTS=(${DB_HOST//\:/ })
154
+ local DB_HOSTNAME=${PARTS[0]};
155
+ local DB_SOCK_OR_PORT=${PARTS[1]};
156
+ local EXTRA=""
157
+
158
+ if ! [ -z $DB_HOSTNAME ] ; then
159
+ if [ $(echo $DB_SOCK_OR_PORT | grep -e '^[0-9]\{1,\}$') ]; then
160
+ EXTRA=" --host=$DB_HOSTNAME --port=$DB_SOCK_OR_PORT --protocol=tcp"
161
+ elif ! [ -z $DB_SOCK_OR_PORT ] ; then
162
+ EXTRA=" --socket=$DB_SOCK_OR_PORT"
163
+ elif ! [ -z $DB_HOSTNAME ] ; then
164
+ EXTRA=" --host=$DB_HOSTNAME --protocol=tcp"
165
+ fi
166
+ fi
167
+
168
+ # create database
169
+ if [ $(mysql --user="$DB_USER" --password="$DB_PASS"$EXTRA --execute='show databases;' | grep ^$DB_NAME$) ]
170
+ then
171
+ echo "Reinstalling will delete the existing test database ($DB_NAME)"
172
+ read -p 'Are you sure you want to proceed? [y/N]: ' DELETE_EXISTING_DB
173
+ recreate_db $DELETE_EXISTING_DB
174
+ else
175
+ create_db
176
+ fi
177
+ }
178
+
179
+ install_wp
180
+ install_test_suite
181
+ install_db
include/api.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
 
3
- require_once('http.php');
4
 
5
  /**
6
  * manages communication with Lingotek TMS
@@ -14,8 +14,9 @@ class Lingotek_API extends Lingotek_HTTP {
14
  protected $client_id;
15
  private $auth_temp;
16
 
17
- const PRODUCTION_URL = "https://myaccount.lingotek.com";
18
- const CLIENT_ID = "780966c9-f9c8-4691-96e2-c0aaf47f62ff";// Lingotek App ID
 
19
 
20
 
21
  private $bridge_url = '';
@@ -26,36 +27,42 @@ class Lingotek_API extends Lingotek_HTTP {
26
  * @since 0.1
27
  */
28
  public function __construct() {
29
- $base_url = get_option('lingotek_base_url');
30
- $this->base_url = $base_url ? $base_url : self::PRODUCTION_URL;
31
- $this->api_url = $this->base_url.'/api';
32
  $this->client_id = self::CLIENT_ID;
33
- $token_details = get_option('lingotek_token');
34
- $this->headers['Authorization'] = 'bearer ' . $token_details['access_token'];
35
- $this->defaults = get_option('lingotek_defaults');
36
-
 
37
  $this->bridge_url = BRIDGE_URL . '/api/v2/transaction/translation/';
38
  }
39
 
40
- public function get_token_details($access_token) {
41
  $url = "{$this->base_url}/auth/oauth2/access_token_info";
42
- Lingotek_Logger::debug( "GET" , array( "url" => $url, "method" => __METHOD__));
43
- $args = array(
 
 
 
 
 
 
44
  'headers' => array(
45
  'Authorization' => "Bearer $access_token",
46
  ),
47
  );
48
- $response = wp_remote_get($url, $args);
49
- $response_code = wp_remote_retrieve_response_code($response);
50
 
51
- if ($response_code == 200) {
52
- $response_body = json_decode(wp_remote_retrieve_body($response));
53
  $token_details = $response_body;
 
 
54
  }
55
- else {
56
- $token_details = FALSE;
57
- }
58
- $this->log_error_on_response_failure($response, "GetTokenDetails: Error occured");
59
  return $token_details;
60
  }
61
 
@@ -70,37 +77,50 @@ class Lingotek_API extends Lingotek_HTTP {
70
  *
71
  * @param string $project_id
72
  */
73
- public function update_callback_url($project_id) {
74
- $args = array('callback_url' => add_query_arg('lingotek', 1, site_url()));
75
- $response = $this->patch($this->api_url . '/project/' . $project_id, $args);
76
- Lingotek_Logger::info('Request to update callback url', array('project_id' => $project_id));
77
- $this->log_error_on_response_failure($response, 'UpdateCallbackUrl: Error occured', array('project_id' => $project_id));
78
- return !is_wp_error($response) && 204 == wp_remote_retrieve_response_code($response);
79
  }
80
 
81
- /**
82
  * creates a new project
83
  *
84
  * @since 0.2
85
  *
86
  * @param string $title
87
  */
88
- public function create_project($title, $community_id) {
89
  $args = array(
90
- 'title' => $title,
91
  'community_id' => $community_id,
92
- 'workflow_id' => $this->get_workflow_id(),
93
- 'callback_url' => add_query_arg('lingotek', 1, site_url()),
94
  );
95
 
96
- $response = $this->post($this->api_url . '/project', $args);
97
- if(!is_wp_error($response) && 201 == wp_remote_retrieve_response_code($response)) {
98
- $new_id = json_decode(wp_remote_retrieve_body($response));
99
- Lingotek_Logger::info('Project created', array('id' => $new_id->properties->id, 'title' => $title));
 
 
 
 
 
 
100
  return $new_id->properties->id;
101
  }
102
-
103
- $this->log_error_on_response_failure($response, 'CreateProject: Error occured', array('title' => $title, 'community_id' => $community_id));
 
 
 
 
 
 
 
104
  return false;
105
  }
106
 
@@ -112,24 +132,37 @@ class Lingotek_API extends Lingotek_HTTP {
112
  * @param array $args expects array with title, content and locale_code
113
  * @returns bool|string document_id, false if something got wrong
114
  */
115
- public function upload_document($args, $wp_id = null) {
116
- Lingotek::log(debug_backtrace());
117
- Lingotek::log('uploading document');
118
- $args = wp_parse_args($args, array('format' => 'JSON', 'project_id' => $this->defaults['project_id'], 'workflow_id' => $this->get_workflow_id()));
119
- $this->format_as_multipart($args);
120
- $response = $this->post($this->api_url . '/document', $args);
121
- $this->update_lingotek_error_option($response, $wp_id, 'upload_document', sprintf(__('There was an error uploading WordPress item %1$s', 'lingotek-translation'), $wp_id));
122
- $code = wp_remote_retrieve_response_code($response);
123
- if (!is_wp_error($response) && 202 == $code) {
124
- $b = json_decode(wp_remote_retrieve_body($response));
125
- Lingotek_Logger::info('Document uploaded', array('document_id' => $b->properties->id, 'wp_id' => $wp_id));
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  return $b->properties->id;
127
- } elseif ($code == 402) {
128
- $lingotek_log_errors = get_option('lingotek_log_errors');
129
- $error_message = $this->get_error_message_from_response($response) !== false ?
130
- $this->get_error_message_from_response($response) : "No error message set by Lingotek";
131
- $lingotek_log_errors['patch_document_error'] = __("Payment required. Message: $error_message", 'lingotek-translation');
132
- update_option('lingotek_log_errors', $lingotek_log_errors, false);
133
  }
134
  return false;
135
  }
@@ -140,159 +173,197 @@ class Lingotek_API extends Lingotek_HTTP {
140
  * @since 0.1
141
  *
142
  * @param string $id document id
143
- * @param array $args expects array with content
144
- * @return bool false if something got wrong
145
  */
146
- public function patch_document($id, $args, $wp_id = null) {
147
- $lgtm = $GLOBALS['wp_lingotek']->model;
148
- $document = $lgtm->get_group_by_id($id);
149
- $args = $unformatted_args = wp_parse_args($args, array('format' => 'JSON'));
150
- $title = isset($args['title']) ? $args['title'] : $id;
151
- $this->format_as_multipart($args);
152
- $response = $this->patch($this->api_url . '/document/' . $id, $args);
153
- $status_code = wp_remote_retrieve_response_code($response);
154
- $body = json_decode(wp_remote_retrieve_body($response));
155
- if ($status_code == 400 && strpos($body->messages[0], 'has previously been cancelled')) {
156
- if ($targets = isset($document->translations) ? array_keys($document->translations) : null) {
157
- $unformatted_args['translation_locale_code'] = $targets;
158
- }
159
- $this->format_args_for_upload($unformatted_args, $wp_id);
160
- if (isset($document->translations)) {
161
- foreach ($document->translations as $locale) {
162
- $document->translations[$locale] = 'pending';
163
- }
164
- }
165
- $document->document_id = '';
166
- unset($document->desc_array['lingotek']);
167
  $document->save();
168
- return $this->upload_document($unformatted_args, $wp_id);
169
  }
170
- if ($status_code == 423) {
171
  $document->document_id = $body->next_document_id;
172
  $document->save();
173
- return $this->patch_document($body->next_document_id, $unformatted_args, $wp_id);
174
  }
175
 
176
  // We will handle patch errors separately. All we want to do is return the result of the current patch request to the user if payment is required
177
  // (although in theory this will never happen, because the WP model is document count based, and it will not allow them to upload documents until
178
  // they choose to buy more documents)
179
- $this->update_patch_error_message($response, $status_code, $title);
180
  // The current behavior sends no body, so we will just check to see if the body is empty for now in order to maintain current behavior
181
- if (empty($body)) {
182
- $success = !is_wp_error($response) && 202 == wp_remote_retrieve_response_code($response);
183
- if ($success) {
184
- Lingotek_Logger::info('Document updated', array('document_id' => $id, 'wp_id' => $wp_id));
 
 
 
 
 
 
185
  } else {
186
- Lingotek_Logger::error('Document failed to update', array('document_id' => $id, 'wp_id' => $wp_id));
 
 
 
 
 
 
187
  }
188
  return $success;
189
- }
190
-
191
- if ($status_code == 410) {
192
- Lingotek_Logger::info("Document ID was archived, reuploading document", array('old_document_id' => $id, 'wp_id' => $wp_id, 'args' => $args));
193
- $targets = array_keys($document->translations);
 
 
 
 
 
 
 
194
  $unformatted_args['translation_locale_code'] = $targets;
195
- $this->format_args_for_upload($unformatted_args, $wp_id);
196
- foreach ($document->translations as $locale) {
197
- $document->translations[$locale] = 'pending';
198
  }
199
- $document->document_id = '';
200
- unset($document->desc_array['lingotek']);
201
  $document->save();
202
- return $this->upload_document($unformatted_args, $wp_id);
203
  }
204
- if ($status_code == 402) {
205
- Lingotek_Logger::error('There was an error updating WordPress item', array('error' => $this->get_error_message_from_response($response)));
206
  $document->source_failed();
207
- return FALSE;
208
  }
209
- if ($status_code == 202 && !is_wp_error($response)) {
210
- Lingotek_Logger::info('Document updated', array('old_document_id' => $id, 'new_document_id' => $body->next_document_id, 'wp_id' => $wp_id));
 
 
 
 
 
 
 
211
  $document->document_id = $body->next_document_id;
212
  $document->save();
213
  return $body->next_document_id;
214
  }
215
- return FALSE;
216
  }
217
 
218
- private function format_args_for_upload(&$args, $wp_id) {
219
- $lgtm = $GLOBALS['wp_lingotek']->model;
220
- $post = get_post($wp_id);
221
- $language = PLL()->model->post->get_language($wp_id);
222
- $project_id = $lgtm->get_profile_option('project_id', $post->post_type, $language, false, $wp_id);
223
- $workflow_id = $lgtm->get_profile_option('workflow_id', $post->post_type, $language, false, $wp_id);
224
  $locale_code = $language->lingotek_locale;
225
- unset($args['format']);
226
  $args['locale_code'] = $locale_code;
227
- $args['project_id'] = $project_id;
228
  $args['workflow_id'] = $workflow_id;
229
  }
230
 
231
- private function update_patch_error_message($response, $status_code, $title) {
232
  // Do not inform user if call was successful.
233
- if ($status_code == 202 || $status_code == 410) {
234
  return;
235
  }
236
- $lingotek_log_errors = get_option('lingotek_log_errors', array());
237
- if (!is_array($lingotek_log_errors)) {
238
  $lingotek_log_errors = array();
239
  }
240
- $error_message = $this->get_error_message_from_response($response) !== FALSE ?
241
- $this->get_error_message_from_response($response) : "No error message set by Lingotek.";
242
 
243
- if ($status_code == 402) {
244
- $lingotek_log_errors['patch_document_error'] = __("Payment required. Message: $error_message", 'lingotek-translation');
245
- }
246
- else {
247
- $lingotek_log_errors['patch_document_error'] = __("Error occurred while updating document $title. Message: $error_message", 'lingotek-translation');
248
  }
249
- update_option('lingotek_log_errors', $lingotek_log_errors);
250
  }
251
 
252
  /**
253
  * cancels a document
254
- *
255
  * @since 1.4.2
256
- *
257
  * @param string $id document id
258
  */
259
- public function cancel_document(&$id, $wp_id = null) {
260
- $args = wp_parse_args(array('cancelled_reason' => "CANCELLED_BY_AUTHOR"));
261
- $response = $this->post("$this->api_url/document/$id/cancel", $args);
262
- if($wp_id) {
263
- $arr = get_option('lingotek_log_errors');
264
- if(isset($arr[$wp_id])) {
265
- unset($arr[$wp_id]);
266
- update_option('lingotek_log_errors', $arr, false);
267
  }
268
  }
269
- $this->log_error_on_response_failure($response, "CancelDocument: Error occurred", array('id' => $id, 'wordpress_id' => $wp_id));
270
- $is_success = !is_wp_error($response) && (204 == wp_remote_retrieve_response_code($response) || 202 == wp_remote_retrieve_response_code($response));
271
- $lgtm = $GLOBALS['wp_lingotek']->model;
272
- $document = $lgtm->get_group_by_id($id);
273
- $current_status = $document->status;
 
 
 
 
 
 
 
274
  $document->status = 'cancelled';
275
- if ($is_success) {
276
- wp_remove_object_terms($wp_id, "lingotek_hash_{$wp_id}", "lingotek_hash");
277
- Lingotek_Logger::info('Document cancelled', array('document_id' => $id, 'wp_id' => $wp_id));
 
 
 
 
 
 
278
  $document->save();
279
  return $is_success;
280
- } elseif (403 != wp_remote_retrieve_response_code($response)) {
281
- wp_remove_object_terms($wp_id, "lingotek_hash_{$wp_id}", "lingotek_hash");
282
- Lingotek_Logger::warning('Document was not cancelled in TMS', array('document' => $id, 'wp_id' => $wp_id));
283
- $document->document_id = $id = '';
 
 
 
 
 
 
 
284
  $document->save();
285
  return true;
286
- }
287
- $document->status = $current_status;
288
- $lingotek_log_errors = get_option('lingotek_log_errors', array());
289
- if (!is_array($lingotek_log_errors)) {
290
  $lingotek_log_errors = array();
291
  }
292
- $error_message = $this->get_error_message_from_response($response) !== FALSE ?
293
- $this->get_error_message_from_response($response) : "No error message set by Lingotek.";
294
  $lingotek_log_errors['disassociate_document_error'] = $error_message;
295
- update_option('lingotek_log_errors', $lingotek_log_errors, false);
296
  return $is_success;
297
  }
298
 
@@ -302,31 +373,31 @@ class Lingotek_API extends Lingotek_HTTP {
302
  *
303
  * @since 0.1
304
  */
305
- public function get_document_ids($args = array()) {
306
- $response = $this->get(add_query_arg($args, $this->api_url . '/document'));
307
- $ids = array();
308
 
309
- if (!is_wp_error($response) && 200 == wp_remote_retrieve_response_code($response)) {
310
- $documents = json_decode(wp_remote_retrieve_body($response));
311
- foreach ($documents->entities as $doc) {
312
  $ids[] = $doc->properties->id;
313
  }
314
  }
315
 
316
- $this->log_error_on_response_failure($response, 'GetDocumentIds: Error occured');
317
  return $ids;
318
  }
319
 
320
- public function get_document_count($args = array()) {
321
- $response = $this->get(add_query_arg($args, $this->api_url . '/document'));
322
- $docs = array();
323
 
324
- if (!is_wp_error($response) && 200 == wp_remote_retrieve_response_code($response)) {
325
- $response = json_decode(wp_remote_retrieve_body($response));
326
  return $response->properties->total;
327
  }
328
 
329
- $this->log_error_on_response_failure($response, 'GetDocumentCount: Error occured');
330
  return null;
331
  }
332
 
@@ -335,18 +406,18 @@ class Lingotek_API extends Lingotek_HTTP {
335
  *
336
  * @since 0.1
337
  */
338
- public function get_documents($args = array()) {
339
- $response = $this->get(add_query_arg($args, $this->api_url . '/document'));
340
- $docs = array();
341
 
342
- if (!is_wp_error($response) && 200 == wp_remote_retrieve_response_code($response)) {
343
- $documents = json_decode(wp_remote_retrieve_body($response));
344
- foreach ($documents->entities as $doc) {
345
  $docs[] = $doc;
346
  }
347
  }
348
 
349
- $this->log_error_on_response_failure($response, 'GetDocuments: Error occured');
350
  return $docs;
351
  }
352
 
@@ -355,27 +426,26 @@ class Lingotek_API extends Lingotek_HTTP {
355
  *
356
  * @since 0.1
357
  */
358
- public function get_document($doc_id) {
359
- $response = $this->get($this->api_url . '/document/' . $doc_id);
360
 
361
- if (!is_wp_error($response) && 200 == wp_remote_retrieve_response_code($response)) {
362
- $document = json_decode(wp_remote_retrieve_body($response));
363
  }
364
 
365
- $this->log_error_on_response_failure($response, 'GetDocument: Error occured');
366
  return $document;
367
  }
368
 
369
- public function get_document_status($doc_id)
370
- {
371
- $imported = FALSE;
372
- $response = $this->get($this->api_url . '/document/' . $doc_id . '/status');
373
 
374
- if (!is_wp_error($response) && 200 == wp_remote_retrieve_response_code($response)) {
375
- $imported = TRUE;
376
  }
377
 
378
- $this->log_error_on_response_failure($response, 'GetDocumentStatus: Error occured', array('document_id' => $doc_id));
379
  return $imported;
380
  }
381
 
@@ -388,14 +458,14 @@ class Lingotek_API extends Lingotek_HTTP {
388
  * @param string $id document id
389
  * @return string
390
  */
391
- public function get_document_content($doc_id) {
392
- $response = $this->get($this->api_url . "/document/$doc_id/content");
393
 
394
- if (!is_wp_error($response) && 200 == wp_remote_retrieve_response_code($response)) {
395
  $content = wp_remote_retrieve_body( $response );
396
  }
397
 
398
- $this->log_error_on_response_failure($response, 'GetDocumentContent: Error occured', ['document_id' => $doc_id]);
399
  return $content;
400
  }
401
 
@@ -408,16 +478,23 @@ class Lingotek_API extends Lingotek_HTTP {
408
  * @param string $locale locale
409
  * @return int with locale percent_complete
410
  */
411
- public function get_translation_status($doc_id, $locale) {
412
- $locale = Lingotek::map_to_lingotek_locale($locale);
413
- $status = -1;
414
- $response = $this->get($this->api_url."/document/$doc_id/translation/$locale");
415
- if (!is_wp_error($response) && 200 == wp_remote_retrieve_response_code($response)) {
416
- $b = json_decode(wp_remote_retrieve_body($response));
417
  $status = $b->properties->percent_complete;
418
  }
419
 
420
- $this->log_error_on_response_failure($response, 'GetTranslationStatus: Error occurred', ['document_id' => $doc_id, 'locale' => $locale]);
 
 
 
 
 
 
 
421
  return $status;
422
  }
423
 
@@ -429,150 +506,209 @@ class Lingotek_API extends Lingotek_HTTP {
429
  * @param string $id document id
430
  * @return array with locale as key and status as value
431
  */
432
- public function get_translations_status($doc_id, $wp_id = null) {
433
- $response = $this->get($this->api_url . '/document/' . $doc_id . '/translation');
434
- if (!is_wp_error($response) && 200 == wp_remote_retrieve_response_code($response)) {
435
- $b = json_decode(wp_remote_retrieve_body($response));
436
- foreach ($b->entities as $e) {
437
- if($e->properties->status != 'CANCELLED') {
438
  // cancelled is in a completed state, but it does not mean the translation is 100% complete
439
- $translations[$e->properties->locale_code] = $e->properties->percent_complete;
 
 
 
440
  }
441
  }
442
  }
443
 
444
- Lingotek_Logger::info('Translation status requested', array('document_id' => $doc_id, 'wp_id' => $wp_id, 'translations' => isset($translations) ? $translations : '' ));
445
-
 
 
 
 
 
 
 
446
  $this->update_lingotek_error_option(
447
- $response,
448
- $wp_id,
449
- 'get_translations_status',
450
- sprintf(__('There was an error updating the translations status for WordPress item %1$s', 'lingotek-translation'), $wp_id),
451
- array('document_id'=>$doc_id));
 
452
 
453
- return empty($translations) ? array() : $translations;
454
  }
455
 
456
 
457
- public function get_language_mappings()
458
- {
459
- $url = 'https://gmc.lingotek.com/v1/locales';
460
- $response = $this->get($url);
461
- return json_decode(wp_remote_retrieve_body($response),true);
462
  }
463
 
464
  /**
465
- * Makes an API call to bridge to get the estimated cost for translating a particular document professionally.
466
- *
467
- * @param string $lingotek_auth the auth token to make an API call to bridge.
468
- * @param string $document_id the id of the specific document.
469
- * @param string $locale the locale of the document being requested.
470
- */
471
- public function get_cost_estimate($lingotek_auth, $document_id, $locale) {
472
  $this->start_bridge_call();
473
 
474
- $args = array(
475
  'document_id' => $document_id,
476
- 'locale' => $locale
477
  );
478
- $response = $this->get($this->bridge_url . 'estimate', $args);
479
 
480
- $success = 200 === wp_remote_retrieve_response_code($response);
481
 
482
  $this->end_bridge_call();
483
 
484
- $this->log_error_on_response_failure($response, 'GetCostEstimate: Error occured', array('document_id' => $document_id, 'locale' => $locale));
485
- return array('success' => $success, 'data' => $this->get_response_body_from_bridge($response));
 
 
 
 
 
 
 
 
 
 
486
  }
487
 
488
  /**
489
- * Makes an API call to bridge request translation for a document using the professional workflow.
490
- *
491
- * @param string $document_id the id of the specific document.
492
- * @param string $locale the locale of the document being requested.
493
- * @param string $workflow_id the id used to process the document.
494
- */
495
- public function request_professional_translation($document_id, $locale, $workflow_id) {
496
  $this->start_bridge_call();
497
-
498
- $args = array(
499
  'document_id' => $document_id,
500
- 'locale' => $locale,
501
  'workflow_id' => $workflow_id,
502
  );
503
- $response = $this->post($this->bridge_url . 'request', $args);
504
- $success = 200 === wp_remote_retrieve_response_code($response);
505
 
506
  $this->end_bridge_call();
507
 
508
- if ($success) { Lingotek_Logger::info('Professional translation requested', array('document_id' => $document_id, 'locale' => $locale, 'wordflow_id' => $workflow_id)); }
509
- $this->log_error_on_response_failure($response, 'RequestProfessionalTranslation: Error occured', array('document_id' => $document_id, 'locale' => $locale, 'workflow_id' => $workflow_id));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
510
 
511
- return array('success' => $success, 'data' => $this->get_response_body_from_bridge($response));
 
 
 
512
  }
513
 
514
  /**
515
- * Makes an API call to bridge request bulk translations for a document using the professional workflow.
516
- *
517
- * @param string $document_id the id of the specific document.
518
- * @param string $locale the locale of the document being requested.
519
- * @param string $workflow_id the id used to process the document.
520
- */
521
- public function request_professional_translation_bulk($workflow_id, $translations, $total_estimate, $summary) {
522
  $this->start_bridge_call();
523
-
524
- $args = array(
525
- 'workflow_id' => $workflow_id,
526
- 'translations' => $translations,
527
  'total_estimate' => $total_estimate,
528
- 'summary' => $summary
529
  );
530
- $response = $this->post($this->bridge_url . 'request/bulk', $args, 60);
531
- $success = 200 === wp_remote_retrieve_response_code($response);
532
 
533
  $this->end_bridge_call();
534
 
535
- if ($success) { Lingotek_Logger::info('Professional translation (bulk) requested', array('translations' => $translations, 'wordflow_id' => $workflow_id)); }
536
- $this->log_error_on_response_failure($response, 'RequestProfessionalTranslationBulk: Error occured', array('translations' => $translations, 'total_estimate' => $total_estimate, 'workflow_id' => $workflow_id));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
537
 
538
- return array('data' => $this->get_response_body_from_bridge($response));
539
  }
540
 
541
 
542
  public function get_lingotek_terms_and_conditions() {
543
  $this->start_bridge_call();
544
- $response = $this->get(BRIDGE_URL . '/api/v2/transaction/terms/');
545
- $success = 200 === wp_remote_retrieve_response_code($response);
546
  $this->end_bridge_call();
547
 
548
- $this->log_error_on_response_failure($response, 'GetLingotekTermsAndConditions: Error occured');
549
- return array('success' => $success, 'data' => $this->get_response_body_from_bridge($response));
 
 
 
550
  }
551
 
552
  /**
553
- * Makes an API call to bridge to get the payment information about the user.
554
- */
555
  public function get_user_payment_information() {
556
  $this->start_bridge_call();
557
 
558
- $response = $this->get(BRIDGE_URL . '/api/v2/transaction/payment');
559
- $success = 200 === wp_remote_retrieve_response_code($response);
560
 
561
  $this->end_bridge_call();
562
 
563
- $this->log_error_on_response_failure($response, "GetUserPaymentInformation: Error occured");
564
- return array('success' => $success, 'payment_info' => $this->get_response_body_from_bridge($response));
 
 
 
565
  }
566
 
567
  /**
568
- * Helper function to retrieve the response body from bridge.
569
- *
570
- * @param array $response the response from bridge.
571
- */
572
- private function get_response_body_from_bridge($response)
573
- {
574
- $body = json_decode(wp_remote_retrieve_body($response),true);
575
- return isset($body) ? $body : wp_remote_retrieve_body($response);
576
  }
577
 
578
  /**
@@ -582,72 +718,82 @@ class Lingotek_API extends Lingotek_HTTP {
582
  *
583
  * @param string $id document id
584
  * @param string $locale Lingotek locale
585
- * @param array $args optional arguments (only workflow_id at the moment)
586
  * @return bool true if the request succeeded
587
  */
588
- public function request_translation($id, $locale, $args = array(), $wp_id = null) {
589
- $lgtm = $GLOBALS['wp_lingotek']->model;
590
- $document = $lgtm->get_group_by_id($id);
591
- $locale = Lingotek::map_to_lingotek_locale($locale);
592
- $args = $unformatted_args = wp_parse_args($args, array('workflow_id' => $this->get_workflow_id()));
593
- $args = array_merge(array('locale_code' => $locale), $args);
594
- $response = $this->post($this->api_url . '/document/' . $id . '/translation', $args);
595
- $title = isset($args['title']) ? $args['title'] : $id;
596
- if ($wp_id) {
597
- $arr = get_option('lingotek_log_errors', array());
598
- $status_code = wp_remote_retrieve_response_code($response);
599
- $body = json_decode(wp_remote_retrieve_body($response));
600
- $this->update_patch_error_message($response, $status_code, $title);
601
- if (423 === $status_code) {
602
  $document->document_id = $body->next_document_id;
603
  $document->save();
604
- return $this->request_translation($body->next_document_id, $locale, $unformatted_args, $wp_id);
605
  }
606
- if (402 === $status_code) {
607
- Lingotek_Logger::error('There was an error updating WordPress item', array('error' => $this->get_error_message_from_response($response)));
608
  $document->source_failed();
609
  return false;
610
  }
611
- if (410 === $status_code) {
612
  // WP hooks automatically check source status so this might not get called
613
- $targets = array_keys($document->translations);
614
- $targets[] = $locale;
615
  $unformatted_args['translation_locale_code'] = $targets;
616
- $this->format_args_for_upload($unformatted_args, $wp_id);
617
- unset($document->desc_array['lingotek']);
618
  $document->save();
619
- foreach ($document->translations as $locale) {
620
- $document->translations[$locale] = 'pending';
621
  }
622
- return $this->upload_document($unformatted_args, $wp_id);
623
  }
624
- if (400 === $status_code &&
625
- !empty($body->messages) &&
626
- strpos($body->messages[0], 'already exists')) {
627
  // Translation has already been requested, treat it as a 201 response
628
  $status_code = 201;
629
  }
630
- if (201 === $status_code) {
631
- if (isset($arr[$wp_id])) {
632
- unset($arr[$wp_id]['wp_error']);
633
- unset($arr[$wp_id]['request_translation'][$locale]);
634
- if (empty($arr[$wp_id])){
635
- unset($arr[$wp_id]);
636
  }
637
  }
638
- } elseif (is_wp_error($response)) {
639
- $arr[$wp_id]['wp_error'] = __('Make sure you have internet connectivity', 'lingotek-translation');
640
- } elseif (400 == $status_code || 404 == $status_code) {
641
- $arr[$wp_id]['request_translation'][$locale] = sprintf(
642
- __('There was an error requesting translation %1$s for WordPress item %2$s', 'lingotek-translation'), $locale, $wp_id
 
 
643
  );
644
  }
645
- update_option('lingotek_log_errors', $arr, false);
 
 
 
 
 
 
 
 
 
 
 
646
  }
647
- if (201 !== $status_code) {
648
- $this->log_error_on_response_failure($response, "RequestTranslation: Error Occurred", ['document_id' => $id, 'locale' => $locale, 'args' => $args]);
649
- }
650
- return !is_wp_error($response) && 201 === $status_code;
651
  }
652
 
653
  /**
@@ -659,77 +805,112 @@ class Lingotek_API extends Lingotek_HTTP {
659
  * @param string $locale Lingotek locale
660
  * @return string|bool the translation, false if there is none
661
  */
662
- public function get_translation($doc_id, $locale, $wp_id = null) {
663
- $locale = Lingotek::map_to_lingotek_locale($locale);
664
-
665
- $response = $this->get(add_query_arg(array('locale_code' => $locale, 'auto_format' => 'true') , $this->api_url . '/document/' . $doc_id . '/content'));
 
 
 
 
 
 
 
 
666
 
667
- if ($wp_id) {
668
- $arr = get_option('lingotek_log_errors');
669
- $status_code = wp_remote_retrieve_response_code($response);
670
- if (410 == $status_code) {
671
- $lgtm = $GLOBALS['wp_lingotek']->model;
672
- $document = $lgtm->get_group_by_id($doc_id);
673
  $document->source_failed();
674
  //TODO IS THIS SETTING ERROR PROPERLY?
675
- $arr[$wp_id]['wp_error'] = __("Document $doc_id has been archived. Please re-upload source", 'lingotek-translation');
676
  return false;
677
- } else if (200 == $status_code) {
678
- if (isset($arr[$wp_id])) {
679
- unset($arr[$wp_id]['wp_error']);
680
- unset($arr[$wp_id]['get_translation'][$locale]);
681
- if (empty($arr[$wp_id])) {
682
- unset($arr[$wp_id]);
683
  }
684
  }
685
- } else if (is_wp_error($response)) {
686
- $arr[$wp_id]['wp_error'] = __('Make sure you have internet connectivity', 'lingotek-translation');
687
- } else if (400 == $status_code || 404 == $status_code) {
688
- $arr[$wp_id]['get_translation'][$locale] = sprintf(
689
- __('There was an error downloading translation %1$s for WordPress item %2$s'), $locale, $wp_id
 
 
690
  );
691
- }
692
- update_option('lingotek_log_errors', $arr, false);
693
- }
694
- $this->log_error_on_response_failure($response, "GetTranslation: Error Occurred", ['document_id' => $doc_id, 'locale' => $locale]);
695
- return !is_wp_error($response) && 200 == $status_code ? wp_remote_retrieve_body($response) : false;
 
 
 
 
 
 
 
696
  }
697
 
698
  /**
699
  * cancels a translation
700
- *
701
  * @since 1.4.2
702
- *
703
  * @param string $id document id
704
  * @param string $locale Lingotek locale
705
  */
706
- public function cancel_translation($id, $locale, $wp_id = null) {
707
- $args = wp_parse_args(array('cancelled_reason' => "CANCELLED_BY_AUTHOR", 'mark_invoiceable' => true));
708
- $response = $this->post("$this->api_url/document/$id/translation/$locale/cancel", $args);
709
-
710
- if($wp_id) {
711
- $arr = get_option('lingotek_log_errors');
712
- if(isset($arr[$wp_id])) {
713
- unset($arr[$wp_id]);
714
- update_option('lingotek_log_errors', $arr, false);
 
 
 
 
 
715
  }
716
  }
717
- $this->log_error_on_response_failure($response, "CancelTranslation: Error occurred", array('id' => $id, 'wordpress_id' => $wp_id));
718
- $is_success = !is_wp_error($response) && (204 == wp_remote_retrieve_response_code($response) || 202 == wp_remote_retrieve_response_code($response));
719
- if ($is_success) {
720
- Lingotek_Logger::info('Target cancelled', ['document_id' => $id, 'wp_id' => $wp_id]);
 
 
 
 
 
 
 
 
 
 
 
 
 
721
  return $is_success;
722
  }
723
- $lingotek_log_errors = get_option('lingotek_log_errors', array());
724
- if (!is_array($lingotek_log_errors)) {
725
  $lingotek_log_errors = array();
726
  }
727
  // Use the response message if it's an authorization error
728
- $response_error_message = 403 == wp_remote_retrieve_response_code($response) && $this->get_error_message_from_response($response) !== FALSE ?
729
- $this->get_error_message_from_response($response) : FALSE;
730
- $error_message = $response_error_message ? $response_error_message : "{$locale} was already completed in the TMS and cannot be cancelled unless the entire document is cancelled.";
731
  $lingotek_log_errors['disassociate_document_error'] = $error_message;
732
- update_option('lingotek_log_errors', $lingotek_log_errors, false);
733
 
734
  return $is_success;
735
  }
@@ -740,64 +921,92 @@ class Lingotek_API extends Lingotek_HTTP {
740
  * @param string $redirect_uri the location where to redirect to after account has been connected
741
  * @return string the complete url for the connect account link
742
  */
743
- public function get_connect_url($redirect_uri, $env = NULL) {
744
- $base_url = $this->base_url;
745
  $client_id = $this->client_id;
746
- if(!is_null($env)){
747
  $base_url = self::PRODUCTION_URL;
748
  }
749
- return "$base_url/auth/authorize.html?client_id=$client_id&redirect_uri=" . urlencode($redirect_uri) . "&response_type=token";
750
  }
751
 
752
- public function get_new_url($redirect_uri) {
753
- $base_url = self::PRODUCTION_URL;
754
  $client_id = $this->client_id;
755
- return "$base_url/lingopoint/portal/requestAccount.action?client_id=$client_id&app=" . urlencode($redirect_uri) . "&response_type=token";
756
-
757
  }
758
 
759
  public function get_communities() {
760
- $response = $this->get(add_query_arg(array('limit' => 1000), $this->api_url . '/community'));
761
- return !is_wp_error($response) && 200 == wp_remote_retrieve_response_code($response) ? json_decode(wp_remote_retrieve_body($response)) : false;
762
  }
763
 
764
- public function get_projects($community_id) {
765
- $response = $this->get(add_query_arg(array('community_id' => $community_id, 'limit' => 1000), $this->api_url . '/project'));
766
- if (wp_remote_retrieve_response_code($response) == 204) {
767
- return array();// there are currently no projects
 
 
 
 
 
 
 
 
 
768
  }
769
- return !is_wp_error($response) && 200 == wp_remote_retrieve_response_code($response) ? json_decode(wp_remote_retrieve_body($response)) : false;
770
  }
771
 
772
- public function get_vaults($community_id) {
773
- $response = $this->get(add_query_arg(array('community_id' => $community_id, 'limit' => 1000), $this->api_url . '/vault'));
774
- return !is_wp_error($response) && 200 == wp_remote_retrieve_response_code($response) ? json_decode(wp_remote_retrieve_body($response)) : false;
 
 
 
 
 
 
 
 
775
  }
776
 
777
- public function get_workflows($community_id) {
778
- $response = $this->get(add_query_arg(array('community_id' => $community_id, 'limit' => 1000), $this->api_url . '/workflow'));
779
- return !is_wp_error($response) && 200 == wp_remote_retrieve_response_code($response) ? json_decode(wp_remote_retrieve_body($response)) : false;
 
 
 
 
 
 
 
 
780
  }
781
 
782
  public function get_filters() {
783
- $response = $this->get(add_query_arg(array('limit' => 1000), $this->api_url . '/filter'));
784
- return !is_wp_error($response) && 200 == wp_remote_retrieve_response_code($response) ? json_decode(wp_remote_retrieve_body($response)) : false;
785
  }
786
 
787
- public function upload_filter($name, $type, $content) {
788
- $args = array('name' => $name, 'type' => $type, 'content' => $content);
789
- $response = $this->post("$this->api_url/filter", $args);
 
 
 
 
790
  }
791
 
792
  private function start_bridge_call() {
793
  $this->auth_temp = $this->headers['Authorization'];
794
- unset($this->headers['Authorization']);
795
- $option = get_option('lingotek_token');
796
  $this->headers['Authorization-Lingotek'] = $option['access_token'];
797
  }
798
 
799
  private function end_bridge_call() {
800
- unset($this->headers['Authorization-Lingotek']);
801
  $this->headers['Authorization'] = $this->auth_temp;
802
  }
803
 
@@ -806,93 +1015,137 @@ class Lingotek_API extends Lingotek_HTTP {
806
  }
807
 
808
  /**
809
- * Helper function to update lingotek errors as 'lingotek_log_errors' option in case of translation actions (get / request).
810
- *
811
- * @param $response the response from the action (wp_remote_*).
812
- * @param $wp_id id that represents the object in the WP world (post_id / term_id / etc)
813
- * @param $action the name of the action performed (for ex 'reqeust_translation')
814
- * @param $error_message the message to write in case the response indicates failure
815
- * @param $locale the locale the translation action was performed on
816
- * @param $extra_data (optional) array of key/value pairs that will be sent as part of the error
817
- */
818
- private function update_lingotek_error_option_for_translation($response, $wp_id, $action, $error_message, $locale, $extra_data = array()){
819
- if ($wp_id) {
820
- $arr = get_option('lingotek_log_errors');
821
- $response_message_code = wp_remote_retrieve_response_code($response);
822
- if (200 == $response_message_code || 201 == $response_message_code) {
823
- if (isset($arr[$wp_id])) {
824
- unset($arr[$wp_id]['wp_error']);
825
- unset($arr[$wp_id][$action][$locale]);
826
- if (empty($arr[$wp_id])) {
827
- unset($arr[$wp_id]);
828
  }
829
  }
830
- }
831
- else if (is_wp_error($response)) {
832
- $arr[$wp_id]['wp_error'] = __('Make sure you have internet connectivity', 'lingotek-translation');
833
- Lingotek_Logger::error($action.": Wordpress error occured, please make sure you have internet connectivity", array_merge(array('http_status'=>$response_message_code, 'wordpress_id'=>$wp_id), $extra_data));
834
- }
835
- else if (400 == $response_message_code || 404 == $response_message_code) {
836
- $arr[$wp_id][$action][$locale] = $error_message;
837
- Lingotek_Logger::error($action.": Error occured", array_merge(array('response_message_code'=>$response_message_code, 'wordpress_id'=>$wp_id, 'response_message'=>$this->get_error_message_from_response($response)), $extra_data));
838
- }
839
- update_option('lingotek_log_errors', $arr, false);
840
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
841
  }
842
 
843
  /**
844
- * Helper function to update lingotek errors as 'lingotek_log_errors' option.
845
- *
846
- * @param $response the response from the action (wp_remote_*).
847
- * @param $wp_id id that represents the object in the WP world (post_id / term_id / etc)
848
- * @param $action the name of the action performed (for ex 'reqeust_translation')
849
- * @param $error_message the message to write in case the response indicates failure
850
- * @param $extra_data (optional) array of key/value pairs that will be sent as part of the error
851
- */
852
- private function update_lingotek_error_option($response, $wp_id, $action, $error_message, $extra_data = array()){
853
- if ($wp_id){
854
- $arr = get_option('lingotek_log_errors');
855
- $response_message_code = wp_remote_retrieve_response_code($response);
856
- if (empty($arr)) {
857
  return;
858
  }
859
 
860
- if (200 == $response_message_code || 202 == $response_message_code) {
861
- if (isset($arr[$wp_id])) {
862
- unset($arr[$wp_id]);
863
  }
864
- }
865
- else if (is_wp_error($response)) {
866
- $arr[$wp_id]['wp_error'] = __('Make sure you have internet connectivity', 'lingotek-translation');
867
- Lingotek_Logger::error("$action: Wordpress error occured, please make sure you have internet connectivity", array_merge(array('http_status'=>$response_message_code, 'wordpress_id'=>$wp_id), $extra_data));
868
- }
869
- else if (400 == $response_message_code || 404 == $response_message_code) {
870
- $arr[$wp_id][$action] = $error_message;
871
- Lingotek_Logger::error("$action: Error occured", array_merge(array('http_status'=>$response_message_code, 'wordpress_id'=>$wp_id, 'response_message'=>$this->get_error_message_from_response($response)), $extra_data));
872
- }
873
- update_option('lingotek_log_errors', $arr, false);
874
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
875
  }
876
 
877
  /**
878
- * Helper function to send error log entry to Lingotek_Logger in case the response indicates failure.
879
- * Failure response has http status different than 200/201/202/204 and is not wp_error response
880
- *
881
- * @param $response the response from the action (wp_remote_*).
882
- * @param $error_message the message to write in case the response indicates failure
883
- * @param $extra_data (optional) array of key/value pairs that will be sent as part of the error
884
- */
885
- private function log_error_on_response_failure($response, $error_message, $extra_data = array()){
886
- $http_code = wp_remote_retrieve_response_code($response);
887
- $success = 200 === $http_code || 201 === $http_code || 202 === $http_code || 204 === $http_code;
888
- if (!$success || is_wp_error($response)) Lingotek_Logger::error($error_message, array_merge(array('http_status'=>$http_code, $extra_data)));
889
- }
890
-
891
- private function get_error_message_from_response($response){
892
- $responseBody = json_decode(wp_remote_retrieve_body($response));
893
- if (empty($responseBody)) {
 
 
 
 
 
 
 
 
 
 
894
  return false;
895
  }
896
- return property_exists($responseBody, "messages") && is_array($responseBody->messages) ? implode(" ",$responseBody->messages) : false;
897
  }
898
- }
1
  <?php
2
 
3
+ require_once 'http.php';
4
 
5
  /**
6
  * manages communication with Lingotek TMS
14
  protected $client_id;
15
  private $auth_temp;
16
 
17
+ const PRODUCTION_URL = 'https://myaccount.lingotek.com';
18
+ // Lingotek App ID.
19
+ const CLIENT_ID = '780966c9-f9c8-4691-96e2-c0aaf47f62ff';
20
 
21
 
22
  private $bridge_url = '';
27
  * @since 0.1
28
  */
29
  public function __construct() {
30
+ $base_url = get_option( 'lingotek_base_url' );
31
+ $this->base_url = $base_url ? $base_url : self::PRODUCTION_URL;
32
+ $this->api_url = $this->base_url . '/api';
33
  $this->client_id = self::CLIENT_ID;
34
+ $token_details = get_option( 'lingotek_token', array() );
35
+ if ( isset( $token_details['access_token'] ) ) {
36
+ $this->headers['Authorization'] = 'bearer ' . $token_details['access_token'];
37
+ }
38
+ $this->defaults = get_option( 'lingotek_defaults', array() );
39
  $this->bridge_url = BRIDGE_URL . '/api/v2/transaction/translation/';
40
  }
41
 
42
+ public function get_token_details( $access_token ) {
43
  $url = "{$this->base_url}/auth/oauth2/access_token_info";
44
+ Lingotek_Logger::debug(
45
+ 'GET',
46
+ array(
47
+ 'url' => $url,
48
+ 'method' => __METHOD__,
49
+ )
50
+ );
51
+ $args = array(
52
  'headers' => array(
53
  'Authorization' => "Bearer $access_token",
54
  ),
55
  );
56
+ $response = wp_remote_get( $url, $args );
57
+ $response_code = wp_remote_retrieve_response_code( $response );
58
 
59
+ if ( $response_code == 200 ) {
60
+ $response_body = json_decode( wp_remote_retrieve_body( $response ) );
61
  $token_details = $response_body;
62
+ } else {
63
+ $token_details = false;
64
  }
65
+ $this->log_error_on_response_failure( $response, 'GetTokenDetails: Error occured' );
 
 
 
66
  return $token_details;
67
  }
68
 
77
  *
78
  * @param string $project_id
79
  */
80
+ public function update_callback_url( $project_id ) {
81
+ $args = array( 'callback_url' => add_query_arg( 'lingotek', 1, site_url() ) );
82
+ $response = $this->patch( $this->api_url . '/project/' . $project_id, $args );
83
+ Lingotek_Logger::info( 'Request to update callback url', array( 'project_id' => $project_id ) );
84
+ $this->log_error_on_response_failure( $response, 'UpdateCallbackUrl: Error occured', array( 'project_id' => $project_id ) );
85
+ return ! is_wp_error( $response ) && 204 == wp_remote_retrieve_response_code( $response );
86
  }
87
 
88
+ /**
89
  * creates a new project
90
  *
91
  * @since 0.2
92
  *
93
  * @param string $title
94
  */
95
+ public function create_project( $title, $community_id ) {
96
  $args = array(
97
+ 'title' => $title,
98
  'community_id' => $community_id,
99
+ 'workflow_id' => $this->get_workflow_id(),
100
+ 'callback_url' => add_query_arg( 'lingotek', 1, site_url() ),
101
  );
102
 
103
+ $response = $this->post( $this->api_url . '/project', $args );
104
+ if ( ! is_wp_error( $response ) && 201 == wp_remote_retrieve_response_code( $response ) ) {
105
+ $new_id = json_decode( wp_remote_retrieve_body( $response ) );
106
+ Lingotek_Logger::info(
107
+ 'Project created',
108
+ array(
109
+ 'id' => $new_id->properties->id,
110
+ 'title' => $title,
111
+ )
112
+ );
113
  return $new_id->properties->id;
114
  }
115
+
116
+ $this->log_error_on_response_failure(
117
+ $response,
118
+ 'CreateProject: Error occured',
119
+ array(
120
+ 'title' => $title,
121
+ 'community_id' => $community_id,
122
+ )
123
+ );
124
  return false;
125
  }
126
 
132
  * @param array $args expects array with title, content and locale_code
133
  * @returns bool|string document_id, false if something got wrong
134
  */
135
+ public function upload_document( $args, $wp_id = null ) {
136
+ Lingotek::log( debug_backtrace() );
137
+ Lingotek::log( 'uploading document' );
138
+ $args = wp_parse_args(
139
+ $args,
140
+ array(
141
+ 'format' => 'JSON',
142
+ 'project_id' => $this->defaults['project_id'],
143
+ 'workflow_id' => $this->get_workflow_id(),
144
+ )
145
+ );
146
+ $this->format_as_multipart( $args );
147
+ $response = $this->post( $this->api_url . '/document', $args );
148
+ $this->update_lingotek_error_option( $response, $wp_id, 'upload_document', sprintf( __( 'There was an error uploading WordPress item %1$s', 'lingotek-translation' ), $wp_id ) );
149
+ $code = wp_remote_retrieve_response_code( $response );
150
+ if ( ! is_wp_error( $response ) && 202 == $code ) {
151
+ $b = json_decode( wp_remote_retrieve_body( $response ) );
152
+ Lingotek_Logger::info(
153
+ 'Document uploaded',
154
+ array(
155
+ 'document_id' => $b->properties->id,
156
+ 'wp_id' => $wp_id,
157
+ )
158
+ );
159
  return $b->properties->id;
160
+ } elseif ( $code == 402 ) {
161
+ $lingotek_log_errors = get_option( 'lingotek_log_errors' );
162
+ $error_message = $this->get_error_message_from_response( $response ) !== false ?
163
+ $this->get_error_message_from_response( $response ) : 'No error message set by Lingotek';
164
+ $lingotek_log_errors['patch_document_error'] = __( "Payment required. Message: $error_message", 'lingotek-translation' );
165
+ update_option( 'lingotek_log_errors', $lingotek_log_errors, false );
166
  }
167
  return false;
168
  }
173
  * @since 0.1
174
  *
175
  * @param string $id document id
176
+ * @param array $args expects array with content
177
+ * @return bool|string false if something got wrong
178
  */
179
+ public function patch_document( $id, $args, $wp_id = null ) {
180
+ $lgtm = $GLOBALS['wp_lingotek']->model;
181
+ $document = $lgtm->get_group_by_id( $id );
182
+ $args = $unformatted_args = wp_parse_args( $args, array( 'format' => 'JSON' ) );
183
+ $title = isset( $args['title'] ) ? $args['title'] : $id;
184
+ $this->format_as_multipart( $args );
185
+ $response = $this->patch( $this->api_url . '/document/' . $id, $args );
186
+ $status_code = wp_remote_retrieve_response_code( $response );
187
+ $body = json_decode( wp_remote_retrieve_body( $response ) );
188
+ if ( $status_code == 400 && strpos( $body->messages[0], 'has previously been cancelled' ) ) {
189
+ // Document has been cancelled, re-upload the post
190
+ // Slug can't be empty or duplicated, so we prefix `disassociated` to show the document id is no longer associated with this post
191
+ $document->document_id = 'disassociated_' . $document->document_id;
192
+ unset( $document->desc_array['lingotek'] );
 
 
 
 
 
 
 
193
  $document->save();
194
+ return $lgtm->upload_post( $wp_id );
195
  }
196
+ if ( $status_code == 423 ) {
197
  $document->document_id = $body->next_document_id;
198
  $document->save();
199
+ return $this->patch_document( $body->next_document_id, $unformatted_args, $wp_id );
200
  }
201
 
202
  // We will handle patch errors separately. All we want to do is return the result of the current patch request to the user if payment is required
203
  // (although in theory this will never happen, because the WP model is document count based, and it will not allow them to upload documents until
204
  // they choose to buy more documents)
205
+ $this->update_patch_error_message( $response, $status_code, $title );
206
  // The current behavior sends no body, so we will just check to see if the body is empty for now in order to maintain current behavior
207
+ if ( empty( $body ) ) {
208
+ $success = ! is_wp_error( $response ) && 202 == wp_remote_retrieve_response_code( $response );
209
+ if ( $success ) {
210
+ Lingotek_Logger::info(
211
+ 'Document updated',
212
+ array(
213
+ 'document_id' => $id,
214
+ 'wp_id' => $wp_id,
215
+ )
216
+ );
217
  } else {
218
+ Lingotek_Logger::error(
219
+ 'Document failed to update',
220
+ array(
221
+ 'document_id' => $id,
222
+ 'wp_id' => $wp_id,
223
+ )
224
+ );
225
  }
226
  return $success;
227
+ }//end if
228
+
229
+ if ( $status_code == 410 ) {
230
+ Lingotek_Logger::info(
231
+ 'Document ID was archived, reuploading document',
232
+ array(
233
+ 'old_document_id' => $id,
234
+ 'wp_id' => $wp_id,
235
+ 'args' => $args,
236
+ )
237
+ );
238
+ $targets = array_keys( $document->translations );
239
  $unformatted_args['translation_locale_code'] = $targets;
240
+ $this->format_args_for_upload( $unformatted_args, $wp_id );
241
+ foreach ( $document->translations as $locale ) {
242
+ $document->translations[ $locale ] = 'pending';
243
  }
244
+ $document->document_id = 'disassociated_' . $document->document_id;
245
+ unset( $document->desc_array['lingotek'] );
246
  $document->save();
247
+ return $this->upload_document( $unformatted_args, $wp_id );
248
  }
249
+ if ( $status_code == 402 ) {
250
+ Lingotek_Logger::error( 'There was an error updating WordPress item', array( 'error' => $this->get_error_message_from_response( $response ) ) );
251
  $document->source_failed();
252
+ return false;
253
  }
254
+ if ( $status_code == 202 && ! is_wp_error( $response ) ) {
255
+ Lingotek_Logger::info(
256
+ 'Document updated',
257
+ array(
258
+ 'old_document_id' => $id,
259
+ 'new_document_id' => $body->next_document_id,
260
+ 'wp_id' => $wp_id,
261
+ )
262
+ );
263
  $document->document_id = $body->next_document_id;
264
  $document->save();
265
  return $body->next_document_id;
266
  }
267
+ return false;
268
  }
269
 
270
+ private function format_args_for_upload( &$args, $wp_id ) {
271
+ $lgtm = $GLOBALS['wp_lingotek']->model;
272
+ $post = get_post( $wp_id );
273
+ $language = PLL()->model->post->get_language( $wp_id );
274
+ $project_id = $lgtm->get_profile_option( 'project_id', $post->post_type, $language, false, $wp_id );
275
+ $workflow_id = $lgtm->get_profile_option( 'workflow_id', $post->post_type, $language, false, $wp_id );
276
  $locale_code = $language->lingotek_locale;
277
+ unset( $args['format'] );
278
  $args['locale_code'] = $locale_code;
279
+ $args['project_id'] = $project_id;
280
  $args['workflow_id'] = $workflow_id;
281
  }
282
 
283
+ private function update_patch_error_message( $response, $status_code, $title ) {
284
  // Do not inform user if call was successful.
285
+ if ( $status_code == 202 || $status_code == 410 ) {
286
  return;
287
  }
288
+ $lingotek_log_errors = get_option( 'lingotek_log_errors', array() );
289
+ if ( ! is_array( $lingotek_log_errors ) ) {
290
  $lingotek_log_errors = array();
291
  }
292
+ $error_message = $this->get_error_message_from_response( $response ) !== false ?
293
+ $this->get_error_message_from_response( $response ) : 'No error message set by Lingotek.';
294
 
295
+ if ( $status_code == 402 ) {
296
+ $lingotek_log_errors['patch_document_error'] = __( "Payment required. Message: $error_message", 'lingotek-translation' );
297
+ } else {
298
+ $lingotek_log_errors['patch_document_error'] = __( "Error occurred while updating document $title. Message: $error_message", 'lingotek-translation' );
 
299
  }
300
+ update_option( 'lingotek_log_errors', $lingotek_log_errors );
301
  }
302
 
303
  /**
304
  * cancels a document
305
+ *
306
  * @since 1.4.2
307
+ *
308
  * @param string $id document id
309
  */
310
+ public function cancel_document( &$id, $wp_id = null ) {
311
+ $args = wp_parse_args( array( 'cancelled_reason' => 'CANCELLED_BY_AUTHOR' ) );
312
+ $response = $this->post( "$this->api_url/document/$id/cancel", $args );
313
+ if ( $wp_id ) {
314
+ $arr = get_option( 'lingotek_log_errors' );
315
+ if ( isset( $arr[ $wp_id ] ) ) {
316
+ unset( $arr[ $wp_id ] );
317
+ update_option( 'lingotek_log_errors', $arr, false );
318
  }
319
  }
320
+ $this->log_error_on_response_failure(
321
+ $response,
322
+ 'CancelDocument: Error occurred',
323
+ array(
324
+ 'id' => $id,
325
+ 'wordpress_id' => $wp_id,
326
+ )
327
+ );
328
+ $is_success = ! is_wp_error( $response ) && ( 204 == wp_remote_retrieve_response_code( $response ) || 202 == wp_remote_retrieve_response_code( $response ) );
329
+ $lgtm = $GLOBALS['wp_lingotek']->model;
330
+ $document = $lgtm->get_group_by_id( $id );
331
+ $current_status = $document->status;
332
  $document->status = 'cancelled';
333
+ if ( $is_success ) {
334
+ wp_remove_object_terms( $wp_id, "lingotek_hash_{$wp_id}", 'lingotek_hash' );
335
+ Lingotek_Logger::info(
336
+ 'Document cancelled',
337
+ array(
338
+ 'document_id' => $id,
339
+ 'wp_id' => $wp_id,
340
+ )
341
+ );
342
  $document->save();
343
  return $is_success;
344
+ } elseif ( 403 != wp_remote_retrieve_response_code( $response ) ) {
345
+ wp_remove_object_terms( $wp_id, "lingotek_hash_{$wp_id}", 'lingotek_hash' );
346
+ Lingotek_Logger::warning(
347
+ 'Document was not cancelled in TMS',
348
+ array(
349
+ 'document' => $id,
350
+ 'wp_id' => $wp_id,
351
+ )
352
+ );
353
+ // Slug can't be empty or duplicated, so we prefix `disassociated` to show the document id is no longer associated with this post
354
+ $document->document_id = $id = 'disassociated_' . $document->document_id;
355
  $document->save();
356
  return true;
357
+ }//end if
358
+ $document->status = $current_status;
359
+ $lingotek_log_errors = get_option( 'lingotek_log_errors', array() );
360
+ if ( ! is_array( $lingotek_log_errors ) ) {
361
  $lingotek_log_errors = array();
362
  }
363
+ $error_message = $this->get_error_message_from_response( $response ) !== false ?
364
+ $this->get_error_message_from_response( $response ) : 'No error message set by Lingotek.';
365
  $lingotek_log_errors['disassociate_document_error'] = $error_message;
366
+ update_option( 'lingotek_log_errors', $lingotek_log_errors, false );
367
  return $is_success;
368
  }
369
 
373
  *
374
  * @since 0.1
375
  */
376
+ public function get_document_ids( $args = array() ) {
377
+ $response = $this->get( add_query_arg( $args, $this->api_url . '/document' ) );
378
+ $ids = array();
379
 
380
+ if ( ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ) {
381
+ $documents = json_decode( wp_remote_retrieve_body( $response ) );
382
+ foreach ( $documents->entities as $doc ) {
383
  $ids[] = $doc->properties->id;
384
  }
385
  }
386
 
387
+ $this->log_error_on_response_failure( $response, 'GetDocumentIds: Error occured' );
388
  return $ids;
389
  }
390
 
391
+ public function get_document_count( $args = array() ) {
392
+ $response = $this->get( add_query_arg( $args, $this->api_url . '/document' ) );
393
+ $docs = array();
394
 
395
+ if ( ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ) {
396
+ $response = json_decode( wp_remote_retrieve_body( $response ) );
397
  return $response->properties->total;
398
  }
399
 
400
+ $this->log_error_on_response_failure( $response, 'GetDocumentCount: Error occured' );
401
  return null;
402
  }
403
 
406
  *
407
  * @since 0.1
408
  */
409
+ public function get_documents( $args = array() ) {
410
+ $response = $this->get( add_query_arg( $args, $this->api_url . '/document' ) );
411
+ $docs = array();
412
 
413
+ if ( ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ) {
414
+ $documents = json_decode( wp_remote_retrieve_body( $response ) );
415
+ foreach ( $documents->entities as $doc ) {
416
  $docs[] = $doc;
417
  }
418
  }
419
 
420
+ $this->log_error_on_response_failure( $response, 'GetDocuments: Error occured' );
421
  return $docs;
422
  }
423
 
426
  *
427
  * @since 0.1
428
  */
429
+ public function get_document( $doc_id ) {
430
+ $response = $this->get( $this->api_url . '/document/' . $doc_id );
431
 
432
+ if ( ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ) {
433
+ $document = json_decode( wp_remote_retrieve_body( $response ) );
434
  }
435
 
436
+ $this->log_error_on_response_failure( $response, 'GetDocument: Error occured' );
437
  return $document;
438
  }
439
 
440
+ public function get_document_status( $doc_id ) {
441
+ $imported = false;
442
+ $response = $this->get( $this->api_url . '/document/' . $doc_id . '/status' );
 
443
 
444
+ if ( ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ) {
445
+ $imported = true;
446
  }
447
 
448
+ $this->log_error_on_response_failure( $response, 'GetDocumentStatus: Error occured', array( 'document_id' => $doc_id ) );
449
  return $imported;
450
  }
451
 
458
  * @param string $id document id
459
  * @return string
460
  */
461
+ public function get_document_content( $doc_id ) {
462
+ $response = $this->get( $this->api_url . "/document/$doc_id/content" );
463
 
464
+ if ( ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ) {
465
  $content = wp_remote_retrieve_body( $response );
466
  }
467
 
468
+ $this->log_error_on_response_failure( $response, 'GetDocumentContent: Error occured', array( 'document_id' => $doc_id ) );
469
  return $content;
470
  }
471
 
478
  * @param string $locale locale
479
  * @return int with locale percent_complete
480
  */
481
+ public function get_translation_status( $doc_id, $locale ) {
482
+ $locale = Lingotek::map_to_lingotek_locale( $locale );
483
+ $status = -1;
484
+ $response = $this->get( $this->api_url . "/document/$doc_id/translation/$locale" );
485
+ if ( ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ) {
486
+ $b = json_decode( wp_remote_retrieve_body( $response ) );
487
  $status = $b->properties->percent_complete;
488
  }
489
 
490
+ $this->log_error_on_response_failure(
491
+ $response,
492
+ 'GetTranslationStatus: Error occurred',
493
+ array(
494
+ 'document_id' => $doc_id,
495
+ 'locale' => $locale,
496
+ )
497
+ );
498
  return $status;
499
  }
500
 
506
  * @param string $id document id
507
  * @return array with locale as key and status as value
508
  */
509
+ public function get_translations_status( $doc_id, $wp_id = null ) {
510
+ $response = $this->get( $this->api_url . '/document/' . $doc_id . '/translation' );
511
+ if ( ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ) {
512
+ $b = json_decode( wp_remote_retrieve_body( $response ) );
513
+ foreach ( $b->entities as $e ) {
514
+ if ( $e->properties->status != 'CANCELLED' ) {
515
  // cancelled is in a completed state, but it does not mean the translation is 100% complete
516
+ $translations[ $e->properties->locale_code ] = array(
517
+ 'progress' => $e->properties->status,
518
+ 'percent_complete' => $e->properties->percent_complete,
519
+ );
520
  }
521
  }
522
  }
523
 
524
+ Lingotek_Logger::info(
525
+ 'Translation status requested',
526
+ array(
527
+ 'document_id' => $doc_id,
528
+ 'wp_id' => $wp_id,
529
+ 'translations' => isset( $translations ) ? $translations : '',
530
+ )
531
+ );
532
+
533
  $this->update_lingotek_error_option(
534
+ $response,
535
+ $wp_id,
536
+ 'get_translations_status',
537
+ sprintf( __( 'There was an error updating the translations status for WordPress item %1$s', 'lingotek-translation' ), $wp_id ),
538
+ array( 'document_id' => $doc_id )
539
+ );
540
 
541
+ return empty( $translations ) ? array() : $translations;
542
  }
543
 
544
 
545
+ public function get_language_mappings() {
546
+ $url = 'https://gmc.lingotek.com/v1/locales';
547
+ $response = $this->get( $url );
548
+ return json_decode( wp_remote_retrieve_body( $response ), true );
 
549
  }
550
 
551
  /**
552
+ * Makes an API call to bridge to get the estimated cost for translating a particular document professionally.
553
+ *
554
+ * @param string $lingotek_auth the auth token to make an API call to bridge.
555
+ * @param string $document_id the id of the specific document.
556
+ * @param string $locale the locale of the document being requested.
557
+ */
558
+ public function get_cost_estimate( $lingotek_auth, $document_id, $locale ) {
559
  $this->start_bridge_call();
560
 
561
+ $args = array(
562
  'document_id' => $document_id,
563
+ 'locale' => $locale,
564
  );
565
+ $response = $this->get( $this->bridge_url . 'estimate', $args );
566
 
567
+ $success = 200 === wp_remote_retrieve_response_code( $response );
568
 
569
  $this->end_bridge_call();
570
 
571
+ $this->log_error_on_response_failure(
572
+ $response,
573
+ 'GetCostEstimate: Error occured',
574
+ array(
575
+ 'document_id' => $document_id,
576
+ 'locale' => $locale,
577
+ )
578
+ );
579
+ return array(
580
+ 'success' => $success,
581
+ 'data' => $this->get_response_body_from_bridge( $response ),
582
+ );
583
  }
584
 
585
  /**
586
+ * Makes an API call to bridge request translation for a document using the professional workflow.
587
+ *
588
+ * @param string $document_id the id of the specific document.
589
+ * @param string $locale the locale of the document being requested.
590
+ * @param string $workflow_id the id used to process the document.
591
+ */
592
+ public function request_professional_translation( $document_id, $locale, $workflow_id ) {
593
  $this->start_bridge_call();
594
+
595
+ $args = array(
596
  'document_id' => $document_id,
597
+ 'locale' => $locale,
598
  'workflow_id' => $workflow_id,
599
  );
600
+ $response = $this->post( $this->bridge_url . 'request', $args );
601
+ $success = 200 === wp_remote_retrieve_response_code( $response );
602
 
603
  $this->end_bridge_call();
604
 
605
+ if ( $success ) {
606
+ Lingotek_Logger::info(
607
+ 'Professional translation requested',
608
+ array(
609
+ 'document_id' => $document_id,
610
+ 'locale' => $locale,
611
+ 'wordflow_id' => $workflow_id,
612
+ )
613
+ ); }
614
+ $this->log_error_on_response_failure(
615
+ $response,
616
+ 'RequestProfessionalTranslation: Error occured',
617
+ array(
618
+ 'document_id' => $document_id,
619
+ 'locale' => $locale,
620
+ 'workflow_id' => $workflow_id,
621
+ )
622
+ );
623
 
624
+ return array(
625
+ 'success' => $success,
626
+ 'data' => $this->get_response_body_from_bridge( $response ),
627
+ );
628
  }
629
 
630
  /**
631
+ * Makes an API call to bridge request bulk translations for a document using the professional workflow.
632
+ *
633
+ * @param string $document_id the id of the specific document.
634
+ * @param string $locale the locale of the document being requested.
635
+ * @param string $workflow_id the id used to process the document.
636
+ */
637
+ public function request_professional_translation_bulk( $workflow_id, $translations, $total_estimate, $summary ) {
638
  $this->start_bridge_call();
639
+
640
+ $args = array(
641
+ 'workflow_id' => $workflow_id,
642
+ 'translations' => $translations,
643
  'total_estimate' => $total_estimate,
644
+ 'summary' => $summary,
645
  );
646
+ $response = $this->post( $this->bridge_url . 'request/bulk', $args, 60 );
647
+ $success = 200 === wp_remote_retrieve_response_code( $response );
648
 
649
  $this->end_bridge_call();
650
 
651
+ if ( $success ) {
652
+ Lingotek_Logger::info(
653
+ 'Professional translation (bulk) requested',
654
+ array(
655
+ 'translations' => $translations,
656
+ 'wordflow_id' => $workflow_id,
657
+ )
658
+ ); }
659
+ $this->log_error_on_response_failure(
660
+ $response,
661
+ 'RequestProfessionalTranslationBulk: Error occured',
662
+ array(
663
+ 'translations' => $translations,
664
+ 'total_estimate' => $total_estimate,
665
+ 'workflow_id' => $workflow_id,
666
+ )
667
+ );
668
 
669
+ return array( 'data' => $this->get_response_body_from_bridge( $response ) );
670
  }
671
 
672
 
673
  public function get_lingotek_terms_and_conditions() {
674
  $this->start_bridge_call();
675
+ $response = $this->get( BRIDGE_URL . '/api/v2/transaction/terms/' );
676
+ $success = 200 === wp_remote_retrieve_response_code( $response );
677
  $this->end_bridge_call();
678
 
679
+ $this->log_error_on_response_failure( $response, 'GetLingotekTermsAndConditions: Error occured' );
680
+ return array(
681
+ 'success' => $success,
682
+ 'data' => $this->get_response_body_from_bridge( $response ),
683
+ );
684
  }
685
 
686
  /**
687
+ * Makes an API call to bridge to get the payment information about the user.
688
+ */
689
  public function get_user_payment_information() {
690
  $this->start_bridge_call();
691
 
692
+ $response = $this->get( BRIDGE_URL . '/api/v2/transaction/payment' );
693
+ $success = 200 === wp_remote_retrieve_response_code( $response );
694
 
695
  $this->end_bridge_call();
696
 
697
+ $this->log_error_on_response_failure( $response, 'GetUserPaymentInformation: Error occured' );
698
+ return array(
699
+ 'success' => $success,
700
+ 'payment_info' => $this->get_response_body_from_bridge( $response ),
701
+ );
702
  }
703
 
704
  /**
705
+ * Helper function to retrieve the response body from bridge.
706
+ *
707
+ * @param array $response the response from bridge.
708
+ */
709
+ private function get_response_body_from_bridge( $response ) {
710
+ $body = json_decode( wp_remote_retrieve_body( $response ), true );
711
+ return isset( $body ) ? $body : wp_remote_retrieve_body( $response );
 
712
  }
713
 
714
  /**
718
  *
719
  * @param string $id document id
720
  * @param string $locale Lingotek locale
721
+ * @param array $args optional arguments (only workflow_id at the moment)
722
  * @return bool true if the request succeeded
723
  */
724
+ public function request_translation( $id, $locale, $args = array(), $wp_id = null ) {
725
+ $lgtm = $GLOBALS['wp_lingotek']->model;
726
+ $document = $lgtm->get_group_by_id( $id );
727
+ $locale = Lingotek::map_to_lingotek_locale( $locale );
728
+ $args = $unformatted_args = wp_parse_args( $args, array( 'workflow_id' => $this->get_workflow_id() ) );
729
+ $args = array_merge( array( 'locale_code' => $locale ), $args );
730
+ $response = $this->post( $this->api_url . '/document/' . $id . '/translation', $args );
731
+ $title = isset( $args['title'] ) ? $args['title'] : $id;
732
+ if ( $wp_id ) {
733
+ $arr = get_option( 'lingotek_log_errors', array() );
734
+ $status_code = wp_remote_retrieve_response_code( $response );
735
+ $body = json_decode( wp_remote_retrieve_body( $response ) );
736
+ $this->update_patch_error_message( $response, $status_code, $title );
737
+ if ( 423 === $status_code ) {
738
  $document->document_id = $body->next_document_id;
739
  $document->save();
740
+ return $this->request_translation( $body->next_document_id, $locale, $unformatted_args, $wp_id );
741
  }
742
+ if ( 402 === $status_code ) {
743
+ Lingotek_Logger::error( 'There was an error updating WordPress item', array( 'error' => $this->get_error_message_from_response( $response ) ) );
744
  $document->source_failed();
745
  return false;
746
  }
747
+ if ( 410 === $status_code ) {
748
  // WP hooks automatically check source status so this might not get called
749
+ $targets = array_keys( $document->translations );
750
+ $targets[] = $locale;
751
  $unformatted_args['translation_locale_code'] = $targets;
752
+ $this->format_args_for_upload( $unformatted_args, $wp_id );
753
+ unset( $document->desc_array['lingotek'] );
754
  $document->save();
755
+ foreach ( $document->translations as $locale ) {
756
+ $document->translations[ $locale ] = 'pending';
757
  }
758
+ return $this->upload_document( $unformatted_args, $wp_id );
759
  }
760
+ if ( 400 === $status_code &&
761
+ ! empty( $body->messages ) &&
762
+ strpos( $body->messages[0], 'already exists' ) ) {
763
  // Translation has already been requested, treat it as a 201 response
764
  $status_code = 201;
765
  }
766
+ if ( 201 === $status_code ) {
767
+ if ( isset( $arr[ $wp_id ] ) ) {
768
+ unset( $arr[ $wp_id ]['wp_error'] );
769
+ unset( $arr[ $wp_id ]['request_translation'][ $locale ] );
770
+ if ( empty( $arr[ $wp_id ] ) ) {
771
+ unset( $arr[ $wp_id ] );
772
  }
773
  }
774
+ } elseif ( is_wp_error( $response ) ) {
775
+ $arr[ $wp_id ]['wp_error'] = __( 'Make sure you have internet connectivity', 'lingotek-translation' );
776
+ } elseif ( 400 == $status_code || 404 == $status_code ) {
777
+ $arr[ $wp_id ]['request_translation'][ $locale ] = sprintf(
778
+ __( 'There was an error requesting translation %1$s for WordPress item %2$s', 'lingotek-translation' ),
779
+ $locale,
780
+ $wp_id
781
  );
782
  }
783
+ update_option( 'lingotek_log_errors', $arr, false );
784
+ }//end if
785
+ if ( 201 !== $status_code ) {
786
+ $this->log_error_on_response_failure(
787
+ $response,
788
+ 'RequestTranslation: Error Occurred',
789
+ array(
790
+ 'document_id' => $id,
791
+ 'locale' => $locale,
792
+ 'args' => $args,
793
+ )
794
+ );
795
  }
796
+ return ! is_wp_error( $response ) && 201 === $status_code;
 
 
 
797
  }
798
 
799
  /**
805
  * @param string $locale Lingotek locale
806
  * @return string|bool the translation, false if there is none
807
  */
808
+ public function get_translation( $doc_id, $locale, $wp_id = null ) {
809
+ $locale = Lingotek::map_to_lingotek_locale( $locale );
810
+
811
+ $response = $this->get(
812
+ add_query_arg(
813
+ array(
814
+ 'locale_code' => $locale,
815
+ 'auto_format' => 'true',
816
+ ),
817
+ $this->api_url . '/document/' . $doc_id . '/content'
818
+ )
819
+ );
820
 
821
+ if ( $wp_id ) {
822
+ $arr = get_option( 'lingotek_log_errors' );
823
+ $status_code = wp_remote_retrieve_response_code( $response );
824
+ if ( 410 == $status_code ) {
825
+ $lgtm = $GLOBALS['wp_lingotek']->model;
826
+ $document = $lgtm->get_group_by_id( $doc_id );
827
  $document->source_failed();
828
  //TODO IS THIS SETTING ERROR PROPERLY?
829
+ $arr[ $wp_id ]['wp_error'] = __( "Document $doc_id has been archived. Please re-upload source", 'lingotek-translation' );
830
  return false;
831
+ } elseif ( 200 == $status_code ) {
832
+ if ( isset( $arr[ $wp_id ] ) ) {
833
+ unset( $arr[ $wp_id ]['wp_error'] );
834
+ unset( $arr[ $wp_id ]['get_translation'][ $locale ] );
835
+ if ( empty( $arr[ $wp_id ] ) ) {
836
+ unset( $arr[ $wp_id ] );
837
  }
838
  }
839
+ } elseif ( is_wp_error( $response ) ) {
840
+ $arr[ $wp_id ]['wp_error'] = __( 'Make sure you have internet connectivity', 'lingotek-translation' );
841
+ } elseif ( 400 == $status_code || 404 == $status_code ) {
842
+ $arr[ $wp_id ]['get_translation'][ $locale ] = sprintf(
843
+ __( 'There was an error downloading translation %1$s for WordPress item %2$s' ),
844
+ $locale,
845
+ $wp_id
846
  );
847
+ }//end if
848
+ update_option( 'lingotek_log_errors', $arr, false );
849
+ }//end if
850
+ $this->log_error_on_response_failure(
851
+ $response,
852
+ 'GetTranslation: Error Occurred',
853
+ array(
854
+ 'document_id' => $doc_id,
855
+ 'locale' => $locale,
856
+ )
857
+ );
858
+ return ! is_wp_error( $response ) && 200 == $status_code ? wp_remote_retrieve_body( $response ) : false;
859
  }
860
 
861
  /**
862
  * cancels a translation
863
+ *
864
  * @since 1.4.2
865
+ *
866
  * @param string $id document id
867
  * @param string $locale Lingotek locale
868
  */
869
+ public function cancel_translation( $id, $locale, $wp_id = null ) {
870
+ $args = wp_parse_args(
871
+ array(
872
+ 'cancelled_reason' => 'CANCELLED_BY_AUTHOR',
873
+ 'mark_invoiceable' => true,
874
+ )
875
+ );
876
+ $response = $this->post( "$this->api_url/document/$id/translation/$locale/cancel", $args );
877
+
878
+ if ( $wp_id ) {
879
+ $arr = get_option( 'lingotek_log_errors' );
880
+ if ( isset( $arr[ $wp_id ] ) ) {
881
+ unset( $arr[ $wp_id ] );
882
+ update_option( 'lingotek_log_errors', $arr, false );
883
  }
884
  }
885
+ $this->log_error_on_response_failure(
886
+ $response,
887
+ 'CancelTranslation: Error occurred',
888
+ array(
889
+ 'id' => $id,
890
+ 'wordpress_id' => $wp_id,
891
+ )
892
+ );
893
+ $is_success = ! is_wp_error( $response ) && ( 204 == wp_remote_retrieve_response_code( $response ) || 202 == wp_remote_retrieve_response_code( $response ) );
894
+ if ( $is_success ) {
895
+ Lingotek_Logger::info(
896
+ 'Target cancelled',
897
+ array(
898
+ 'document_id' => $id,
899
+ 'wp_id' => $wp_id,
900
+ )
901
+ );
902
  return $is_success;
903
  }
904
+ $lingotek_log_errors = get_option( 'lingotek_log_errors', array() );
905
+ if ( ! is_array( $lingotek_log_errors ) ) {
906
  $lingotek_log_errors = array();
907
  }
908
  // Use the response message if it's an authorization error
909
+ $response_error_message = 403 == wp_remote_retrieve_response_code( $response ) && $this->get_error_message_from_response( $response ) !== false ?
910
+ $this->get_error_message_from_response( $response ) : false;
911
+ $error_message = $response_error_message ? $response_error_message : "{$locale} was already completed in the TMS and cannot be cancelled unless the entire document is cancelled.";
912
  $lingotek_log_errors['disassociate_document_error'] = $error_message;
913
+ update_option( 'lingotek_log_errors', $lingotek_log_errors, false );
914
 
915
  return $is_success;
916
  }
921
  * @param string $redirect_uri the location where to redirect to after account has been connected
922
  * @return string the complete url for the connect account link
923
  */
924
+ public function get_connect_url( $redirect_uri, $env = null ) {
925
+ $base_url = $this->base_url;
926
  $client_id = $this->client_id;
927
+ if ( ! is_null( $env ) ) {
928
  $base_url = self::PRODUCTION_URL;
929
  }
930
+ return "$base_url/auth/authorize.html?client_id=$client_id&redirect_uri=" . urlencode( $redirect_uri ) . '&response_type=token';
931
  }
932
 
933
+ public function get_new_url( $redirect_uri ) {
934
+ $base_url = self::PRODUCTION_URL;
935
  $client_id = $this->client_id;
936
+ return "$base_url/lingopoint/portal/requestAccount.action?client_id=$client_id&app=" . urlencode( $redirect_uri ) . '&response_type=token';
 
937
  }
938
 
939
  public function get_communities() {
940
+ $response = $this->get( add_query_arg( array( 'limit' => 1000 ), $this->api_url . '/community' ) );
941
+ return ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ? json_decode( wp_remote_retrieve_body( $response ) ) : false;
942
  }
943
 
944
+ public function get_projects( $community_id ) {
945
+ $response = $this->get(
946
+ add_query_arg(
947
+ array(
948
+ 'community_id' => $community_id,
949
+ 'limit' => 1000,
950
+ ),
951
+ $this->api_url . '/project'
952
+ )
953
+ );
954
+ if ( wp_remote_retrieve_response_code( $response ) == 204 ) {
955
+ // There are currently no projects.
956
+ return array();
957
  }
958
+ return ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ? json_decode( wp_remote_retrieve_body( $response ) ) : false;
959
  }
960
 
961
+ public function get_vaults( $community_id ) {
962
+ $response = $this->get(
963
+ add_query_arg(
964
+ array(
965
+ 'community_id' => $community_id,
966
+ 'limit' => 1000,
967
+ ),
968
+ $this->api_url . '/vault'
969
+ )
970
+ );
971
+ return ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ? json_decode( wp_remote_retrieve_body( $response ) ) : false;
972
  }
973
 
974
+ public function get_workflows( $community_id ) {
975
+ $response = $this->get(
976
+ add_query_arg(
977
+ array(
978
+ 'community_id' => $community_id,
979
+ 'limit' => 1000,
980
+ ),
981
+ $this->api_url . '/workflow'
982
+ )
983
+ );
984
+ return ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ? json_decode( wp_remote_retrieve_body( $response ) ) : false;
985
  }
986
 
987
  public function get_filters() {
988
+ $response = $this->get( add_query_arg( array( 'limit' => 1000 ), $this->api_url . '/filter' ) );
989
+ return ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ? json_decode( wp_remote_retrieve_body( $response ) ) : false;
990
  }
991
 
992
+ public function upload_filter( $name, $type, $content ) {
993
+ $args = array(
994
+ 'name' => $name,
995
+ 'type' => $type,
996
+ 'content' => $content,
997
+ );
998
+ $response = $this->post( "$this->api_url/filter", $args );
999
  }
1000
 
1001
  private function start_bridge_call() {
1002
  $this->auth_temp = $this->headers['Authorization'];
1003
+ unset( $this->headers['Authorization'] );
1004
+ $option = get_option( 'lingotek_token' );
1005
  $this->headers['Authorization-Lingotek'] = $option['access_token'];
1006
  }
1007
 
1008
  private function end_bridge_call() {
1009
+ unset( $this->headers['Authorization-Lingotek'] );
1010
  $this->headers['Authorization'] = $this->auth_temp;
1011
  }
1012
 
1015
  }
1016
 
1017
  /**
1018
+ * Helper function to update lingotek errors as 'lingotek_log_errors' option in case of translation actions (get / request).
1019
+ *
1020
+ * @param $response the response from the action (wp_remote_*).
1021
+ * @param $wp_id id that represents the object in the WP world (post_id / term_id / etc)
1022
+ * @param $action the name of the action performed (for ex 'reqeust_translation')
1023
+ * @param $error_message the message to write in case the response indicates failure
1024
+ * @param $locale the locale the translation action was performed on
1025
+ * @param $extra_data (optional) array of key/value pairs that will be sent as part of the error
1026
+ */
1027
+ private function update_lingotek_error_option_for_translation( $response, $wp_id, $action, $error_message, $locale, $extra_data = array() ) {
1028
+ if ( $wp_id ) {
1029
+ $arr = get_option( 'lingotek_log_errors' );
1030
+ $response_message_code = wp_remote_retrieve_response_code( $response );
1031
+ if ( 200 == $response_message_code || 201 == $response_message_code ) {
1032
+ if ( isset( $arr[ $wp_id ] ) ) {
1033
+ unset( $arr[ $wp_id ]['wp_error'] );
1034
+ unset( $arr[ $wp_id ][ $action ][ $locale ] );
1035
+ if ( empty( $arr[ $wp_id ] ) ) {
1036
+ unset( $arr[ $wp_id ] );
1037
  }
1038
  }
1039
+ } elseif ( is_wp_error( $response ) ) {
1040
+ $arr[ $wp_id ]['wp_error'] = __( 'Make sure you have internet connectivity', 'lingotek-translation' );
1041
+ Lingotek_Logger::error(
1042
+ $action . ': WordPress error occured, please make sure you have internet connectivity',
1043
+ array_merge(
1044
+ array(
1045
+ 'http_status' => $response_message_code,
1046
+ 'wordpress_id' => $wp_id,
1047
+ ),
1048
+ $extra_data
1049
+ )
1050
+ );
1051
+ } elseif ( 400 == $response_message_code || 404 == $response_message_code ) {
1052
+ $arr[ $wp_id ][ $action ][ $locale ] = $error_message;
1053
+ Lingotek_Logger::error(
1054
+ $action . ': Error occured',
1055
+ array_merge(
1056
+ array(
1057
+ 'response_message_code' => $response_message_code,
1058
+ 'wordpress_id' => $wp_id,
1059
+ 'response_message' => $this->get_error_message_from_response( $response ),
1060
+ ),
1061
+ $extra_data
1062
+ )
1063
+ );
1064
+ }//end if
1065
+ update_option( 'lingotek_log_errors', $arr, false );
1066
+ }//end if
1067
  }
1068
 
1069
  /**
1070
+ * Helper function to update lingotek errors as 'lingotek_log_errors' option.
1071
+ *
1072
+ * @param $response the response from the action (wp_remote_*).
1073
+ * @param $wp_id id that represents the object in the WP world (post_id / term_id / etc)
1074
+ * @param $action the name of the action performed (for ex 'reqeust_translation')
1075
+ * @param $error_message the message to write in case the response indicates failure
1076
+ * @param $extra_data (optional) array of key/value pairs that will be sent as part of the error
1077
+ */
1078
+ private function update_lingotek_error_option( $response, $wp_id, $action, $error_message, $extra_data = array() ) {
1079
+ if ( $wp_id ) {
1080
+ $arr = get_option( 'lingotek_log_errors' );
1081
+ $response_message_code = wp_remote_retrieve_response_code( $response );
1082
+ if ( empty( $arr ) ) {
1083
  return;
1084
  }
1085
 
1086
+ if ( 200 == $response_message_code || 202 == $response_message_code ) {
1087
+ if ( isset( $arr[ $wp_id ] ) ) {
1088
+ unset( $arr[ $wp_id ] );
1089
  }
1090
+ } elseif ( is_wp_error( $response ) ) {
1091
+ $arr[ $wp_id ]['wp_error'] = __( 'Make sure you have internet connectivity', 'lingotek-translation' );
1092
+ Lingotek_Logger::error(
1093
+ "$action: WordPress error occured, please make sure you have internet connectivity",
1094
+ array_merge(
1095
+ array(
1096
+ 'http_status' => $response_message_code,
1097
+ 'wordpress_id' => $wp_id,
1098
+ ),
1099
+ $extra_data
1100
+ )
1101
+ );
1102
+ } elseif ( 400 == $response_message_code || 404 == $response_message_code ) {
1103
+ $arr[ $wp_id ][ $action ] = $error_message;
1104
+ Lingotek_Logger::error(
1105
+ "$action: Error occured",
1106
+ array_merge(
1107
+ array(
1108
+ 'http_status' => $response_message_code,
1109
+ 'wordpress_id' => $wp_id,
1110
+ 'response_message' => $this->get_error_message_from_response( $response ),
1111
+ ),
1112
+ $extra_data
1113
+ )
1114
+ );
1115
+ }//end if
1116
+ update_option( 'lingotek_log_errors', $arr, false );
1117
+ }//end if
1118
  }
1119
 
1120
  /**
1121
+ * Helper function to send error log entry to Lingotek_Logger in case the response indicates failure.
1122
+ * Failure response has http status different than 200/201/202/204 and is not wp_error response
1123
+ *
1124
+ * @param $response the response from the action (wp_remote_*).
1125
+ * @param $error_message the message to write in case the response indicates failure
1126
+ * @param $extra_data (optional) array of key/value pairs that will be sent as part of the error
1127
+ */
1128
+ private function log_error_on_response_failure( $response, $error_message, $extra_data = array() ) {
1129
+ $http_code = wp_remote_retrieve_response_code( $response );
1130
+ $success = 200 === $http_code || 201 === $http_code || 202 === $http_code || 204 === $http_code;
1131
+ if ( ! $success || is_wp_error( $response ) ) {
1132
+ Lingotek_Logger::error(
1133
+ $error_message,
1134
+ array_merge(
1135
+ array(
1136
+ 'http_status' => $http_code,
1137
+ $extra_data,
1138
+ )
1139
+ )
1140
+ );
1141
+ }
1142
+ }
1143
+
1144
+ private function get_error_message_from_response( $response ) {
1145
+ $responseBody = json_decode( wp_remote_retrieve_body( $response ) );
1146
+ if ( empty( $responseBody ) ) {
1147
  return false;
1148
  }
1149
+ return property_exists( $responseBody, 'messages' ) && is_array( $responseBody->messages ) ? implode( ' ', $responseBody->messages ) : false;
1150
  }
1151
+ }
include/callback.php CHANGED
@@ -13,9 +13,9 @@ class Lingotek_Callback {
13
  *
14
  * @since 0.1
15
  */
16
- public function __construct(&$model) {
17
  $this->lgtm = &$model;
18
- add_filter('request', array(&$this, 'request'));
19
  }
20
 
21
  /*
@@ -23,174 +23,179 @@ class Lingotek_Callback {
23
  *
24
  * @since 0.1
25
  *
26
- * @param array $query_vars query vars known to WordPres
27
  * @return array unmodified query vars if the request is not a Lingotek callback
28
  */
29
- public function request($query_vars) {
30
- if (empty($query_vars['lingotek'])) {
31
  return $query_vars;
32
  }
33
  $type = $_GET['type'];
34
- if (isset($type, $_GET['document_id']) && $document = $this->lgtm->get_group_by_id($_GET['document_id'])) {
35
- switch ($type) {
36
  case 'get':
37
- $this->handleGet($document);
38
  break;
39
  case 'target':
40
  case 'phase':
41
- $this->handleTargetOrPhase($document, $type);
 
42
  break;
43
  case 'target_cancelled':
44
- $this->handleTargetCancelled($document);
45
  break;
46
  case 'document_uploaded':
47
  case 'document_updated':
48
- $this->handleDocumentUploadedOrUpdated($document);
49
  break;
50
  case 'import_failure':
51
- $this->handleImportFailure($document);
52
  break;
53
  case 'document_archived':
54
  case 'document_deleted':
55
- $this->handleDocumentArchivedOrDeleted($document);
56
  break;
57
  case 'document_cancelled';
58
- $this->handleDocumentCancelled($document);
59
  break;
60
  default:
61
- Lingotek_Logger::info('Callback received, no handler for type', array('Type' => $type));
62
- }
63
- status_header(200); // useless as it the default value
 
64
  die();
65
- }
66
- status_header(404); // no document found
 
67
  die();
68
  }
69
 
70
- public function handleGet($document) {
71
  // url for in context review
72
- if (isset($_GET['locale'])) {
73
- $locale = Lingotek::map_to_wp_locale($_GET['locale']); // map to WP locale
74
- Lingotek_Logger::info('Callback received', array('Callback Parameters' => $_GET));
 
75
  // posts
76
- if (post_type_exists($document->type)) {
77
- if ($id = PLL()->model->post->get($document->source, $locale)) {
78
- wp_redirect(get_permalink($id), 301);
79
  exit();
80
- }
81
- else {
82
- wp_redirect(get_permalink($document->source), 302);
83
  exit();
84
  }
85
  }
86
  // taxonomy terms
87
- elseif (taxonomy_exists($document->type) && $id = $document->pllm->get_term($document->source, $locale)) {
88
- wp_redirect(get_term_link($id, $document->type), 301);
89
  exit();
90
  }
91
 
92
- status_header(404); // no document found
 
93
  die();
94
- }
95
  }
96
 
97
- public function handleTargetOrPhase($document, $type) {
98
- if (isset($_GET['locale'])) {
99
  $callback_parameters = array(
100
- 'Target Locale' => isset($_GET['locale_code']) ? $_GET['locale_code'] : NULL,
101
- 'Phase Name' => isset($_GET['phase_name']) ? $_GET['phase_name'] : NULL,
102
- 'Status' => isset($_GET['status']) ? $_GET['status'] : NULL,
103
- 'Document ID' => isset($_GET['document_id']) ? $_GET['document_id'] : NULL,
104
- 'Project ID' => isset($_GET['projectId']) ? (int)$_GET['projectId'] : NULL,
105
- 'Community ID' => isset($_GET['community_id']) ? $_GET['community_id'] : NULL,
106
- 'Progress' => isset($_GET['progress']) ? (int)$_GET['progress'] : NULL,
107
- 'Complete' => isset($_GET['complete']) ? $_GET['complete'] : NULL,
108
- 'Type' => isset($_GET['type']) ? $_GET['type'] : NULL,
109
- 'Document Status' => isset($_GET['doc_status']) ? $_GET['doc_status'] : NULL,
110
  );
111
- Lingotek_Logger::info('Callback received', array('Callback Parameters' => $callback_parameters));
112
  // We will need access to PLL_Admin_Sync::copy_post_metas
113
  global $polylang;
114
- $polylang->sync = new PLL_Admin_Sync($polylang);
115
- $locale = Lingotek::map_to_wp_locale($_GET['locale']); // map to WP locale
116
- $document->is_automatic_download($locale) ? $document->create_translation($locale, true, $type) : $document->translation_ready($locale);
117
- }
 
118
  }
119
 
120
- public function handleDocumentUploadedOrUpdated($document) {
121
  $document->source_ready();
122
  $callback_parameters = array(
123
- 'Document ID' => isset($_GET['document_id']) ? $_GET['document_id'] : NULL,
124
- 'Project ID' => isset($_GET['projectId']) ? (int)$_GET['projectId'] : NULL,
125
- 'Community ID' => isset($_GET['community_id']) ? $_GET['community_id'] : NULL,
126
- 'Progress' => isset($_GET['progress']) ? (int)$_GET['progress'] : NULL,
127
- 'Complete' => isset($_GET['complete']) ? $_GET['complete'] : NULL,
128
- 'Type' => isset($_GET['type']) ? $_GET['type'] : NULL,
129
- 'Document Status' => isset($_GET['doc_status']) ? $_GET['doc_status'] : NULL,
130
  );
131
- Lingotek_Logger::info('Callback received', array('Callback Parameters' => $callback_parameters));
132
- if ($document->is_automatic_upload()) {
133
  $document->request_translations();
134
  }
135
  }
136
 
137
- public function handleImportFailure($document) {
138
  $callback_parameters = array(
139
- 'Document ID' => isset($_GET['document_id']) ? $_GET['document_id'] : NULL,
140
- 'Type' => isset($_GET['type']) ? $_GET['type'] : NULL,
141
  );
142
- if (isset($_GET['prev_document_id'])) {
143
- Lingotek_Logger::info("Document update failed. Reverting to previous id", $callback_parameters);
144
  $document->id = $_GET['prev_document_id'];
145
  }
146
- Lingotek_Logger::info('Callback received', array('Callback Parameters' => $callback_parameters));
147
  $document->source_failed();
148
  }
149
-
150
- public function handleDocumentArchivedOrDeleted($document) {
151
- $callback_parameters = array (
152
- 'Document ID' => isset($_GET['document_id']) ? $_GET['document_id'] : NULL,
153
- 'Type' => isset($_GET['type']) ? $_GET['type'] : NULL,
154
  );
155
- Lingotek_Logger::info('Callback received', array('Callback Parameters' => $callback_parameters));
156
- $wp_id = isset($document->desc_array['lingotek']['source']) ? $document->desc_array['lingotek']['source'] : NULL;
157
- unset($document->desc_array['lingotek']);
158
  $document->document_id = '';
159
  $document->save();
160
- wp_remove_object_terms($wp_id, "lingotek_hash_{$wp_id}", "lingotek_hash");
161
  }
162
 
163
- public function handleDocumentCancelled($document) {
164
  $callback_parameters = array(
165
- 'Document ID' => isset($_GET['document_id']) ? $_GET['document_id'] : NULL,
166
- 'Type' => isset($_GET['type']) ? $_GET['type'] : NULL,
167
  );
168
- if (isset($document->desc_array['lingotek']['translations']) && count($document->desc_array['lingotek']['translations']) > 0 ) {
169
- unset($document->desc_array['lingotek']['translations']);
170
  $document->desc_array['lingotek']['status'] = 'cancelled';
171
  } else {
172
- unset($document->desc_array['lingotek']);
173
  }
174
- $wp_id = isset($document->desc_array['lingotek']['source']) ? $document->desc_array['lingotek']['source'] : NULL;
175
  $document->status = 'cancelled';
176
  $document->save();
177
- wp_remove_object_terms($wp_id, "lingotek_hash_{$wp_id}", "lingotek_hash");
178
- Lingotek_Logger::info('Callback Received', array('Callback Parameters' => $callback_parameters));
179
  }
180
 
181
- public function handleTargetCancelled($document) {
182
  $callback_parameters = array(
183
- 'Document ID' => isset($_GET['document_id']) ? $_GET['document_id'] : NULL,
184
- 'Type' => isset($_GET['type']) ? $_GET['type'] : NULL,
185
- 'Locale' => isset($_GET['locale']) ? $_GET['locale'] : NULL,
186
  );
187
- $locale = Lingotek::map_to_wp_locale($_GET['locale']); // map to WP locale
188
- if (!isset($document->desc_array['lingotek']['translations'][$locale])) {
 
189
  $document->desc_array['lingotek']['translations'][] = $locale;
 
190
  }
191
- $document->desc_array['lingotek']['translations'][$locale] = 'cancelled';
192
- $document->save();
193
- Lingotek_Logger::info('Callback received', array('Callback Parameters' => $callback_parameters));
194
  }
195
-
196
  }
13
  *
14
  * @since 0.1
15
  */
16
+ public function __construct( &$model ) {
17
  $this->lgtm = &$model;
18
+ add_filter( 'request', array( &$this, 'request' ) );
19
  }
20
 
21
  /*
23
  *
24
  * @since 0.1
25
  *
26
+ * @param array $query_vars query vars known to WordPress
27
  * @return array unmodified query vars if the request is not a Lingotek callback
28
  */
29
+ public function request( $query_vars ) {
30
+ if ( empty( $query_vars['lingotek'] ) ) {
31
  return $query_vars;
32
  }
33
  $type = $_GET['type'];
34
+ if ( isset( $type, $_GET['document_id'] ) && $document = $this->lgtm->get_group_by_id( $_GET['document_id'] ) ) {
35
+ switch ( $type ) {
36
  case 'get':
37
+ $this->handleGet( $document );
38
  break;
39
  case 'target':
40
  case 'phase':
41
+ case 'download_interim_translation':
42
+ $this->handleTargetOrPhaseOrDownloadInterimTranslation( $document, $type );
43
  break;
44
  case 'target_cancelled':
45
+ $this->handleTargetCancelled( $document );
46
  break;
47
  case 'document_uploaded':
48
  case 'document_updated':
49
+ $this->handleDocumentUploadedOrUpdated( $document );
50
  break;
51
  case 'import_failure':
52
+ $this->handleImportFailure( $document );
53
  break;
54
  case 'document_archived':
55
  case 'document_deleted':
56
+ $this->handleDocumentArchivedOrDeleted( $document );
57
  break;
58
  case 'document_cancelled';
59
+ $this->handleDocumentCancelled( $document );
60
  break;
61
  default:
62
+ Lingotek_Logger::info( 'Callback received, no handler for type', array( 'Type' => $type ) );
63
+ }//end switch
64
+ // Useless as it the default value.
65
+ status_header( 200 );
66
  die();
67
+ }//end if
68
+ // No document found.
69
+ status_header( 404 );
70
  die();
71
  }
72
 
73
+ public function handleGet( $document ) {
74
  // url for in context review
75
+ if ( isset( $_GET['locale'] ) ) {
76
+ // Map to WordPress locale.
77
+ $locale = Lingotek::map_to_wp_locale( $_GET['locale'] );
78
+ Lingotek_Logger::info( 'Callback received', array( 'Callback Parameters' => $_GET ) );
79
  // posts
80
+ if ( post_type_exists( $document->type ) ) {
81
+ if ( $id = PLL()->model->post->get( $document->source, $locale ) ) {
82
+ wp_redirect( get_permalink( $id ), 301 );
83
  exit();
84
+ } else {
85
+ wp_redirect( get_permalink( $document->source ), 302 );
 
86
  exit();
87
  }
88
  }
89
  // taxonomy terms
90
+ elseif ( taxonomy_exists( $document->type ) && $id = $document->pllm->get_term( $document->source, $locale ) ) {
91
+ wp_redirect( get_term_link( $id, $document->type ), 301 );
92
  exit();
93
  }
94
 
95
+ // No document found.
96
+ status_header( 404 );
97
  die();
98
+ }//end if
99
  }
100
 
101
+ public function handleTargetOrPhaseOrDownloadInterimTranslation( $document, $type ) {
102
+ if ( isset( $_GET['locale'] ) ) {
103
  $callback_parameters = array(
104
+ 'Target Locale' => isset( $_GET['locale_code'] ) ? $_GET['locale_code'] : null,
105
+ 'Phase Name' => isset( $_GET['phase_name'] ) ? $_GET['phase_name'] : null,
106
+ 'Status' => isset( $_GET['status'] ) ? $_GET['status'] : null,
107
+ 'Document ID' => isset( $_GET['document_id'] ) ? $_GET['document_id'] : null,
108
+ 'Project ID' => isset( $_GET['projectId'] ) ? (int) $_GET['projectId'] : null,
109
+ 'Community ID' => isset( $_GET['community_id'] ) ? $_GET['community_id'] : null,
110
+ 'Progress' => isset( $_GET['progress'] ) ? (int) $_GET['progress'] : null,
111
+ 'Complete' => isset( $_GET['complete'] ) ? $_GET['complete'] : null,
112
+ 'Type' => isset( $_GET['type'] ) ? $_GET['type'] : null,
113
+ 'Document Status' => isset( $_GET['doc_status'] ) ? $_GET['doc_status'] : null,
114
  );
115
+ Lingotek_Logger::info( 'Callback received', array( 'Callback Parameters' => $callback_parameters ) );
116
  // We will need access to PLL_Admin_Sync::copy_post_metas
117
  global $polylang;
118
+ $polylang->sync = new PLL_Admin_Sync( $polylang );
119
+ // Map to WordPress locale.
120
+ $locale = Lingotek::map_to_wp_locale( $_GET['locale'] );
121
+ $document->is_automatic_download( $locale ) ? $document->create_translation( $locale, true, $type ) : $document->translation_ready( $locale );
122
+ }//end if
123
  }
124
 
125
+ public function handleDocumentUploadedOrUpdated( $document ) {
126
  $document->source_ready();
127
  $callback_parameters = array(
128
+ 'Document ID' => isset( $_GET['document_id'] ) ? $_GET['document_id'] : null,
129
+ 'Project ID' => isset( $_GET['projectId'] ) ? (int) $_GET['projectId'] : null,
130
+ 'Community ID' => isset( $_GET['community_id'] ) ? $_GET['community_id'] : null,
131
+ 'Progress' => isset( $_GET['progress'] ) ? (int) $_GET['progress'] : null,
132
+ 'Complete' => isset( $_GET['complete'] ) ? $_GET['complete'] : null,
133
+ 'Type' => isset( $_GET['type'] ) ? $_GET['type'] : null,
134
+ 'Document Status' => isset( $_GET['doc_status'] ) ? $_GET['doc_status'] : null,
135
  );
136
+ Lingotek_Logger::info( 'Callback received', array( 'Callback Parameters' => $callback_parameters ) );
137
+ if ( $document->is_automatic_upload() ) {
138
  $document->request_translations();
139
  }
140
  }
141
 
142
+ public function handleImportFailure( $document ) {
143
  $callback_parameters = array(
144
+ 'Document ID' => isset( $_GET['document_id'] ) ? $_GET['document_id'] : null,
145
+ 'Type' => isset( $_GET['type'] ) ? $_GET['type'] : null,
146
  );
147
+ if ( isset( $_GET['prev_document_id'] ) ) {
148
+ Lingotek_Logger::info( 'Document update failed. Reverting to previous id', $callback_parameters );
149
  $document->id = $_GET['prev_document_id'];
150
  }
151
+ Lingotek_Logger::info( 'Callback received', array( 'Callback Parameters' => $callback_parameters ) );
152
  $document->source_failed();
153
  }
154
+
155
+ public function handleDocumentArchivedOrDeleted( $document ) {
156
+ $callback_parameters = array(
157
+ 'Document ID' => isset( $_GET['document_id'] ) ? $_GET['document_id'] : null,
158
+ 'Type' => isset( $_GET['type'] ) ? $_GET['type'] : null,
159
  );
160
+ Lingotek_Logger::info( 'Callback received', array( 'Callback Parameters' => $callback_parameters ) );
161
+ $wp_id = isset( $document->desc_array['lingotek']['source'] ) ? $document->desc_array['lingotek']['source'] : null;
162
+ unset( $document->desc_array['lingotek'] );
163
  $document->document_id = '';
164
  $document->save();
165
+ wp_remove_object_terms( $wp_id, "lingotek_hash_{$wp_id}", 'lingotek_hash' );
166
  }
167
 
168
+ public function handleDocumentCancelled( $document ) {
169
  $callback_parameters = array(
170
+ 'Document ID' => isset( $_GET['document_id'] ) ? $_GET['document_id'] : null,
171
+ 'Type' => isset( $_GET['type'] ) ? $_GET['type'] : null,
172
  );
173
+ if ( isset( $document->desc_array['lingotek']['translations'] ) && count( $document->desc_array['lingotek']['translations'] ) > 0 ) {
174
+ unset( $document->desc_array['lingotek']['translations'] );
175
  $document->desc_array['lingotek']['status'] = 'cancelled';
176
  } else {
177
+ unset( $document->desc_array['lingotek'] );
178
  }
179
+ $wp_id = isset( $document->desc_array['lingotek']['source'] ) ? $document->desc_array['lingotek']['source'] : null;
180
  $document->status = 'cancelled';
181
  $document->save();
182
+ wp_remove_object_terms( $wp_id, "lingotek_hash_{$wp_id}", 'lingotek_hash' );
183
+ Lingotek_Logger::info( 'Callback Received', array( 'Callback Parameters' => $callback_parameters ) );
184
  }
185
 
186
+ public function handleTargetCancelled( $document ) {
187
  $callback_parameters = array(
188
+ 'Document ID' => isset( $_GET['document_id'] ) ? $_GET['document_id'] : null,
189
+ 'Type' => isset( $_GET['type'] ) ? $_GET['type'] : null,
190
+ 'Locale' => isset( $_GET['locale'] ) ? $_GET['locale'] : null,
191
  );
192
+ // Map to WordPress locale.
193
+ $locale = Lingotek::map_to_wp_locale( $_GET['locale'] );
194
+ if ( ! isset( $document->desc_array['lingotek']['translations'][ $locale ] ) ) {
195
  $document->desc_array['lingotek']['translations'][] = $locale;
196
+ $document->save();
197
  }
198
+ $document->update_translation_status( $locale, 'cancelled' );
199
+ Lingotek_Logger::info( 'Callback received', array( 'Callback Parameters' => $callback_parameters ) );
 
200
  }
 
201
  }
include/dashboard.php CHANGED
@@ -21,33 +21,35 @@ class Lingotek_Dashboard {
21
  function ajax_language_dashboard() {
22
  global $polylang;
23
 
24
- $request_method = isset($_REQUEST['_method']) ? $_REQUEST['_method'] : (isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET');
25
 
26
  $response = array(
27
- 'method' => $request_method
28
  );
29
 
30
- switch ($request_method) {
31
  case 'POST':
32
- if (isset($_REQUEST['code'], $_REQUEST['native'], $_REQUEST['direction'])) {
33
  $name = $_REQUEST['native'];
34
- $slug = substr($_REQUEST['code'], 0, strpos($_REQUEST['code'], '_')); // 3rd parameter of strstr needs PHP 5.3
35
- $locale = Lingotek::map_to_wp_locale($_REQUEST['code']);
36
-
37
- // avoid conflicts between language slugs
38
- $existing_slugs = $polylang->model->get_languages_list(array('fields' => 'slug'));
39
- if (!empty($existing_slugs) && in_array($slug, $existing_slugs))
40
- $slug = strtolower(str_replace('_', '-', $locale));
 
 
41
 
42
- $rtl = $_REQUEST['direction'] == 'RTL';
43
  $term_group = 0;
44
 
45
  // adds the language
46
- $polylang->model->add_language(compact('name', 'slug', 'locale', 'rtl', 'term_group'));
47
 
48
  // attempts to install the language pack
49
- require_once(ABSPATH . 'wp-admin/includes/translation-install.php');
50
- wp_download_language_pack($locale);
51
 
52
  // force checking for themes and plugins translations updates
53
  wp_update_themes();
@@ -55,148 +57,154 @@ class Lingotek_Dashboard {
55
 
56
  $response = array(
57
  'request' => 'POST: add target language to CMS and Lingotek Project Language',
58
- 'locale' => $_REQUEST['code'],
59
- 'xcode' => $locale,
60
- 'active' => 1,
61
  'enabled' => 1,
62
- 'source' => self::get_counts_by_type($locale, 'sources'),
63
- 'target' => self::get_counts_by_type($locale, 'targets')
64
  );
65
- status_header(200);
66
  } else {
67
- $code = $_REQUEST['code'];
68
- $native = $_REQUEST['native'];
69
  $direction = $_REQUEST['direction'];
70
- $response = [
71
  'request' => 'POST: add target language to CMS and and Lingotek Project Language',
72
  'success' => false,
73
- 'message' => __("Missing locale, direction, or name. Locale: $code, Name: $native, Direction: $direction", 'lingotek-translation')
74
- ];
75
 
76
- status_header(400);
77
- }
78
  break;
79
 
80
  case 'DELETE':
81
- $body = file_get_contents("php://input");
82
- $code = str_replace('code=', '', $body);
83
- $lang = $polylang->model->get_language(Lingotek::map_to_wp_locale($code)); // map code to WP locales to find the language
84
-
85
- // prevents deleting the last language as it would break the Lingotek dashboard
86
- if (1 == count($polylang->model->get_languages_list())) {
87
- $response = array (
88
- 'request' => sprintf('DELETE: remove language from CMS and project (%s)', $code),
89
- 'code' => $code,
 
90
  'success' => false,
91
- 'message' => __('You must keep at least one language.', 'lingotek-translation')
92
  );
93
- status_header(403);
94
- }
95
-
96
- elseif (!self::has_language_content($lang)) {
97
- $default_category = pll_get_term(get_option('default_category'), $lang->slug);
98
- $polylang->model->delete_language((int) $lang->term_id);
99
- wp_delete_term( $default_category, 'category' ); // delete the default category after the language
100
 
101
  // Deletes the translation status so when re-adding a language the string groups translations won't display as current
102
  $lingotek_model = new Lingotek_Model();
103
- $strings = $lingotek_model->get_strings();
104
- foreach ($strings as $string) {
105
- $group = $lingotek_model->get_group('string', $string['context']);
106
- if ($group) {
107
- unset($group->translations[$lang->locale]);
108
  $group->save();
109
  }
110
  }
111
 
112
- $response = array (
113
- 'request' => sprintf('DELETE: remove language from CMS and project (%s)', $code),
114
- 'code' => $code,
115
- 'active' => false,
116
- 'success' => true
117
  );
118
- status_header(204);
119
- }
120
-
121
- else {
122
- $response = array (
123
- 'request' => sprintf('DELETE: remove language from CMS and project (%s)', $code),
124
- 'code' => $code,
125
  'success' => false,
126
- 'message' => __('The language can only be removed when no existing content is using it. If you would like to remove this language from the site, then first remove any content assigned to this language.', 'lingotek-translation')
127
  );
128
- status_header(403);
129
- }
130
  break;
131
 
132
  case 'GET':
133
  default:
134
- $locale_code = isset($_REQUEST['code']) ? $_REQUEST['code'] : NULL;
135
- $response = $response + $this->get_language_details($locale_code);
136
  break;
137
- }
138
 
139
- wp_send_json($response);
140
  }
141
 
142
  /**
143
  * Lingotek - get the details of each language
144
  */
145
- function get_language_details($locale_requested = NULL) {
146
  global $polylang;
147
 
148
- $response = array();
149
  $available_languages = $polylang->model->get_languages_list();
150
- $source_total = 0;
151
- $target_total = 0;
152
- $source_totals = array();
153
- $target_totals = array();
154
 
155
  // If we get a parameter, only return that language. Otherwise return all languages.
156
- foreach ($available_languages as $lang_details) {
157
  $wordpress_lang_code = $lang_details->slug;
158
- $locale = $lang_details->locale;
159
- if (!is_null($locale_requested) && $locale_requested != $locale) {
160
  continue;
161
  }
162
 
163
- $lingotek_locale = str_replace('-', '_', $lang_details->lingotek_locale);
164
- $source_counts = self::get_source_counts($wordpress_lang_code);
165
- $target_counts = self::get_target_counts($wordpress_lang_code);
166
- self::standardize_and_sort($source_counts['types'], $target_counts['types']);
167
- $source_count = $source_counts['total']; //unset($source_counts['total']);
168
  $target_count = $target_counts['total'];
169
 
170
  $target_status = array(
171
- 'locale' => $lingotek_locale, // Return this language code as the Lingotek language code.
172
- 'xcode' => $wordpress_lang_code,
173
- 'active' => 1, //TO-DO: lingotek_enabled?
174
- 'enabled' => 1, //intval($lang_details->active), // wordpress enabled
175
- 'source' => $source_counts,
176
- 'target' => $target_counts
 
 
 
177
  );
178
- if ($locale_requested == $locale) {
179
  $response = $target_status;
180
- }
181
- else {
182
- $response[$lingotek_locale] = $target_status;
183
  }
184
  //$source_total += $source_count;
185
  $target_total += $target_count;
186
  //$source_totals = self::array_sum_values($source_totals, $source_counts['types']);
187
- $target_totals = self::array_sum_values($target_totals, $target_counts['types']);
188
- }
189
- if (is_null($locale_requested)) {
190
  $source_totals_package = self::get_unique_source_counts_by_type();
191
- $source_totals = $source_totals_package['types'];
192
- $source_total = $source_totals_package['total'];
193
- self::standardize_and_sort($source_totals, $target_totals);
194
 
195
  $response = array(
196
  'languages' => $response,
197
- 'source' => array('types' => $source_totals, 'total' => $source_total),
198
- 'target' => array('types' => $target_totals, 'total' => $target_total),
199
- 'count' => count($available_languages),
 
 
 
 
 
 
200
  );
201
  }
202
  return $response;
@@ -205,72 +213,74 @@ class Lingotek_Dashboard {
205
  /**
206
  * Lingotek - standardize and sort helper function
207
  */
208
- static function standardize_and_sort(&$a1, &$a2) {
209
- $merged_totals = array_fill_keys(array_keys($a1 + $a2), 0);
210
- $a1 = $a1 + $merged_totals;
211
- $a2 = $a2 + $merged_totals;
212
- ksort($a1);
213
- ksort($a2);
214
  }
215
 
216
  /**
217
  * Lingotek - get_source_counts
218
  */
219
- function get_source_counts($locale) {
220
- return self::get_counts_by_type($locale, 'sources');
221
  }
222
 
223
  /**
224
  * Lingotek - get_target_counts
225
  */
226
- function get_target_counts($locale) {
227
- return self::get_counts_by_type($locale, 'targets');
228
  }
229
 
230
  /**
231
  * Lingotek - get_counts_by_type
232
  */
233
- static function get_counts_by_type($locale, $condition) {
234
  global $polylang;
235
 
236
- $lgtm = new Lingotek_Model(); // FIXME not created by Lingotek as Polylang believes we are doing ajax on frontend
 
237
 
238
- foreach ($polylang->model->get_translated_post_types() as $post_type) {
239
- $count = $lgtm->count_posts($post_type);
240
- $post_type_object = get_post_type_object($post_type);
241
- $response['types'][$post_type_object->labels->name] = isset($count[$condition][$locale]) ? $count[$condition][$locale] : 0;
242
  }
243
 
244
- foreach ($polylang->model->get_translated_taxonomies() as $tax) {
245
- $count = $lgtm->count_terms($tax);
246
- $taxonomy = get_taxonomy($tax);
247
- $response['types'][$taxonomy->labels->name] = isset($count[$condition][$locale]) ? $count[$condition][$locale] : 0;
248
  }
249
 
250
- $response['total'] = array_sum($response['types']);
251
 
252
  return $response;
253
  }
254
 
255
- static function get_unique_source_counts_by_type(){
256
-
257
  global $polylang;
258
 
259
- $lgtm = new Lingotek_Model(); // FIXME not created by Lingotek as Polylang believes we are doing ajax on frontend
260
-
261
- foreach ($polylang->model->get_translated_post_types() as $post_type) {
262
- $count = $lgtm->count_posts($post_type);
263
- $post_type_object = get_post_type_object($post_type);
264
- $response['types'][$post_type_object->labels->name] = isset($count['total']) ? $count['total'] : 0; //only count translation sets
 
265
  }
266
 
267
- foreach ($polylang->model->get_translated_taxonomies() as $tax) {
268
- $count = $lgtm->count_terms($tax);
269
- $taxonomy = get_taxonomy($tax);
270
- $response['types'][$taxonomy->labels->name] = isset($count['total']) ? $count['total'] : 0; //only count translation sets
 
271
  }
272
 
273
- $response['total'] = array_sum($response['types']);
274
 
275
  return $response;
276
  }
@@ -280,30 +290,30 @@ class Lingotek_Dashboard {
280
  * array array_sum_values ( array array1 [, array array2 [, array ...]] )
281
  */
282
  public static function array_sum_values() {
283
- $return = array();
284
  $intArgs = func_num_args();
285
  $arrArgs = func_get_args();
286
- if ($intArgs < 1) {
287
- trigger_error('Warning: Wrong parameter count for arraySumValues()', E_USER_WARNING);
288
  }
289
 
290
- foreach ($arrArgs as $arrItem) {
291
- if (!is_array($arrItem)) {
292
- trigger_error('Warning: Wrong parameter values for arraySumValues()', E_USER_WARNING);
293
  }
294
- foreach ($arrItem as $k => $v) {
295
- if (!key_exists($k, $return)) {
296
- $return[$k] = 0;
297
  }
298
- $return[$k] += $v;
299
  }
300
  }
301
  return $return;
302
 
303
  $sumArray = array();
304
- foreach ($myArray as $k => $subArray) {
305
- foreach ($subArray as $id => $value) {
306
- $sumArray[$id]+=$value;
307
  }
308
  }
309
  return $sumArray;
@@ -317,23 +327,23 @@ class Lingotek_Dashboard {
317
  * @param object $language
318
  * @return bool false if no content in the language or only the default category
319
  */
320
- static public function has_language_content($language) {
321
  // posts
322
- $objects = get_objects_in_term($language->term_id, 'language');
323
- if (!empty($objects)) {
324
- foreach ($objects as $key => $object) {
325
- $post = get_post($object);
326
- if ($post->post_status == 'auto-draft') {
327
- unset($objects[$key]);
328
  }
329
  }
330
- if (!empty($objects)) {
331
  return true;
332
  }
333
  }
334
 
335
  // terms, only the default category is accepted
336
- $objects = get_objects_in_term($language->tl_term_id, 'term_language');
337
- return count($objects) > 1 || (isset($objects[0]) && $objects[0] != pll_get_term(get_option('default_category'), $language->slug));
338
  }
339
  }
21
  function ajax_language_dashboard() {
22
  global $polylang;
23
 
24
+ $request_method = isset( $_REQUEST['_method'] ) ? $_REQUEST['_method'] : ( isset( $_SERVER['REQUEST_METHOD'] ) ? $_SERVER['REQUEST_METHOD'] : 'GET' );
25
 
26
  $response = array(
27
+ 'method' => $request_method,
28
  );
29
 
30
+ switch ( $request_method ) {
31
  case 'POST':
32
+ if ( isset( $_REQUEST['code'], $_REQUEST['native'], $_REQUEST['direction'] ) ) {
33
  $name = $_REQUEST['native'];
34
+ // 3rd parameter of strstr needs PHP 5.3.
35
+ $slug = substr( $_REQUEST['code'], 0, strpos( $_REQUEST['code'], '_' ) );
36
+ $locale = Lingotek::map_to_wp_locale( $_REQUEST['code'] );
37
+
38
+ // Avoid conflicts between language slugs.
39
+ $existing_slugs = $polylang->model->get_languages_list( array( 'fields' => 'slug' ) );
40
+ if ( ! empty( $existing_slugs ) && in_array( $slug, $existing_slugs ) ) {
41
+ $slug = strtolower( str_replace( '_', '-', $locale ) );
42
+ }
43
 
44
+ $rtl = $_REQUEST['direction'] == 'RTL';
45
  $term_group = 0;
46
 
47
  // adds the language
48
+ $polylang->model->add_language( compact( 'name', 'slug', 'locale', 'rtl', 'term_group' ) );
49
 
50
  // attempts to install the language pack
51
+ require_once ABSPATH . 'wp-admin/includes/translation-install.php';
52
+ wp_download_language_pack( $locale );
53
 
54
  // force checking for themes and plugins translations updates
55
  wp_update_themes();
57
 
58
  $response = array(
59
  'request' => 'POST: add target language to CMS and Lingotek Project Language',
60
+ 'locale' => $_REQUEST['code'],
61
+ 'xcode' => $locale,
62
+ 'active' => 1,
63
  'enabled' => 1,
64
+ 'source' => self::get_counts_by_type( $locale, 'sources' ),
65
+ 'target' => self::get_counts_by_type( $locale, 'targets' ),
66
  );
67
+ status_header( 200 );
68
  } else {
69
+ $code = $_REQUEST['code'];
70
+ $native = $_REQUEST['native'];
71
  $direction = $_REQUEST['direction'];
72
+ $response = array(
73
  'request' => 'POST: add target language to CMS and and Lingotek Project Language',
74
  'success' => false,
75
+ 'message' => __( "Missing locale, direction, or name. Locale: $code, Name: $native, Direction: $direction", 'lingotek-translation' ),
76
+ );
77
 
78
+ status_header( 400 );
79
+ }//end if
80
  break;
81
 
82
  case 'DELETE':
83
+ $body = file_get_contents( 'php://input' );
84
+ $code = str_replace( 'code=', '', $body );
85
+ // Map code to WP locales to find the language.
86
+ $lang = $polylang->model->get_language( Lingotek::map_to_wp_locale( $code ) );
87
+
88
+ // Prevents deleting the last language as it would break the Lingotek dashboard.
89
+ if ( 1 == count( $polylang->model->get_languages_list() ) ) {
90
+ $response = array(
91
+ 'request' => sprintf( 'DELETE: remove language from CMS and project (%s)', $code ),
92
+ 'code' => $code,
93
  'success' => false,
94
+ 'message' => __( 'You must keep at least one language.', 'lingotek-translation' ),
95
  );
96
+ status_header( 403 );
97
+ } elseif ( ! self::has_language_content( $lang ) ) {
98
+ $default_category = pll_get_term( get_option( 'default_category' ), $lang->slug );
99
+ $polylang->model->delete_language( (int) $lang->term_id );
100
+ // Delete the default category after the language.
101
+ wp_delete_term( $default_category, 'category' );
 
102
 
103
  // Deletes the translation status so when re-adding a language the string groups translations won't display as current
104
  $lingotek_model = new Lingotek_Model();
105
+ $strings = $lingotek_model->get_strings();
106
+ foreach ( $strings as $string ) {
107
+ $group = $lingotek_model->get_group( 'string', $string['context'] );
108
+ if ( $group ) {
109
+ unset( $group->translations[ $lang->locale ] );
110
  $group->save();
111
  }
112
  }
113
 
114
+ $response = array(
115
+ 'request' => sprintf( 'DELETE: remove language from CMS and project (%s)', $code ),
116
+ 'code' => $code,
117
+ 'active' => false,
118
+ 'success' => true,
119
  );
120
+ status_header( 204 );
121
+ } else {
122
+ $response = array(
123
+ 'request' => sprintf( 'DELETE: remove language from CMS and project (%s)', $code ),
124
+ 'code' => $code,
 
 
125
  'success' => false,
126
+ 'message' => __( 'The language can only be removed when no existing content is using it. If you would like to remove this language from the site, then first remove any content assigned to this language.', 'lingotek-translation' ),
127
  );
128
+ status_header( 403 );
129
+ }//end if
130
  break;
131
 
132
  case 'GET':
133
  default:
134
+ $locale_code = isset( $_REQUEST['code'] ) ? $_REQUEST['code'] : null;
135
+ $response = $response + $this->get_language_details( $locale_code );
136
  break;
137
+ }//end switch
138
 
139
+ wp_send_json( $response );
140
  }
141
 
142
  /**
143
  * Lingotek - get the details of each language
144
  */
145
+ function get_language_details( $locale_requested = null ) {
146
  global $polylang;
147
 
148
+ $response = array();
149
  $available_languages = $polylang->model->get_languages_list();
150
+ $source_total = 0;
151
+ $target_total = 0;
152
+ $source_totals = array();
153
+ $target_totals = array();
154
 
155
  // If we get a parameter, only return that language. Otherwise return all languages.
156
+ foreach ( $available_languages as $lang_details ) {
157
  $wordpress_lang_code = $lang_details->slug;
158
+ $locale = $lang_details->locale;
159
+ if ( ! is_null( $locale_requested ) && $locale_requested != $locale ) {
160
  continue;
161
  }
162
 
163
+ $lingotek_locale = str_replace( '-', '_', $lang_details->lingotek_locale );
164
+ $source_counts = self::get_source_counts( $wordpress_lang_code );
165
+ $target_counts = self::get_target_counts( $wordpress_lang_code );
166
+ self::standardize_and_sort( $source_counts['types'], $target_counts['types'] );
167
+ $source_count = $source_counts['total'];
168
  $target_count = $target_counts['total'];
169
 
170
  $target_status = array(
171
+ // Return this language code as the Lingotek language code.
172
+ 'locale' => $lingotek_locale,
173
+ 'xcode' => $wordpress_lang_code,
174
+ // Lingotek enabled (active).
175
+ 'active' => 1,
176
+ // WordPress enabled (enabled)
177
+ 'enabled' => 1,
178
+ 'source' => $source_counts,
179
+ 'target' => $target_counts,
180
  );
181
+ if ( $locale_requested == $locale ) {
182
  $response = $target_status;
183
+ } else {
184
+ $response[ $lingotek_locale ] = $target_status;
 
185
  }
186
  //$source_total += $source_count;
187
  $target_total += $target_count;
188
  //$source_totals = self::array_sum_values($source_totals, $source_counts['types']);
189
+ $target_totals = self::array_sum_values( $target_totals, $target_counts['types'] );
190
+ }//end foreach
191
+ if ( is_null( $locale_requested ) ) {
192
  $source_totals_package = self::get_unique_source_counts_by_type();
193
+ $source_totals = $source_totals_package['types'];
194
+ $source_total = $source_totals_package['total'];
195
+ self::standardize_and_sort( $source_totals, $target_totals );
196
 
197
  $response = array(
198
  'languages' => $response,
199
+ 'source' => array(
200
+ 'types' => $source_totals,
201
+ 'total' => $source_total,
202
+ ),
203
+ 'target' => array(
204
+ 'types' => $target_totals,
205
+ 'total' => $target_total,
206
+ ),
207
+ 'count' => count( $available_languages ),
208
  );
209
  }
210
  return $response;
213
  /**
214
  * Lingotek - standardize and sort helper function
215
  */
216
+ static function standardize_and_sort( &$a1, &$a2 ) {
217
+ $merged_totals = array_fill_keys( array_keys( $a1 + $a2 ), 0 );
218
+ $a1 = $a1 + $merged_totals;
219
+ $a2 = $a2 + $merged_totals;
220
+ ksort( $a1 );
221
+ ksort( $a2 );
222
  }
223
 
224
  /**
225
  * Lingotek - get_source_counts
226
  */
227
+ function get_source_counts( $locale ) {
228
+ return self::get_counts_by_type( $locale, 'sources' );
229
  }
230
 
231
  /**
232
  * Lingotek - get_target_counts
233
  */
234
+ function get_target_counts( $locale ) {
235
+ return self::get_counts_by_type( $locale, 'targets' );
236
  }
237
 
238
  /**
239
  * Lingotek - get_counts_by_type
240
  */
241
+ static function get_counts_by_type( $locale, $condition ) {
242
  global $polylang;
243
 
244
+ // FIXME not created by Lingotek as Polylang believes we are doing ajax on frontend
245
+ $lgtm = new Lingotek_Model();
246
 
247
+ foreach ( $polylang->model->get_translated_post_types() as $post_type ) {
248
+ $count = $lgtm->count_posts( $post_type );
249
+ $post_type_object = get_post_type_object( $post_type );
250
+ $response['types'][ $post_type_object->labels->name ] = isset( $count[ $condition ][ $locale ] ) ? $count[ $condition ][ $locale ] : 0;
251
  }
252
 
253
+ foreach ( $polylang->model->get_translated_taxonomies() as $tax ) {
254
+ $count = $lgtm->count_terms( $tax );
255
+ $taxonomy = get_taxonomy( $tax );
256
+ $response['types'][ $taxonomy->labels->name ] = isset( $count[ $condition ][ $locale ] ) ? $count[ $condition ][ $locale ] : 0;
257
  }
258
 
259
+ $response['total'] = array_sum( $response['types'] );
260
 
261
  return $response;
262
  }
263
 
264
+ static function get_unique_source_counts_by_type() {
 
265
  global $polylang;
266
 
267
+ // FIXME not created by Lingotek as Polylang believes we are doing ajax on frontend
268
+ $lgtm = new Lingotek_Model();
269
+ foreach ( $polylang->model->get_translated_post_types() as $post_type ) {
270
+ $count = $lgtm->count_posts( $post_type );
271
+ $post_type_object = get_post_type_object( $post_type );
272
+ // Only count translation sets.
273
+ $response['types'][ $post_type_object->labels->name ] = isset( $count['total'] ) ? $count['total'] : 0;
274
  }
275
 
276
+ foreach ( $polylang->model->get_translated_taxonomies() as $tax ) {
277
+ $count = $lgtm->count_terms( $tax );
278
+ $taxonomy = get_taxonomy( $tax );
279
+ // Only count translation sets.
280
+ $response['types'][ $taxonomy->labels->name ] = isset( $count['total'] ) ? $count['total'] : 0;
281
  }
282
 
283
+ $response['total'] = array_sum( $response['types'] );
284
 
285
  return $response;
286
  }
290
  * array array_sum_values ( array array1 [, array array2 [, array ...]] )
291
  */
292
  public static function array_sum_values() {
293
+ $return = array();
294
  $intArgs = func_num_args();
295
  $arrArgs = func_get_args();
296
+ if ( $intArgs < 1 ) {
297
+ trigger_error( 'Warning: Wrong parameter count for arraySumValues()', E_USER_WARNING );
298
  }
299
 
300
+ foreach ( $arrArgs as $arrItem ) {
301
+ if ( ! is_array( $arrItem ) ) {
302
+ trigger_error( 'Warning: Wrong parameter values for arraySumValues()', E_USER_WARNING );
303
  }
304
+ foreach ( $arrItem as $k => $v ) {
305
+ if ( ! key_exists( $k, $return ) ) {
306
+ $return[ $k ] = 0;
307
  }
308
+ $return[ $k ] += $v;
309
  }
310
  }
311
  return $return;
312
 
313
  $sumArray = array();
314
+ foreach ( $myArray as $k => $subArray ) {
315
+ foreach ( $subArray as $id => $value ) {
316
+ $sumArray[ $id ] += $value;
317
  }
318
  }
319
  return $sumArray;
327
  * @param object $language
328
  * @return bool false if no content in the language or only the default category
329
  */
330
+ public static function has_language_content( $language ) {
331
  // posts
332
+ $objects = get_objects_in_term( $language->term_id, 'language' );
333
+ if ( ! empty( $objects ) ) {
334
+ foreach ( $objects as $key => $object ) {
335
+ $post = get_post( $object );
336
+ if ( $post->post_status == 'auto-draft' ) {
337
+ unset( $objects[ $key ] );
338
  }
339
  }
340
+ if ( ! empty( $objects ) ) {
341
  return true;
342
  }
343
  }
344
 
345
  // terms, only the default category is accepted
346
+ $objects = get_objects_in_term( $language->tl_term_id, 'term_language' );
347
+ return count( $objects ) > 1 || ( isset( $objects[0] ) && $objects[0] != pll_get_term( get_option( 'default_category' ), $language->slug ) );
348
  }
349
  }
include/group-post.php CHANGED
@@ -7,8 +7,8 @@
7
  */
8
  class Lingotek_Group_Post extends Lingotek_Group {
9
 
10
- const SAME_AS_SOURCE = 'SAME_AS_SOURCE'; // pref constant used for downloaded translations
11
-
12
  /*
13
  * set a translation term for an object
14
  *
@@ -18,18 +18,19 @@ class Lingotek_Group_Post extends Lingotek_Group {
18
  * @param object $language
19
  * @param string $document_id translation term name (Lingotek document id)
20
  */
21
- public static function create($object_id, $language, $document_id) {
22
  $data = array(
23
- 'lingotek' => array(
24
- 'type' => get_post_type($object_id),
25
  'source' => $object_id,
26
  'status' => 'importing',
27
- 'translations' => array()
28
  ),
29
- $language->slug => $object_id // for Polylang
 
30
  );
31
- self::save_hash_on_upload($object_id);
32
- self::_create($object_id, $document_id, $data, 'post_translations');
33
  }
34
 
35
  /*
@@ -40,66 +41,66 @@ class Lingotek_Group_Post extends Lingotek_Group {
40
  * @param string $post_type
41
  * @return array
42
  */
43
- static public function get_content_type_fields($post_type, $post_ID = NULL) {
44
- $cache_key = 'content_type_fields_' . $post_type;
45
- $arr = wp_cache_get($cache_key, 'lingotek');
46
- if (!$arr) {
47
- $arr = 'attachment' == $post_type ?
48
- array(
49
- 'post_title' => __('Title', 'lingotek-translation'),
50
- 'post_excerpt' => __('Caption', 'lingotek-translation'),
51
- 'metas' => ['_wp_attachment_image_alt' => __('Alternative Text', 'lingotek-translation')],
52
- 'post_content' => __('Description', 'lingotek-translation'),
53
- ) : array(
54
- 'post_title' => __('Title', 'lingotek-translation'),
55
- 'post_name' => __('Slug', 'lingotek-translation'),
56
- 'post_content' => __('Content', 'lingotek-translation'),
57
- 'post_excerpt' => __('Excerpt', 'lingotek-translation')
58
- );
59
-
60
- // if the user hasn't visited the custom fields tab, and hasn't saved actions for custom
61
- // fields, and uploaded a post, check the wpml file for settings
62
- if ($post_ID) {
63
- self::get_updated_meta_values($post_ID);
64
- }
65
- // add the custom fields from the lingotek_custom_fields option
66
- $custom_fields = get_option('lingotek_custom_fields', array());
67
-
68
- if (is_array($custom_fields) && !empty($custom_fields)) {
69
- foreach ($custom_fields as $cf => $setting) {
70
- if ('translate' == $setting) {
71
- $arr['metas'][$cf] = $cf;
72
- }
73
- }
74
- }
75
- wp_cache_set($cache_key, $arr, 'lingotek', 300);
76
- }
77
- // allow plugins to modify the fields to translate
78
- return apply_filters('lingotek_post_content_type_fields', $arr, $post_type);
79
- }
80
-
81
- /*
82
- * returns custom fields from the wpml-config.xml file
83
- *
84
- * @since 0.2
85
- *
86
- * @param string $post_type
87
- * @return array
88
- */
89
- static public function get_custom_fields_from_wpml() {
90
  $wpml_config = PLL_WPML_Config::instance();
91
- $arr = array();
92
 
93
- if (isset($wpml_config->tags['custom-fields'])) {
94
- foreach ($wpml_config->tags['custom-fields'] as $context) {
95
- foreach ($context['custom-field'] as $cf) {
96
- $arr[$cf['value']] = $cf['attributes']['action'];
97
  }
98
  }
99
  }
100
 
101
  // allow plugins to modify the fields to translate
102
- return apply_filters('lingotek_post_content_type_fields_from_wpml', $arr);
103
  }
104
 
105
  /*
@@ -109,59 +110,62 @@ class Lingotek_Group_Post extends Lingotek_Group {
109
  *
110
  * @return array
111
  */
112
- static public function get_custom_fields_from_wp_postmeta($post_ID = NULL)
113
- {
114
- $all_acf_fields = [];
115
- $custom_fields = get_option('lingotek_custom_fields', array());
116
- $meta_black_list = array('_encloseme', '_edit_last', '_edit_lock', '_wp_trash_meta_status', '_wp_trash_meta_time');
117
- $arr = array();
118
- $keys = array();
119
-
120
- if ($post_ID) {
121
- $p = get_post($post_ID);
122
  $posts[] = $p;
123
  } else {
124
- $posts = get_posts(array(
125
- 'posts_per_page' => -1,
126
- 'post_type' => 'post'
127
- ));
128
- $pages = get_posts(array(
129
- 'posts_per_page' => -1,
130
- 'post_type' => 'page'
131
- ));
132
-
133
- $posts = array_merge($posts, $pages);
 
 
 
 
134
  }
135
  //Only perform if ACF is installed and these functions are active
136
- if (function_exists('acf_get_field_groups') && function_exists('acf_get_fields')) {
137
- $groups = acf_get_field_groups();
138
- $field_holder = [];
139
- foreach ($groups as $group) {
140
- if (isset($group['key'])) {
141
- $field_holder = acf_get_fields($group['key']);
142
- foreach ($field_holder as $field) {
143
- $field_data = [];
144
- $field_data['meta_key'] = $field['name'];
145
  $field_data['meta_value'] = $field['key'];
146
- $all_acf_fields[] = $field_data;
147
  }
148
  }
149
  }
150
  }
151
 
152
- foreach ($posts as $post) {
153
- $metadata = has_meta($post->ID);
154
- foreach ($metadata as $key => $meta) {
155
- if (in_array($meta['meta_key'], $meta_black_list) || in_array($meta['meta_key'], $keys)) {
156
- unset($metadata[$key]);
157
  }
158
  $keys[] = $meta['meta_key'];
159
  }
160
- $arr = array_merge($arr, $metadata);
161
  }
162
- $arr = array_merge($arr, $all_acf_fields);
163
  // allow plugins to modify the fields to translate
164
- return apply_filters('lingotek_post_custom_fields', $arr);
165
  }
166
 
167
  /*
@@ -171,9 +175,8 @@ class Lingotek_Group_Post extends Lingotek_Group {
171
  *
172
  * @return bool
173
  */
174
- protected static function is_advanced_custom_fields_meta($key, $value)
175
- {
176
- return ((substr($key, 0, strlen('_')) === '_') && (substr($value, 0, strlen('field_')) === 'field_')) ? TRUE : FALSE;
177
  }
178
 
179
  /*
@@ -183,47 +186,46 @@ class Lingotek_Group_Post extends Lingotek_Group {
183
  *
184
  * @return array
185
  */
186
- public static function get_updated_meta_values($post_ID = NULL)
187
- {
188
- $custom_fields_from_wpml = self::get_custom_fields_from_wpml();
189
- $custom_fields_from_postmeta = self::get_custom_fields_from_wp_postmeta($post_ID);
190
- $custom_fields_from_lingotek = get_option('lingotek_custom_fields', array());
191
- if (!is_array($custom_fields_from_lingotek)) {
192
  $custom_fields_from_lingotek = array();
193
  }
194
- $default_custom_fields = get_option('lingotek_default_custom_fields') ? get_option('lingotek_default_custom_fields') : 'ignore';
195
- $custom_fields = array();
196
- $items = array();
197
 
198
- foreach ($custom_fields_from_postmeta as $cf) {
199
  // hide-copy means hide from user, and always copy to translations (Advanced Custom Fields plugin)
200
- if (self::is_advanced_custom_fields_meta($cf['meta_key'], $cf['meta_value'])) {
201
- $custom_fields[$cf['meta_key']] = 'hide-copy';
202
  continue;
203
  }
204
 
205
  // no lingotek setting
206
- if (!array_key_exists($cf['meta_key'], $custom_fields_from_lingotek)) {
207
  // no lingotek setting, but there's a wpml setting
208
- if (array_key_exists($cf['meta_key'], $custom_fields_from_wpml)) {
209
- $custom_fields[$cf['meta_key']] = $custom_fields_from_wpml[$cf['meta_key']];
210
  }
211
  // no lingotek setting, no wpml setting, so save default setting of ignore
212
  else {
213
- $custom_fields[$cf['meta_key']] = $default_custom_fields;
214
  }
215
  }
216
  // lingotek already has this field setting saved
217
  else {
218
- $custom_fields[$cf['meta_key']] = $custom_fields_from_lingotek[$cf['meta_key']];
219
  }
220
- }
221
 
222
- if ($post_ID) {
223
  // get_option sometimes returns empty string for `lingotek_custom_fields`
224
- $custom_fields = is_array($custom_fields_from_lingotek) ? array_merge($custom_fields_from_lingotek, $custom_fields) : $custom_fields;
225
  }
226
- update_option('lingotek_custom_fields', $custom_fields, false);
227
  }
228
 
229
  /*
@@ -234,19 +236,18 @@ class Lingotek_Group_Post extends Lingotek_Group {
234
  * @return array
235
  */
236
 
237
- public static function get_cached_meta_values()
238
- {
239
- $custom_fields_from_lingotek = get_option('lingotek_custom_fields', array());
240
- $items = array();
241
 
242
- if (is_array($custom_fields_from_lingotek)) {
243
- foreach ($custom_fields_from_lingotek as $key => $setting) {
244
- if ($setting === 'hide-copy') {
245
  continue;
246
  }
247
- $arr = array(
248
  'meta_key' => $key,
249
- 'setting' => $setting,
250
  );
251
  $items[] = $arr;
252
  }
@@ -262,50 +263,50 @@ class Lingotek_Group_Post extends Lingotek_Group {
262
  * @param object $post
263
  * @return string json encoded content to translate
264
  */
265
- public static function get_content($post) {
266
- $arr = array();
267
- $fields = self::get_content_type_fields($post->post_type, $post->ID);
268
- $content_types = get_option('lingotek_content_type');
269
- $post_custom_fields = get_post_meta($post->ID);
270
- $meta_black_list = array('_encloseme', '_edit_last', '_edit_lock', '_wp_trash_meta_status', '_wp_trash_meta_time');
271
- foreach (array_keys($fields) as $key) {
272
- if ('metas' == $key) {
273
- foreach ($post_custom_fields as $meta => $value) {
274
  // check for advanced custom fields meta expects a string
275
  // so if array, check first item
276
- $value = is_array($value) ? current($value) : $value;
277
- if (self::is_advanced_custom_fields_meta($meta, $value) || in_array($meta, $meta_black_list)) {
278
  continue;
279
  }
280
  // Get all metas in array format
281
- $meta_value = get_post_meta($post->ID, $meta, true);
282
- if ($meta_value && isset($fields['metas'][$meta])) {
283
- $arr['metas'][$meta] = $meta_value;
284
  }
285
  }
286
  // Check if acf is active and using these functions
287
- $acf_empty_string = "";
288
- if (isset($fields['metas'][$acf_empty_string]) && function_exists('acf_get_field_groups') && function_exists('acf_get_fields')) {
289
- $arr['metas'][$acf_empty_string] = get_post_meta($post->ID, $acf_empty_string, true);
290
  }
291
  }
292
  // send slug for translation only if it has been modified
293
- elseif ('post_name' == $key && empty($content_types[$post->post_type]['fields'][$key])) {
294
- $default_slug = sanitize_title($post->post_title); // default slug created by WP
 
295
  // if ($default_slug != $post->post_name)
296
- $arr['post'][$key] = $post->$key;
297
- } elseif (empty($content_types[$post->post_type]['fields'][$key])) {
298
- $arr['post'][$key] = $post->$key;
299
  }
300
- }
301
- return json_encode($arr);
302
  }
303
 
304
- public static function is_valid_auto_upload_post_status($post_status)
305
- {
306
- $prefs = Lingotek_Model::get_prefs();
307
  $valid_statuses = $prefs['auto_upload_post_statuses'];
308
- $valid = isset($valid_statuses[$post_status]) && $valid_statuses[$post_status];
309
  return $valid;
310
  }
311
 
@@ -314,11 +315,10 @@ class Lingotek_Group_Post extends Lingotek_Group {
314
  *
315
  * @since 0.1
316
  */
317
- public function request_translations()
318
- {
319
- if (isset($this->source)) {
320
- $language = PLL()->model->post->get_language((int)$this->source);
321
- $this->_request_translations($language);
322
  }
323
  }
324
 
@@ -330,122 +330,135 @@ class Lingotek_Group_Post extends Lingotek_Group {
330
  *
331
  * @param string $locale
332
  */
333
- public function create_translation($locale, $automatic = false, $callback_type = NULL)
334
- {
335
  // Removes content sanitization so YouTube videos, links, etc don't get removed when inserting translations
336
- remove_filter('content_save_pre', 'wp_filter_post_kses');
337
- remove_filter('content_filtered_save_pre', 'wp_filter_post_kses');
338
  $client = new Lingotek_API();
339
- $status = $client->get_translation_status($this->document_id, $locale);
340
 
341
- if ($status === -1) {
342
  return;
343
  }
344
 
345
- $translation = $client->get_translation($this->document_id, $locale, $this->source);
346
- if (!$translation || $this->translation_not_ready(json_decode($translation, true))) return; // If the request failed.
347
- $translation = json_decode($translation, true); // wp_insert_post expects array
 
 
 
 
348
 
349
  self::$creating_translation = true;
350
- $prefs = Lingotek_Model::get_prefs(); // need an array by default
 
351
 
352
  $tr_post = $translation['post'];
353
- if (isset($tr_post['post_name'])) {
354
- $tr_post['post_name'] = sanitize_title($tr_post['post_name']);
355
  }
356
 
357
- $post = get_post($this->source); // source post
358
- $tr_post['post_status'] = ($prefs['download_post_status'] === self::SAME_AS_SOURCE) ? $post->post_status : $prefs['download_post_status']; // status
 
 
359
 
360
  // update existing translation
361
- if ($tr_id = PLL()->model->post->get($this->source, $locale)) {
362
  $tr_post['ID'] = $tr_id;
363
 
364
  // copy or ignore metas
365
- self::copy_or_ignore_metas($post->ID, $tr_id);
366
 
367
  // translate metas
368
- if (isset($translation['metas'])) {
369
- self::copy_translated_metas($translation['metas'], $tr_id);
370
  }
371
 
372
- wp_update_post($tr_post);
373
- if ($status !== 100) {
374
- $this->safe_translation_status_update($locale, 'interim');
375
  } else {
376
- $this->safe_translation_status_update($locale, 'current');
377
  }
378
  }
379
 
380
  // create new translation
381
- else if (($this->translations[$locale] == 'ready' || $this->translations[$locale] == 'pending') || $automatic) {
382
- $content_type_options = get_option('lingotek_content_type');
383
- if (!isset($content_type_options[$post->post_type]['fields']['post_name'])) {
384
- unset($post->post_name); // forces the creation of a new default slug if not translated by Lingotek
 
385
  }
386
- $tr_post = array_merge((array)$post, $tr_post); // copy all untranslated fields from the original post
387
- $tr_post['ID'] = null; // will force the creation of a new post
 
 
388
 
389
  // translate parent
390
- $tr_post['post_parent'] = ($post->post_parent && $tr_parent = $this->pllm->post->get_translation($post->post_parent, $locale)) ? $tr_parent : 0;
391
 
392
- if ('attachment' == $post->post_type) {
393
- $tr_id = wp_insert_attachment($tr_post);
394
- add_post_meta($tr_id, '_wp_attachment_metadata', get_post_meta($this->source, '_wp_attachment_metadata', true));
395
- add_post_meta($tr_id, '_wp_attached_file', get_post_meta($this->source, '_wp_attached_file', true));
396
  } else {
397
- $tr_id = wp_insert_post($tr_post);
398
  }
399
 
400
- if ($tr_id) {
401
- $tr_lang = $this->pllm->get_language($locale);
402
- PLL()->model->post->set_language($tr_id, $tr_lang);
403
- $this->safe_translation_status_update($locale, 'current', array($tr_lang->slug => $tr_id));
404
- if ($status !== 100) {
405
- $this->safe_translation_status_update($locale, 'interim');
406
  }
407
- wp_set_object_terms($tr_id, $this->term_id, 'post_translations');
408
 
409
  // Copies categories and tags
410
- $GLOBALS['polylang']->sync->taxonomies->copy($this->source, $tr_id, $tr_lang->slug);
411
 
412
  // assign terms and metas
413
- $GLOBALS['polylang']->sync->post_metas->copy($this->source, $tr_id, $tr_lang->slug);
414
 
415
  // copy or ignore metas
416
- self::copy_or_ignore_metas($post->ID, $tr_id);
417
 
418
  // translate metas
419
- if (isset($translation['metas'])) {
420
- self::copy_translated_metas($translation['metas'], $tr_id);
421
  }
422
 
423
- if (class_exists('PLL_Share_Post_Slug', true) && $content_type_options[$post->post_type]['fields']['post_name'] == 1) {
424
- wp_update_post(array('ID' => $tr_id, 'post_name' => $post->post_name));
 
 
 
 
 
425
  }
426
- }
427
  }
428
 
429
  self::$creating_translation = false;
430
 
431
  // Adds content sanitization back in after Lingotek saves the translation
432
- add_filter('content_save_pre', 'wp_filter_post_kses');
433
- add_filter('content_filtered_save_pre', 'wp_filter_post_kses');
434
  }
435
 
436
  /**
437
- * TMS will return an associative array with empty fields if the translation is not ready.
438
  *
439
  * @param array $translation the array returned from TMS.
440
  */
441
- private function translation_not_ready($translation)
442
- {
443
- $trimmed_title = trim($translation['post']['post_title']);
444
- $trimmed_content = trim($translation['post']['post_content']);
445
- $trimmed_excerpt = trim($translation['post']['post_excerpt']);
446
- return empty($trimmed_title) &&
447
- empty($trimmed_content) &&
448
- empty($trimmed_excerpt);
449
  }
450
 
451
  /*
@@ -454,19 +467,18 @@ class Lingotek_Group_Post extends Lingotek_Group {
454
  * @since 1.0.9
455
  */
456
 
457
- public static function copy_or_ignore_metas($post_id, $tr_id)
458
- {
459
  // copy or ignore metas
460
- $custom_fields = get_option('lingotek_custom_fields', array());
461
- $post_custom_fields = get_post_meta($post_id);
462
- foreach ($post_custom_fields as $key => $source_meta) {
463
  // Set to blank string to ignore if no lingotek setting has been set.
464
- $setting = isset($custom_fields[$key]) ? $custom_fields[$key] : "";
465
- if ('copy' === $setting || 'hide-copy' === $setting) {
466
- $source_meta = current(get_post_meta($post_id, $key));
467
- update_post_meta($tr_id, $key, $source_meta);
468
- } elseif ('ignore' === $setting) {
469
- delete_post_meta($tr_id, $key);
470
  }
471
  }
472
  }
@@ -476,11 +488,11 @@ class Lingotek_Group_Post extends Lingotek_Group {
476
  *
477
  * @since 1.0.9
478
  */
479
- protected static function copy_translated_metas($translation_metas, $tr_id)
480
- {
481
- if (!empty($translation_metas)) {
482
- foreach ($translation_metas as $key => $meta)
483
- update_post_meta($tr_id, $key, $meta);
484
  }
485
  }
486
 
@@ -491,9 +503,8 @@ class Lingotek_Group_Post extends Lingotek_Group {
491
  *
492
  * @return bool
493
  */
494
- public function is_automatic_upload()
495
- {
496
- return 'automatic' == Lingotek_Model::get_profile_option('upload', get_post_type($this->source), $this->get_source_language(), false, $this->source) && parent::is_automatic_upload();
497
  }
498
 
499
  /*
@@ -503,9 +514,8 @@ class Lingotek_Group_Post extends Lingotek_Group {
503
  *
504
  * @return object
505
  */
506
- public function get_source_language()
507
- {
508
- return PLL()->model->post->get_language($this->source);
509
  }
510
 
511
  /*
@@ -513,13 +523,12 @@ class Lingotek_Group_Post extends Lingotek_Group {
513
  *
514
  * @since 1.0.9
515
  */
516
- protected static function save_hash_on_upload($object_id)
517
- {
518
- $post = get_post($object_id);
519
  $document_id = 'lingotek_hash_' . $post->ID;
520
- $new_hash = md5(Lingotek_Group_Post::get_content($post));
521
 
522
- wp_insert_term($document_id, 'lingotek_hash', array('description' => $new_hash));
523
- wp_set_object_terms($post->ID, $document_id, 'lingotek_hash');
524
  }
525
- }
7
  */
8
  class Lingotek_Group_Post extends Lingotek_Group {
9
 
10
+ // Preference constant used for downloaded translations.
11
+ const SAME_AS_SOURCE = 'SAME_AS_SOURCE';
12
  /*
13
  * set a translation term for an object
14
  *
18
  * @param object $language
19
  * @param string $document_id translation term name (Lingotek document id)
20
  */
21
+ public static function create( $object_id, $language, $document_id ) {
22
  $data = array(
23
+ 'lingotek' => array(
24
+ 'type' => get_post_type( $object_id ),
25
  'source' => $object_id,
26
  'status' => 'importing',
27
+ 'translations' => array(),
28
  ),
29
+ // For Polylang.
30
+ $language->slug => $object_id,
31
  );
32
+ self::save_hash_on_upload( $object_id );
33
+ self::_create( $object_id, $document_id, $data, 'post_translations' );
34
  }
35
 
36
  /*
41
  * @param string $post_type
42
  * @return array
43
  */
44
+ public static function get_content_type_fields( $post_type, $post_ID = null ) {
45
+ $cache_key = 'content_type_fields_' . $post_type;
46
+ $arr = wp_cache_get( $cache_key, 'lingotek' );
47
+ if ( ! $arr ) {
48
+ $arr = 'attachment' == $post_type ?
49
+ array(
50
+ 'post_title' => __( 'Title', 'lingotek-translation' ),
51
+ 'post_excerpt' => __( 'Caption', 'lingotek-translation' ),
52
+ 'metas' => array( '_wp_attachment_image_alt' => __( 'Alternative Text', 'lingotek-translation' ) ),
53
+ 'post_content' => __( 'Description', 'lingotek-translation' ),
54
+ ) : array(
55
+ 'post_title' => __( 'Title', 'lingotek-translation' ),
56
+ 'post_name' => __( 'Slug', 'lingotek-translation' ),
57
+ 'post_content' => __( 'Content', 'lingotek-translation' ),
58
+ 'post_excerpt' => __( 'Excerpt', 'lingotek-translation' ),
59
+ );
60
+
61
+ // if the user hasn't visited the custom fields tab, and hasn't saved actions for custom
62
+ // fields, and uploaded a post, check the wpml file for settings
63
+ if ( $post_ID ) {
64
+ self::get_updated_meta_values( $post_ID );
65
+ }
66
+ // add the custom fields from the lingotek_custom_fields option
67
+ $custom_fields = get_option( 'lingotek_custom_fields', array() );
68
+
69
+ if ( is_array( $custom_fields ) && ! empty( $custom_fields ) ) {
70
+ foreach ( $custom_fields as $cf => $setting ) {
71
+ if ( 'translate' == $setting ) {
72
+ $arr['metas'][ $cf ] = $cf;
73
+ }
74
+ }
75
+ }
76
+ wp_cache_set( $cache_key, $arr, 'lingotek', 300 );
77
+ }//end if
78
+ // allow plugins to modify the fields to translate
79
+ return apply_filters( 'lingotek_post_content_type_fields', $arr, $post_type );
80
+ }
81
+
82
+ /*
83
+ * returns custom fields from the wpml-config.xml file
84
+ *
85
+ * @since 0.2
86
+ *
87
+ * @param string $post_type
88
+ * @return array
89
+ */
90
+ public static function get_custom_fields_from_wpml() {
91
  $wpml_config = PLL_WPML_Config::instance();
92
+ $arr = array();
93
 
94
+ if ( isset( $wpml_config->tags['custom-fields'] ) ) {
95
+ foreach ( $wpml_config->tags['custom-fields'] as $context ) {
96
+ foreach ( $context['custom-field'] as $cf ) {
97
+ $arr[ $cf['value'] ] = $cf['attributes']['action'];
98
  }
99
  }
100
  }
101
 
102
  // allow plugins to modify the fields to translate
103
+ return apply_filters( 'lingotek_post_content_type_fields_from_wpml', $arr );
104
  }
105
 
106
  /*
110
  *
111
  * @return array
112
  */
113
+ public static function get_custom_fields_from_wp_postmeta( $post_ID = null ) {
114
+ $all_acf_fields = array();
115
+ $custom_fields = get_option( 'lingotek_custom_fields', array() );
116
+ $meta_black_list = array( '_encloseme', '_edit_last', '_edit_lock', '_wp_trash_meta_status', '_wp_trash_meta_time' );
117
+ $arr = array();
118
+ $keys = array();
119
+
120
+ if ( $post_ID ) {
121
+ $p = get_post( $post_ID );
 
122
  $posts[] = $p;
123
  } else {
124
+ $posts = get_posts(
125
+ array(
126
+ 'posts_per_page' => -1,
127
+ 'post_type' => 'post',
128
+ )
129
+ );
130
+ $pages = get_posts(
131
+ array(
132
+ 'posts_per_page' => -1,
133
+ 'post_type' => 'page',
134
+ )
135
+ );
136
+
137
+ $posts = array_merge( $posts, $pages );
138
  }
139
  //Only perform if ACF is installed and these functions are active
140
+ if ( function_exists( 'acf_get_field_groups' ) && function_exists( 'acf_get_fields' ) ) {
141
+ $groups = acf_get_field_groups();
142
+ $field_holder = array();
143
+ foreach ( $groups as $group ) {
144
+ if ( isset( $group['key'] ) ) {
145
+ $field_holder = acf_get_fields( $group['key'] );
146
+ foreach ( $field_holder as $field ) {
147
+ $field_data = array();
148
+ $field_data['meta_key'] = $field['name'];
149
  $field_data['meta_value'] = $field['key'];
150
+ $all_acf_fields[] = $field_data;
151
  }
152
  }
153
  }
154
  }
155
 
156
+ foreach ( $posts as $post ) {
157
+ $metadata = has_meta( $post->ID );
158
+ foreach ( $metadata as $key => $meta ) {
159
+ if ( in_array( $meta['meta_key'], $meta_black_list ) || in_array( $meta['meta_key'], $keys ) ) {
160
+ unset( $metadata[ $key ] );
161
  }
162
  $keys[] = $meta['meta_key'];
163
  }
164
+ $arr = array_merge( $arr, $metadata );
165
  }
166
+ $arr = array_merge( $arr, $all_acf_fields );
167
  // allow plugins to modify the fields to translate
168
+ return apply_filters( 'lingotek_post_custom_fields', $arr );
169
  }
170
 
171
  /*
175
  *
176
  * @return bool
177
  */
178
+ protected static function is_advanced_custom_fields_meta( $key, $value ) {
179
+ return ( ( substr( $key, 0, strlen( '_' ) ) === '_' ) && ( substr( $value, 0, strlen( 'field_' ) ) === 'field_' ) ) ? true : false;
 
180
  }
181
 
182
  /*
186
  *
187
  * @return array
188
  */
189
+ public static function get_updated_meta_values( $post_ID = null ) {
190
+ $custom_fields_from_wpml = self::get_custom_fields_from_wpml();
191
+ $custom_fields_from_postmeta = self::get_custom_fields_from_wp_postmeta( $post_ID );
192
+ $custom_fields_from_lingotek = get_option( 'lingotek_custom_fields', array() );
193
+ if ( ! is_array( $custom_fields_from_lingotek ) ) {
 
194
  $custom_fields_from_lingotek = array();
195
  }
196
+ $default_custom_fields = get_option( 'lingotek_default_custom_fields' ) ? get_option( 'lingotek_default_custom_fields' ) : 'ignore';
197
+ $custom_fields = array();
198
+ $items = array();
199
 
200
+ foreach ( $custom_fields_from_postmeta as $cf ) {
201
  // hide-copy means hide from user, and always copy to translations (Advanced Custom Fields plugin)
202
+ if ( self::is_advanced_custom_fields_meta( $cf['meta_key'], $cf['meta_value'] ) ) {
203
+ $custom_fields[ $cf['meta_key'] ] = 'hide-copy';
204
  continue;
205
  }
206
 
207
  // no lingotek setting
208
+ if ( ! array_key_exists( $cf['meta_key'], $custom_fields_from_lingotek ) ) {
209
  // no lingotek setting, but there's a wpml setting
210
+ if ( array_key_exists( $cf['meta_key'], $custom_fields_from_wpml ) ) {
211
+ $custom_fields[ $cf['meta_key'] ] = $custom_fields_from_wpml[ $cf['meta_key'] ];
212
  }
213
  // no lingotek setting, no wpml setting, so save default setting of ignore
214
  else {
215
+ $custom_fields[ $cf['meta_key'] ] = $default_custom_fields;
216
  }
217
  }
218
  // lingotek already has this field setting saved
219
  else {
220
+ $custom_fields[ $cf['meta_key'] ] = $custom_fields_from_lingotek[ $cf['meta_key'] ];
221
  }
222
+ }//end foreach
223
 
224
+ if ( $post_ID ) {
225
  // get_option sometimes returns empty string for `lingotek_custom_fields`
226
+ $custom_fields = is_array( $custom_fields_from_lingotek ) ? array_merge( $custom_fields_from_lingotek, $custom_fields ) : $custom_fields;
227
  }
228
+ update_option( 'lingotek_custom_fields', $custom_fields, false );
229
  }
230
 
231
  /*
236
  * @return array
237
  */
238
 
239
+ public static function get_cached_meta_values() {
240
+ $custom_fields_from_lingotek = get_option( 'lingotek_custom_fields', array() );
241
+ $items = array();
 
242
 
243
+ if ( is_array( $custom_fields_from_lingotek ) ) {
244
+ foreach ( $custom_fields_from_lingotek as $key => $setting ) {
245
+ if ( $setting === 'hide-copy' ) {
246
  continue;
247
  }
248
+ $arr = array(
249
  'meta_key' => $key,
250
+ 'setting' => $setting,
251
  );
252
  $items[] = $arr;
253
  }
263
  * @param object $post
264
  * @return string json encoded content to translate
265
  */
266
+ public static function get_content( $post ) {
267
+ $arr = array();
268
+ $fields = self::get_content_type_fields( $post->post_type, $post->ID );
269
+ $content_types = get_option( 'lingotek_content_type' );
270
+ $post_custom_fields = get_post_meta( $post->ID );
271
+ $meta_black_list = array( '_encloseme', '_edit_last', '_edit_lock', '_wp_trash_meta_status', '_wp_trash_meta_time' );
272
+ foreach ( array_keys( $fields ) as $key ) {
273
+ if ( 'metas' == $key ) {
274
+ foreach ( $post_custom_fields as $meta => $value ) {
275
  // check for advanced custom fields meta expects a string
276
  // so if array, check first item
277
+ $value = is_array( $value ) ? current( $value ) : $value;
278
+ if ( self::is_advanced_custom_fields_meta( $meta, $value ) || in_array( $meta, $meta_black_list ) ) {
279
  continue;
280
  }
281
  // Get all metas in array format
282
+ $meta_value = get_post_meta( $post->ID, $meta, true );
283
+ if ( $meta_value && isset( $fields['metas'][ $meta ] ) ) {
284
+ $arr['metas'][ $meta ] = $meta_value;
285
  }
286
  }
287
  // Check if acf is active and using these functions
288
+ $acf_empty_string = '';
289
+ if ( isset( $fields['metas'][ $acf_empty_string ] ) && function_exists( 'acf_get_field_groups' ) && function_exists( 'acf_get_fields' ) ) {
290
+ $arr['metas'][ $acf_empty_string ] = get_post_meta( $post->ID, $acf_empty_string, true );
291
  }
292
  }
293
  // send slug for translation only if it has been modified
294
+ elseif ( 'post_name' == $key && empty( $content_types[ $post->post_type ]['fields'][ $key ] ) ) {
295
+ // Default slug created by WordPress.
296
+ $default_slug = sanitize_title( $post->post_title );
297
  // if ($default_slug != $post->post_name)
298
+ $arr['post'][ $key ] = $post->$key;
299
+ } elseif ( empty( $content_types[ $post->post_type ]['fields'][ $key ] ) ) {
300
+ $arr['post'][ $key ] = $post->$key;
301
  }
302
+ }//end foreach
303
+ return json_encode( $arr );
304
  }
305
 
306
+ public static function is_valid_auto_upload_post_status( $post_status ) {
307
+ $prefs = Lingotek_Model::get_prefs();
 
308
  $valid_statuses = $prefs['auto_upload_post_statuses'];
309
+ $valid = isset( $valid_statuses[ $post_status ] ) && $valid_statuses[ $post_status ];
310
  return $valid;
311
  }
312
 
315
  *
316
  * @since 0.1
317
  */
318
+ public function request_translations() {
319
+ if ( isset( $this->source ) ) {
320
+ $language = PLL()->model->post->get_language( (int) $this->source );
321
+ $this->_request_translations( $language );
 
322
  }
323
  }
324
 
330
  *
331
  * @param string $locale
332
  */
333
+ public function create_translation( $locale, $automatic = false, $callback_type = null ) {
 
334
  // Removes content sanitization so YouTube videos, links, etc don't get removed when inserting translations
335
+ remove_filter( 'content_save_pre', 'wp_filter_post_kses' );
336
+ remove_filter( 'content_filtered_save_pre', 'wp_filter_post_kses' );
337
  $client = new Lingotek_API();
338
+ $status = $client->get_translation_status( $this->document_id, $locale );
339
 
340
+ if ( $status === -1 ) {
341
  return;
342
  }
343
 
344
+ $translation = $client->get_translation( $this->document_id, $locale, $this->source );
345
+ // If the request failed.
346
+ if ( ! $translation || $this->translation_not_ready( json_decode( $translation, true ) ) ) {
347
+ return;
348
+ }
349
+ // wp_insert_post expects array
350
+ $translation = json_decode( $translation, true );
351
 
352
  self::$creating_translation = true;
353
+ // Need an array by default.
354
+ $prefs = Lingotek_Model::get_prefs();
355
 
356
  $tr_post = $translation['post'];
357
+ if ( isset( $tr_post['post_name'] ) ) {
358
+ $tr_post['post_name'] = sanitize_title( $tr_post['post_name'] );
359
  }
360
 
361
+ // source post
362
+ $post = get_post( $this->source );
363
+ // status
364
+ $tr_post['post_status'] = ( $prefs['download_post_status'] === self::SAME_AS_SOURCE ) ? $post->post_status : $prefs['download_post_status'];
365
 
366
  // update existing translation
367
+ if ( $tr_id = PLL()->model->post->get( $this->source, $locale ) ) {
368
  $tr_post['ID'] = $tr_id;
369
 
370
  // copy or ignore metas
371
+ self::copy_or_ignore_metas( $post->ID, $tr_id );
372
 
373
  // translate metas
374
+ if ( isset( $translation['metas'] ) ) {
375
+ self::copy_translated_metas( $translation['metas'], $tr_id );
376
  }
377
 
378
+ wp_update_post( $tr_post );
379
+ if ( $status !== 100 ) {
380
+ $this->safe_translation_status_update( $locale, 'interim' );
381
  } else {
382
+ $this->safe_translation_status_update( $locale, 'current' );
383
  }
384
  }
385
 
386
  // create new translation
387
+ elseif ( ( $this->translations[ $locale ] == 'ready' || $this->translations[ $locale ] == 'pending' ) || $automatic ) {
388
+ $content_type_options = get_option( 'lingotek_content_type' );
389
+ if ( ! isset( $content_type_options[ $post->post_type ]['fields']['post_name'] ) ) {
390
+ // Forces the creation of a new default slug if not translated by Lingotek.
391
+ unset( $post->post_name );
392
  }
393
+ // Copy all untranslated fields from the original post.
394
+ $tr_post = array_merge( (array) $post, $tr_post );
395
+ // Will force the creation of a new post.
396
+ $tr_post['ID'] = null;
397
 
398
  // translate parent
399
+ $tr_post['post_parent'] = ( $post->post_parent && $tr_parent = $this->pllm->post->get_translation( $post->post_parent, $locale ) ) ? $tr_parent : 0;
400
 
401
+ if ( 'attachment' == $post->post_type ) {
402
+ $tr_id = wp_insert_attachment( $tr_post );
403
+ add_post_meta( $tr_id, '_wp_attachment_metadata', get_post_meta( $this->source, '_wp_attachment_metadata', true ) );
404
+ add_post_meta( $tr_id, '_wp_attached_file', get_post_meta( $this->source, '_wp_attached_file', true ) );
405
  } else {
406
+ $tr_id = wp_insert_post( $tr_post );
407
  }
408
 
409
+ if ( $tr_id ) {
410
+ $tr_lang = $this->pllm->get_language( $locale );
411
+ PLL()->model->post->set_language( $tr_id, $tr_lang );
412
+ $this->safe_translation_status_update( $locale, 'current', array( $tr_lang->slug => $tr_id ) );
413
+ if ( $status !== 100 ) {
414
+ $this->safe_translation_status_update( $locale, 'interim' );
415
  }
416
+ wp_set_object_terms( $tr_id, $this->term_id, 'post_translations' );
417
 
418
  // Copies categories and tags
419
+ $GLOBALS['polylang']->sync->taxonomies->copy( $this->source, $tr_id, $tr_lang->slug );
420
 
421
  // assign terms and metas
422
+ $GLOBALS['polylang']->sync->post_metas->copy( $this->source, $tr_id, $tr_lang->slug );
423
 
424
  // copy or ignore metas
425
+ self::copy_or_ignore_metas( $post->ID, $tr_id );
426
 
427
  // translate metas
428
+ if ( isset( $translation['metas'] ) ) {
429
+ self::copy_translated_metas( $translation['metas'], $tr_id );
430
  }
431
 
432
+ if ( class_exists( 'PLL_Share_Post_Slug', true ) && $content_type_options[ $post->post_type ]['fields']['post_name'] == 1 ) {
433
+ wp_update_post(
434
+ array(
435
+ 'ID' => $tr_id,
436
+ 'post_name' => $post->post_name,
437
+ )
438
+ );
439
  }
440
+ }//end if
441
  }
442
 
443
  self::$creating_translation = false;
444
 
445
  // Adds content sanitization back in after Lingotek saves the translation
446
+ add_filter( 'content_save_pre', 'wp_filter_post_kses' );
447
+ add_filter( 'content_filtered_save_pre', 'wp_filter_post_kses' );
448
  }
449
 
450
  /**
451
+ * TMS will return an associative array with empty fields if the translation is not ready.
452
  *
453
  * @param array $translation the array returned from TMS.
454
  */
455
+ private function translation_not_ready( $translation ) {
456
+ $trimmed_title = trim( $translation['post']['post_title'] );
457
+ $trimmed_content = trim( $translation['post']['post_content'] );
458
+ $trimmed_excerpt = trim( $translation['post']['post_excerpt'] );
459
+ return empty( $trimmed_title ) &&
460
+ empty( $trimmed_content ) &&
461
+ empty( $trimmed_excerpt );
 
462
  }
463
 
464
  /*
467
  * @since 1.0.9
468
  */
469
 
470
+ public static function copy_or_ignore_metas( $post_id, $tr_id ) {
 
471
  // copy or ignore metas
472
+ $custom_fields = get_option( 'lingotek_custom_fields', array() );
473
+ $post_custom_fields = get_post_meta( $post_id );
474
+ foreach ( $post_custom_fields as $key => $source_meta ) {
475
  // Set to blank string to ignore if no lingotek setting has been set.
476
+ $setting = isset( $custom_fields[ $key ] ) ? $custom_fields[ $key ] : '';
477
+ if ( 'copy' === $setting || 'hide-copy' === $setting ) {
478
+ $source_meta = current( get_post_meta( $post_id, $key ) );
479
+ update_post_meta( $tr_id, $key, $source_meta );
480
+ } elseif ( 'ignore' === $setting ) {
481
+ delete_post_meta( $tr_id, $key );
482
  }
483
  }
484
  }
488
  *
489
  * @since 1.0.9
490
  */
491
+ protected static function copy_translated_metas( $translation_metas, $tr_id ) {
492
+ if ( ! empty( $translation_metas ) ) {
493
+ foreach ( $translation_metas as $key => $meta ) {
494
+ update_post_meta( $tr_id, $key, $meta );
495
+ }
496
  }
497
  }
498
 
503
  *
504
  * @return bool
505
  */
506
+ public function is_automatic_upload() {
507
+ return 'automatic' == Lingotek_Model::get_profile_option( 'upload', get_post_type( $this->source ), $this->get_source_language(), false, $this->source ) && parent::is_automatic_upload();
 
508
  }
509
 
510
  /*
514
  *
515
  * @return object
516
  */
517
+ public function get_source_language() {
518
+ return PLL()->model->post->get_language( $this->source );
 
519
  }
520
 
521
  /*
523
  *
524
  * @since 1.0.9
525
  */
526
+ protected static function save_hash_on_upload( $object_id ) {
527
+ $post = get_post( $object_id );
 
528
  $document_id = 'lingotek_hash_' . $post->ID;
529
+ $new_hash = md5( self::get_content( $post ) );
530
 
531
+ wp_insert_term( $document_id, 'lingotek_hash', array( 'description' => $new_hash ) );
532
+ wp_set_object_terms( $post->ID, $document_id, 'lingotek_hash' );
533
  }
534
+ }
include/group-string.php CHANGED
@@ -14,10 +14,10 @@ class Lingotek_Group_String extends Lingotek_Group {
14
  *
15
  * @param object $term term translation object
16
  */
17
- protected function load($term) {
18
- parent::load($term);
19
  $this->name = $term->name;
20
- $this->md5 = &$this->desc_array['lingotek']['md5'];
21
  }
22
 
23
  /*
@@ -26,7 +26,15 @@ class Lingotek_Group_String extends Lingotek_Group {
26
  * @since 0.2
27
  */
28
  public function save() {
29
- wp_update_term((int) $this->term_id, $this->taxonomy, array('slug' => $this->document_id, 'name' => $this->name, 'description' => serialize($this->desc_array)));
 
 
 
 
 
 
 
 
30
  }
31
 
32
  /*
@@ -38,32 +46,44 @@ class Lingotek_Group_String extends Lingotek_Group {
38
  * @param object $language
39
  * @param string $document_id translation term name (Lingotek document id)
40
  */
41
- public static function create($name, $language, $document_id) {
42
  $desc = array(
43
  'lingotek' => array(
44
  'type' => 'string',
45
- 'md5' => md5(self::get_content($name)),
46
  'source' => $language->mo_id,
47
  'status' => 'importing',
48
- 'translations' => array()
49
  ),
50
  );
51
 
52
- $terms = wp_get_object_terms($language->mo_id, 'post_translations');
53
 
54
  // the translation already exists but was previously disassociated
55
- if ($key = array_search($name, wp_list_pluck($terms, 'name'))) {
56
- wp_update_term((int) $terms[$key]->term_id, 'post_translations', array('slug' => $document_id, 'name' => $name, 'description' => serialize($desc)));
57
- }
58
-
59
- else {
60
- wp_insert_term($name, 'post_translations', array('slug' => $document_id, 'description' => serialize($desc)));
61
- }
62
-
63
- wp_set_object_terms($language->mo_id, $document_id, 'post_translations', true); // add terms
64
-
 
 
 
 
 
 
 
 
 
 
 
 
65
  }
66
-
67
  /*
68
  * uploads a modified source
69
  *
@@ -72,18 +92,18 @@ class Lingotek_Group_String extends Lingotek_Group {
72
  * @param string $group group name
73
  * @param string $empty used for compatibility with parent class
74
  */
75
- public function patch($params, $group = '', $content = null) {
76
- $client = new Lingotek_API();
77
- $res = $client->patch_document($this->document_id, $params, $group);
78
-
79
- if ($res !== FALSE) {
80
- $this->md5 = md5($content);
81
- $this->status = 'importing';
82
- $this->translations = array_fill_keys(array_keys($this->translations), 'pending');
83
  $this->save();
84
  }
85
  }
86
-
87
  /*
88
  * returns the content to translate
89
  *
@@ -92,22 +112,24 @@ class Lingotek_Group_String extends Lingotek_Group {
92
  * @param object $group string group name
93
  * @return string json encoded content to translate
94
  */
95
- public static function get_content($group) {
96
- foreach (PLL_Admin_Strings::get_strings() as $string) {
97
- if ($string['context'] == $group)
98
- $arr[$string['string']] = $string['string'];
 
99
  }
100
- return json_encode($arr);
101
  }
102
-
103
  /*
104
  * requests translations to Lingotek TMS
105
  *
106
  * @since 0.2
107
  */
108
  public function request_translations() {
109
- if (isset($this->source))
110
- $this->_request_translations($this->get_source_language());
 
111
  }
112
 
113
  /*
@@ -118,26 +140,29 @@ class Lingotek_Group_String extends Lingotek_Group {
118
  *
119
  * @param string $locale
120
  */
121
- public function create_translation($locale) {
122
  $client = new Lingotek_API();
123
 
124
- if (false === ($translation = $client->get_translation($this->document_id, $locale, $this->name)))
125
  return;
 
126
 
127
- $strings = wp_list_pluck(PLL_Admin_Strings::get_strings(), 'name', 'string'); // get the strings name for the filter
128
- $translations = json_decode($translation, true); // wp_insert_post expects array
129
- $language = $this->pllm->get_language($locale);
 
 
130
 
131
  $mo = new PLL_MO();
132
- $mo->import_from_db($language);
133
 
134
- foreach ($translations as $key => $translation) {
135
- $translation = apply_filters('pll_sanitize_string_translation', $translation, $strings[$key], $this->name);
136
- $mo->add_entry($mo->make_entry($key, $translation));
137
  }
138
 
139
- $mo->export_to_db($language);
140
- $this->safe_translation_status_update($locale, 'current');
141
  }
142
 
143
  /*
@@ -148,7 +173,7 @@ class Lingotek_Group_String extends Lingotek_Group {
148
  * @return bool
149
  */
150
  public function is_automatic_upload() {
151
- return 'automatic' == Lingotek_Model::get_profile_option('upload', 'string', $this->get_source_language()) && parent::is_automatic_upload();
152
  }
153
 
154
  /*
@@ -159,6 +184,6 @@ class Lingotek_Group_String extends Lingotek_Group {
159
  * @return object
160
  */
161
  public function get_source_language() {
162
- return $this->pllm->get_language($this->pllm->options['default_lang']);
163
  }
164
- }
14
  *
15
  * @param object $term term translation object
16
  */
17
+ protected function load( $term ) {
18
+ parent::load( $term );
19
  $this->name = $term->name;
20
+ $this->md5 = &$this->desc_array['lingotek']['md5'];
21
  }
22
 
23
  /*
26
  * @since 0.2
27
  */
28
  public function save() {
29
+ wp_update_term(
30
+ (int) $this->term_id,
31
+ $this->taxonomy,
32
+ array(
33
+ 'slug' => $this->document_id,
34
+ 'name' => $this->name,
35
+ 'description' => serialize( $this->desc_array ),
36
+ )
37
+ );
38
  }
39
 
40
  /*
46
  * @param object $language
47
  * @param string $document_id translation term name (Lingotek document id)
48
  */
49
+ public static function create( $name, $language, $document_id ) {
50
  $desc = array(
51
  'lingotek' => array(
52
  'type' => 'string',
53
+ 'md5' => md5( self::get_content( $name ) ),
54
  'source' => $language->mo_id,
55
  'status' => 'importing',
56
+ 'translations' => array(),
57
  ),
58
  );
59
 
60
+ $terms = wp_get_object_terms( $language->mo_id, 'post_translations' );
61
 
62
  // the translation already exists but was previously disassociated
63
+ if ( $key = array_search( $name, wp_list_pluck( $terms, 'name' ) ) ) {
64
+ wp_update_term(
65
+ (int) $terms[ $key ]->term_id,
66
+ 'post_translations',
67
+ array(
68
+ 'slug' => $document_id,
69
+ 'name' => $name,
70
+ 'description' => serialize( $desc ),
71
+ )
72
+ );
73
+ } else {
74
+ wp_insert_term(
75
+ $name,
76
+ 'post_translations',
77
+ array(
78
+ 'slug' => $document_id,
79
+ 'description' => serialize( $desc ),
80
+ )
81
+ );
82
+ }//end if
83
+ // Add terms.
84
+ wp_set_object_terms( $language->mo_id, $document_id, 'post_translations', true );
85
  }
86
+
87
  /*
88
  * uploads a modified source
89
  *
92
  * @param string $group group name
93
  * @param string $empty used for compatibility with parent class
94
  */
95
+ public function patch( $params, $group = '', $content = null ) {
96
+ $client = new Lingotek_API();
97
+ $res = $client->patch_document( $this->document_id, $params, $group );
98
+
99
+ if ( $res !== false ) {
100
+ $this->md5 = md5( $content );
101
+ $this->status = 'importing';
102
+ $this->translations = array_fill_keys( array_keys( $this->translations ), 'pending' );
103
  $this->save();
104
  }
105
  }
106
+
107
  /*
108
  * returns the content to translate
109
  *
112
  * @param object $group string group name
113
  * @return string json encoded content to translate
114
  */
115
+ public static function get_content( $group ) {
116
+ foreach ( PLL_Admin_Strings::get_strings() as $string ) {
117
+ if ( $string['context'] == $group ) {
118
+ $arr[ $string['string'] ] = $string['string'];
119
+ }
120
  }
121
+ return json_encode( $arr );
122
  }
123
+
124
  /*
125
  * requests translations to Lingotek TMS
126
  *
127
  * @since 0.2
128
  */
129
  public function request_translations() {
130
+ if ( isset( $this->source ) ) {
131
+ $this->_request_translations( $this->get_source_language() );
132
+ }
133
  }
134
 
135
  /*
140
  *
141
  * @param string $locale
142
  */
143
+ public function create_translation( $locale ) {
144
  $client = new Lingotek_API();
145
 
146
+ if ( false === ( $translation = $client->get_translation( $this->document_id, $locale, $this->name ) ) ) {
147
  return;
148
+ }
149
 
150
+ // Get the strings name for the filter.
151
+ $strings = wp_list_pluck( PLL_Admin_Strings::get_strings(), 'name', 'string' );
152
+ // wp_insert_post expects array.
153
+ $translations = json_decode( $translation, true );
154
+ $language = $this->pllm->get_language( $locale );
155
 
156
  $mo = new PLL_MO();
157
+ $mo->import_from_db( $language );
158
 
159
+ foreach ( $translations as $key => $translation ) {
160
+ $translation = apply_filters( 'pll_sanitize_string_translation', $translation, $strings[ $key ], $this->name );
161
+ $mo->add_entry( $mo->make_entry( $key, $translation ) );
162
  }
163
 
164
+ $mo->export_to_db( $language );
165
+ $this->safe_translation_status_update( $locale, 'current' );
166
  }
167
 
168
  /*
173
  * @return bool
174
  */
175
  public function is_automatic_upload() {
176
+ return 'automatic' == Lingotek_Model::get_profile_option( 'upload', 'string', $this->get_source_language() ) && parent::is_automatic_upload();
177
  }
178
 
179
  /*
184
  * @return object
185
  */
186
  public function get_source_language() {
187
+ return $this->pllm->get_language( $this->pllm->options['default_lang'] );
188
  }
189
+ }
include/group-term.php CHANGED
@@ -17,18 +17,19 @@ class Lingotek_Group_Term extends Lingotek_Group {
17
  * @param object $language
18
  * @param string $document_id translation term name (Lingotek document id)
19
  */
20
- public static function create($object_id, $tax, $language, $document_id) {
21
  $data = array(
22
- 'lingotek' => array(
23
  'type' => $tax,
24
  'source' => $object_id,
25
  'status' => 'importing',
26
- 'translations' => array()
27
  ),
28
- $language->slug => $object_id // for Polylang
 
29
  );
30
 
31
- self::_create($object_id, $document_id, $data, 'term_translations');
32
  }
33
 
34
  /*
@@ -39,16 +40,16 @@ class Lingotek_Group_Term extends Lingotek_Group {
39
  * @param string $taxonomy
40
  * @return array
41
  */
42
- static public function get_content_type_fields($taxonomy) {
43
  $arr = array(
44
- 'name' => __('Name', 'lingotek-translation'),
45
  'args' => array(
46
- 'slug' => __('Slug', 'lingotek-translation'),
47
- 'description' => __('Description', 'lingotek-translation')
48
- )
49
  );
50
 
51
- return apply_filters('lingotek_term_content_type_fields', $arr, $taxonomy);
52
  }
53
 
54
  /*
@@ -59,24 +60,23 @@ class Lingotek_Group_Term extends Lingotek_Group {
59
  * @param object $term
60
  * @return string json encoded content to translate
61
  */
62
- public static function get_content($term) {
63
- $fields = self::get_content_type_fields($term->taxonomy);
64
- $content_types = get_option('lingotek_content_type');
65
-
66
- foreach (array_keys($fields) as $key) {
67
- if ('args' == $key) {
68
- foreach (array_keys($fields['args']) as $arg) {
69
- if (empty($content_types[$term->taxonomy]['fields']['args'][$arg]))
70
- $arr['args'][$arg] = $term->$arg;
 
71
  }
72
- }
73
-
74
- elseif (empty($content_types[$term->taxonomy]['fields'][$key])) {
75
- $arr[$key] = $term->$key;
76
  }
77
  }
78
 
79
- return json_encode($arr);
80
  }
81
 
82
  /*
@@ -85,9 +85,9 @@ class Lingotek_Group_Term extends Lingotek_Group {
85
  * @since 0.2
86
  */
87
  public function request_translations() {
88
- if (isset($this->source)) {
89
- $language = PLL()->model->term->get_language((int) $this->source);
90
- $this->_request_translations($language);
91
  }
92
  }
93
 
@@ -99,61 +99,62 @@ class Lingotek_Group_Term extends Lingotek_Group {
99
  *
100
  * @param string $locale
101
  */
102
- public function create_translation($locale) {
103
  $client = new Lingotek_API();
104
 
105
- if (false === ($translation = $client->get_translation($this->document_id, $locale, $this->source)))
106
  return;
 
107
 
108
  self::$creating_translation = true;
109
 
110
- $translation = json_decode($translation, true); // wp_insert_post expects array
111
- $args = $translation['args'];
 
112
 
113
  // update existing translation
114
- if ($tr_id = PLL()->model->term->get($this->source, $locale)) {
115
  $args['name'] = $translation['name'];
116
- wp_update_term($tr_id, $this->type, $args);
117
 
118
- $this->safe_translation_status_update($locale, 'current');
119
  }
120
 
121
  // create new translation
122
  else {
123
- $content_type_options = get_option('lingotek_content_type');
124
- $tr_lang = $this->pllm->get_language($locale);
125
 
126
  // translate parent
127
- $term = get_term($this->source, $this->type);
128
- $args['parent'] = ($term->parent && $tr_parent = PLL()->model->term->get_translation($term->parent, $locale)) ? $tr_parent : 0;
129
 
130
- if (class_exists('PLL_Share_Term_Slug', true) && isset($content_type_options[$this->type]['fields']['args']['slug'])) {
131
  remove_action( 'create_term', array( PLL()->filters_term, 'save_term' ), 999, 3 );
132
  remove_action( 'edit_term', array( PLL()->filters_term, 'save_term' ), 999, 3 );
133
- remove_action( 'pre_post_update', array( PLL()->filters_term, 'pre_post_update' ));
134
- remove_filter( 'pre_term_name', array( PLL()->filters_term, 'pre_term_name' ));
135
- remove_filter( 'pre_term_slug', array( PLL()->filters_term, 'pre_term_slug' ), 10, 2);
136
  add_action( 'pre_post_update', array( PLL()->share_term_slug, 'pre_post_update' ) );
137
  add_filter( 'pre_term_name', array( PLL()->share_term_slug, 'pre_term_name' ) );
138
  add_filter( 'pre_term_slug', array( PLL()->share_term_slug, 'pre_term_slug' ), 10, 2 );
139
  add_action( 'create_term', array( PLL()->share_term_slug, 'save_term' ), 1, 3 );
140
  add_action( 'edit_term', array( PLL()->share_term_slug, 'save_term' ), 1, 3 );
141
  $_POST['term_lang_choice'] = $tr_lang->slug;
142
- $args['slug'] = $term->slug;
143
- }
144
- else {
145
  // attempt to get a unique slug in case it already exists in another language
146
- if (isset($args['slug']) && term_exists($args['slug'])) {
147
  $args['slug'] .= '-' . $tr_lang->slug;
148
  }
149
  }
150
 
151
- $tr = wp_insert_term($translation['name'], $this->type, $args);
152
 
153
- if (!is_wp_error($tr)) {
154
- PLL()->model->term->set_language($tr['term_id'], $tr_lang);
155
- $this->safe_translation_status_update($locale, 'current', array($tr_lang->slug => $tr['term_id']));
156
- wp_set_object_terms($tr['term_id'], $this->term_id, 'term_translations');
157
  }
158
  }
159
 
@@ -168,7 +169,7 @@ class Lingotek_Group_Term extends Lingotek_Group {
168
  * @return bool
169
  */
170
  public function is_automatic_upload() {
171
- return 'automatic' == Lingotek_Model::get_profile_option('upload', $this->type, $this->get_source_language()) && parent::is_automatic_upload();
172
  }
173
 
174
  /*
@@ -179,6 +180,6 @@ class Lingotek_Group_Term extends Lingotek_Group {
179
  * @return object
180
  */
181
  public function get_source_language() {
182
- return PLL()->model->term->get_language($this->source);
183
  }
184
  }
17
  * @param object $language
18
  * @param string $document_id translation term name (Lingotek document id)
19
  */
20
+ public static function create( $object_id, $tax, $language, $document_id ) {
21
  $data = array(
22
+ 'lingotek' => array(
23
  'type' => $tax,
24
  'source' => $object_id,
25
  'status' => 'importing',
26
+ 'translations' => array(),
27
  ),
28
+ // for Polylang
29
+ $language->slug => $object_id,
30
  );
31
 
32
+ self::_create( $object_id, $document_id, $data, 'term_translations' );
33
  }
34
 
35
  /*
40
  * @param string $taxonomy
41
  * @return array
42
  */
43
+ public static function get_content_type_fields( $taxonomy ) {
44
  $arr = array(
45
+ 'name' => __( 'Name', 'lingotek-translation' ),
46
  'args' => array(
47
+ 'slug' => __( 'Slug', 'lingotek-translation' ),
48
+ 'description' => __( 'Description', 'lingotek-translation' ),
49
+ ),
50
  );
51
 
52
+ return apply_filters( 'lingotek_term_content_type_fields', $arr, $taxonomy );
53
  }
54
 
55
  /*
60
  * @param object $term
61
  * @return string json encoded content to translate
62
  */
63
+ public static function get_content( $term ) {
64
+ $fields = self::get_content_type_fields( $term->taxonomy );
65
+ $content_types = get_option( 'lingotek_content_type' );
66
+
67
+ foreach ( array_keys( $fields ) as $key ) {
68
+ if ( 'args' == $key ) {
69
+ foreach ( array_keys( $fields['args'] ) as $arg ) {
70
+ if ( empty( $content_types[ $term->taxonomy ]['fields']['args'][ $arg ] ) ) {
71
+ $arr['args'][ $arg ] = $term->$arg;
72
+ }
73
  }
74
+ } elseif ( empty( $content_types[ $term->taxonomy ]['fields'][ $key ] ) ) {
75
+ $arr[ $key ] = $term->$key;
 
 
76
  }
77
  }
78
 
79
+ return json_encode( $arr );
80
  }
81
 
82
  /*
85
  * @since 0.2
86
  */
87
  public function request_translations() {
88
+ if ( isset( $this->source ) ) {
89
+ $language = PLL()->model->term->get_language( (int) $this->source );
90
+ $this->_request_translations( $language );
91
  }
92
  }
93
 
99
  *
100
  * @param string $locale
101
  */
102
+ public function create_translation( $locale ) {
103
  $client = new Lingotek_API();
104
 
105
+ if ( false === ( $translation = $client->get_translation( $this->document_id, $locale, $this->source ) ) ) {
106
  return;
107
+ }
108
 
109
  self::$creating_translation = true;
110
 
111
+ // wp_insert_post expects array
112
+ $translation = json_decode( $translation, true );
113
+ $args = $translation['args'];
114
 
115
  // update existing translation
116
+ if ( $tr_id = PLL()->model->term->get( $this->source, $locale ) ) {
117
  $args['name'] = $translation['name'];
118
+ wp_update_term( $tr_id, $this->type, $args );
119
 
120
+ $this->safe_translation_status_update( $locale, 'current' );
121
  }
122
 
123
  // create new translation
124
  else {
125
+ $content_type_options = get_option( 'lingotek_content_type' );
126
+ $tr_lang = $this->pllm->get_language( $locale );
127
 
128
  // translate parent
129
+ $term = get_term( $this->source, $this->type );
130
+ $args['parent'] = ( $term->parent && $tr_parent = PLL()->model->term->get_translation( $term->parent, $locale ) ) ? $tr_parent : 0;
131
 
132
+ if ( class_exists( 'PLL_Share_Term_Slug', true ) && isset( $content_type_options[ $this->type ]['fields']['args']['slug'] ) ) {
133
  remove_action( 'create_term', array( PLL()->filters_term, 'save_term' ), 999, 3 );
134
  remove_action( 'edit_term', array( PLL()->filters_term, 'save_term' ), 999, 3 );
135
+ remove_action( 'pre_post_update', array( PLL()->filters_term, 'pre_post_update' ) );
136
+ remove_filter( 'pre_term_name', array( PLL()->filters_term, 'pre_term_name' ) );
137
+ remove_filter( 'pre_term_slug', array( PLL()->filters_term, 'pre_term_slug' ), 10, 2 );
138
  add_action( 'pre_post_update', array( PLL()->share_term_slug, 'pre_post_update' ) );
139
  add_filter( 'pre_term_name', array( PLL()->share_term_slug, 'pre_term_name' ) );
140
  add_filter( 'pre_term_slug', array( PLL()->share_term_slug, 'pre_term_slug' ), 10, 2 );
141
  add_action( 'create_term', array( PLL()->share_term_slug, 'save_term' ), 1, 3 );
142
  add_action( 'edit_term', array( PLL()->share_term_slug, 'save_term' ), 1, 3 );
143
  $_POST['term_lang_choice'] = $tr_lang->slug;
144
+ $args['slug'] = $term->slug;
145
+ } else {
 
146
  // attempt to get a unique slug in case it already exists in another language
147
+ if ( isset( $args['slug'] ) && term_exists( $args['slug'] ) ) {
148
  $args['slug'] .= '-' . $tr_lang->slug;
149
  }
150
  }
151
 
152
+ $tr = wp_insert_term( $translation['name'], $this->type, $args );
153
 
154
+ if ( ! is_wp_error( $tr ) ) {
155
+ PLL()->model->term->set_language( $tr['term_id'], $tr_lang );
156
+ $this->safe_translation_status_update( $locale, 'current', array( $tr_lang->slug => $tr['term_id'] ) );
157
+ wp_set_object_terms( $tr['term_id'], $this->term_id, 'term_translations' );
158
  }
159
  }
160
 
169
  * @return bool
170
  */
171
  public function is_automatic_upload() {
172
+ return 'automatic' == Lingotek_Model::get_profile_option( 'upload', $this->type, $this->get_source_language() ) && parent::is_automatic_upload();
173
  }
174
 
175
  /*
180
  * @return object
181
  */
182
  public function get_source_language() {
183
+ return PLL()->model->term->get_language( $this->source );
184
  }
185
  }
include/group.php CHANGED
@@ -1,110 +1,118 @@
1
  <?php
2
 
3
- /*
4
  * Abstract class for Translations groups objects
5
  *
6
  * @since 0.2
7
  */
8
  abstract class Lingotek_Group {
9
- static public $creating_translation; // used to avoid uploading a translation when using automatinc upload
 
10
 
11
- /*
12
  * constructor
13
  *
14
  * @since 0.2
15
  */
16
- public function __construct($term, &$pllm) {
17
  $this->pllm = &$pllm;
18
- $this->load($term);
19
  }
20
 
21
- /*
22
  * assigns this object properties from the underlying term
23
  *
24
  * @since 0.2
25
  *
26
  * @param object $term term translation object
27
  */
28
- protected function load($term) {
29
- $this->term_id = (int) $term->term_id;
30
- $this->tt_id = (int) $term->term_taxonomy_id;
31
  $this->document_id = $term->slug;
32
- $this->taxonomy = $term->taxonomy;
33
- $this->desc_array = unserialize($term->description);
34
 
35
- foreach (array('type', 'source', 'status', 'translations') as $prop)
36
- $this->$prop = &$this->desc_array['lingotek'][$prop];
 
37
  }
38
 
39
- /*
40
  * updates the translation term in DB
41
  *
42
  * @since 0.2
43
  */
44
  public function save() {
45
  $args = array(
46
- 'description' => serialize($this->desc_array),
47
- 'slug' => $this->document_id,
 
48
  );
49
- if (!empty($this->document_id)) {
50
- // Name is required for the term, cannot be null or empty
51
- $args['name'] = $this->document_id;
52
- }
53
- $update = wp_update_term((int) $this->term_id, $this->taxonomy, $args);
54
  }
55
 
56
- /*
57
  * provides a safe way to update the translations statuses when receiving "simultaneous" TMS callbacks
58
  *
59
  * @since 0.2
60
  *
61
  * @param string $locale
62
  * @param string $status
63
- * @param array $arr translations to add
64
  */
65
- protected function safe_translation_status_update($locale, $status, $arr = array()) {
66
  global $wpdb;
67
- $wpdb->query("LOCK TABLES $wpdb->term_taxonomy WRITE");
68
- $d = $wpdb->get_var($wpdb->prepare("SELECT description FROM $wpdb->term_taxonomy WHERE term_taxonomy_id = %d", $this->tt_id));
69
- $d = unserialize($d);
70
- $this->translations[$locale] = $d['lingotek']['translations'][$locale] = $status;
71
- $d = array_merge($d, $arr); // optionally add a new translation
72
- $d = serialize($d);
73
- $wpdb->query($wpdb->prepare("UPDATE $wpdb->term_taxonomy SET description = %s WHERE term_taxonomy_id = %d", $d, $this->tt_id));
74
- $wpdb->query("UNLOCK TABLES");
 
75
  }
76
 
77
- /*
78
  * creates a new term translation object in DB
79
  *
80
  * @since 0.2
81
  *
82
- * @param int $object_id the id of the object to translate
83
  * @param string $document_id Lingotek document id
84
- * @param array $desc data to store in the Lingotek array
85
  * @param string $taxonomy either 'post_translations' or 'term_translations'
86
  */
87
- protected static function _create($object_id, $document_id, $desc, $taxonomy) {
88
- $terms = wp_get_object_terms($object_id, $taxonomy);
89
- $term = array_pop($terms);
90
 
91
- if (empty($term)) {
92
- wp_insert_term($document_id, $taxonomy, array('description' => serialize($desc)));
93
  }
94
 
95
  // the translation already exists but was not managed by Lingotek
96
  else {
97
- if (is_array($old_desc = maybe_unserialize($term->description)))
98
- $desc = array_merge($old_desc, $desc);
99
- wp_update_term((int) $term->term_id, $taxonomy, array('slug' => $document_id, 'name' => $document_id, 'description' => serialize($desc)));
 
 
 
 
 
 
 
 
 
100
  }
101
 
102
- wp_set_object_terms($object_id, $document_id, $taxonomy);
103
  }
104
 
105
- /*
106
  * deletes translations downloaded from the Lingotek TMS
107
- *
108
  *
109
  * @since 0.2
110
  *
@@ -112,79 +120,79 @@ abstract class Lingotek_Group {
112
  */
113
  public function delete() {
114
  $client = new Lingotek_API();
115
- if ($client->cancel_document($this->document_id, $this->source)) {
116
- update_option("ignore_delete_pref", TRUE);
117
- unset($this->desc_array['lingotek']);
118
- foreach ($this->desc_array as $locale) {
119
- if ($locale !== $this->source) {
120
  wp_trash_post( $locale );
121
- unset($this->desc_array[$locale]);
122
  }
123
  }
124
  $this->save();
125
- wp_delete_term($this->term_id, $this->taxonomy);
126
- update_option("ignore_delete_pref", FALSE);
127
  } else {
128
- update_option('disassociate_source_failed', TRUE);
129
  }
130
  }
131
 
132
 
133
  /**
134
  * cancels translations from the Lingotek TMS
135
- *
136
  * @param bool $cancel whether to cancel the Lingotek document or not
137
  */
138
  public function cancel() {
139
  $client = new Lingotek_API();
140
- if ($client->cancel_document($this->document_id, $this->source)) {
141
- if (isset($this->desc_array['lingotek']['translations']) && count ($this->desc_array['lingotek']['translations']) > 0) {
142
- unset($this->desc_array['lingotek']['translations']);
143
  $this->desc_array['lingotek']['status'] = 'cancelled';
144
  } else {
145
- unset($this->desc_array['lingotek']);
146
  }
147
  } else {
148
- update_option('cancel_source_failed', TRUE);
149
  }
150
  $this->save();
151
  }
152
 
153
  /**
154
  * delete translation from the Lingotek TMS
155
- *
156
  * @param bool $cancel whether to cancel the Lingotek document or not
157
  */
158
- public function delete_translation($language, $id){
159
  $client = new Lingotek_API();
160
- if ($client->cancel_translation($this->document_id, $language->lingotek_locale, $id)) {
161
- update_option("ignore_delete_pref", TRUE);
162
- $this->desc_array['lingotek']['translations'][$language->locale] = 'cancelled';
163
- unset($this->desc_array[$language->locale]);
164
- wp_trash_post($id);
165
  $this->save();
166
- update_option("ignore_delete_pref", FALSE);
167
  } else {
168
- update_option('disassociate_target_failed', TRUE);
169
  }
170
  }
171
 
172
  /**
173
  * cancel target from the Lingotek TMS
174
- *
175
  * @param bool $cancel whether to cancel the Lingotek document or not
176
  */
177
- public function cancel_translation($language, $id) {
178
  $client = new Lingotek_API();
179
- if ($client->cancel_translation($this->document_id, $language->lingotek_locale, $id)) {
180
- $this->desc_array['lingotek']['translations'][$language->locale] = 'cancelled';
181
  $this->save();
182
  } else {
183
- update_option('cancel_target_failed', TRUE);
184
  }
185
  }
186
 
187
- /*
188
  * uploads a modified source
189
  *
190
  * @since 0.2
@@ -192,33 +200,33 @@ abstract class Lingotek_Group {
192
  * @param string $title
193
  * @param object $content can be a post object, a term object
194
  */
195
- public function patch($params) {
196
  $client = new Lingotek_API();
197
- $res = $client->patch_document($this->document_id, $params, $this->source);
198
 
199
- if ($res !== FALSE) {
200
- $this->document_id = $res;
201
- $this->status = 'importing';
202
- $this->translations = isset($this->translations) ? array_fill_keys(array_keys($this->translations), 'pending') : null;
203
  $this->save();
204
  }
205
  }
206
 
207
- /*
208
  * checks the status of source document
209
  *
210
  * @since 0.2
211
  */
212
- public function source_status() {
213
  $client = new Lingotek_API();
214
 
215
- if ('importing' == $this->status && $client->get_document_status($this->document_id)){
216
  $this->status = 'current';
217
  $this->save();
218
  }
219
  }
220
 
221
- /*
222
  * sets source status to ready
223
  *
224
  * @since 0.2
@@ -228,172 +236,166 @@ abstract class Lingotek_Group {
228
  $this->save();
229
  }
230
 
231
- /*
232
  * requests a translation to Lingotek TMS
233
  *
234
  * @since 0.2
235
  *
236
  * @param string $locale
237
  */
238
- public function request_translation($locale) {
239
- $workflow = $this->get_workflow_object($this->get_source_language(), $locale, $this->type, $this->source);
240
- if ($workflow->has_custom_request_procedure()) {
241
  $workflow->do_custom_request();
242
  } else {
243
- $client = new Lingotek_API();
244
- $language = $this->pllm->get_language($locale);
245
- $workflow = Lingotek_Model::get_profile_option('workflow_id', $this->type, $this->get_source_language(), $language, $this->source);
246
- if ('project-default' === $workflow) {
247
  $workflow = null;
248
  }
249
- $args = $workflow ? array('workflow_id' => $workflow) : array();
250
 
251
- if (!$this->is_disabled_target($language) && empty($this->translations[$language->locale])) {
252
  // don't change translations to pending if the api call failed
253
- if ($client->request_translation($this->document_id, $language->locale, $args, $this->source)) {
254
- $this->status = 'current';
255
- $this->translations[$language->locale] = 'pending';
256
  }
257
 
258
  $this->save();
259
  }
260
- }
261
  }
262
 
263
- /*
264
  * requests translations to Lingotek TMS
265
  *
266
  * @since 0.2
267
  *
268
  * @param object $source_language language of the source
269
  */
270
- protected function _request_translations($source_language) {
 
 
271
 
272
- $type_id = NULL;
273
- $client = new Lingotek_API();
274
-
275
- foreach ($this->pllm->get_languages_list() as $lang) {
276
- $workflow = $this->get_workflow_object($source_language, $lang->locale, $this->type, $this->source);
277
- if ($workflow->has_custom_request_procedure()) {
278
  $workflow->do_custom_request();
279
  } else {
280
- if ($source_language->slug != $lang->slug && !$this->is_disabled_target($source_language, $lang) && empty($this->translations[$lang->locale])) {
281
- $workflow = Lingotek_Model::get_profile_option('workflow_id', $this->type, $source_language, $lang, $this->source);
282
- if ('project-default' === $workflow) {
283
  $workflow = null;
284
  }
285
- $args = $workflow ? array('workflow_id' => $workflow) : array();
286
 
287
- if ($this->type == 'string') {
288
  $type_id = $this->name;
289
- }
290
- else {
291
  $type_id = $this->source;
292
  }
293
  // don't change translations to pending if the api call failed
294
- if ($client->request_translation($this->document_id, $lang->locale, $args, $type_id)) {
295
 
296
  /**
297
- * This is a fix that reloads the object before editing & saving it. The problem
298
- * was that the callbacks were coming back before this method finished so the
299
  * $this->translations array was out of sync with what was in the database. We fix this
300
  * by reading the DB only when we need to -> make our edit -> save the edit. This keeps us from holding on to
301
  * old data and overwritting the new data.
302
  */
303
- if ('post_translations' === $this->taxonomy) {
304
- $this->load( PLL()->model->post->get_object_term((int) $this->source, 'post_translations') );
305
- } else if ('term_translations' === $this->taxonomy) {
306
- $this->load( PLL()->model->term->get_object_term((int) $this->source, 'term_translations') );
307
  }
308
  $this->status = 'current';
309
- if (!isset($this->translations[$lang->locale]) || isset($this->translations[$lang->locale]) && $this->translations[$lang->locale] != 'current') {
310
- $this->translations[$lang->locale] = 'pending';
311
  }
312
  $this->save();
313
  }
314
- }
315
- }
316
- }
317
  }
318
 
319
  /**
320
- * Publicly exposes the safe_translation_status_update method that allows us to safely update
321
- * translation statuses. This method is used when a request translation call is made to bridge and that
322
- * translation was requested successfully.
323
- */
324
- public function update_translation_status($locale, $status)
325
- {
326
- $this->safe_translation_status_update($locale, $status);
327
  }
328
 
329
- /*
330
  * checks the translations status of a document
331
  *
332
  * @since 0.1
333
  */
334
  public function translations_status() {
335
- // $client = new Lingotek_API();
336
- // $translations = $client->get_translations_status($this->document_id, $this->source); // key are Lingotek locales
337
- // foreach($this->translations as $locale => $status) {
338
- // $lingotek_locale = $this->pllm->get_language($locale)->lingotek_locale;
339
- // if ('current' != $status && isset($translations[$lingotek_locale]) && 100 == $translations[$lingotek_locale])
340
- // $this->translations[$locale] = 'ready';
341
- // }
342
- // $this->save();
343
-
344
  $this->translation_status_hard_refresh();
345
  }
346
 
347
  public function translation_status_hard_refresh() {
348
  $client = new Lingotek_API();
349
- $translations = $client->get_translations_status($this->document_id, $this->source); // key are Lingotek locales
 
350
  $lingotek_locale_to_pll_locale = array();
351
- foreach (PLL()->model->get_languages_list() as $pll_language) {
352
- $lingotek_locale_to_pll_locale[$pll_language->lingotek_locale] = $pll_language->locale;
353
  }
354
- foreach ($translations as $lingotek_locale => $percent)
355
- {
356
- if (!isset($lingotek_locale_to_pll_locale[$lingotek_locale])) { continue; }
357
- $wp_locale = $lingotek_locale_to_pll_locale[$lingotek_locale];
358
-
359
- if ($translations[$lingotek_locale] < 100 && $this->translations[$wp_locale] !== 'interim') {
360
- $this->translations[$wp_locale] = 'pending';
361
- }
362
- else if ($this->translations[$wp_locale] === 'interim' && $translations[$lingotek_locale] === 100) {
363
- $this->translations[$wp_locale] = 'ready';
364
  }
365
- else if ((!isset($this->translations[$wp_locale])) || ($this->translations[$wp_locale] !== 'current') && $this->translations[$wp_locale] !== 'interim') {
366
- $this->translations[$wp_locale] = 'ready';
 
 
 
 
 
 
 
 
 
 
367
  }
368
  }
369
 
370
  $this->save();
371
  }
372
 
373
- /*
374
  * sets translation status to ready
375
  *
376
  * @since 0.1
377
  * @uses Lingotek_Group::safe_translation_status_update() as the status can be automatically set by the TMS callback
378
  */
379
- public function translation_ready($locale) {
380
- $this->safe_translation_status_update($locale, 'ready');
381
  }
382
 
383
- /*
384
  * attempts to create all translations from an object
385
  *
386
  * @since 0.2
387
  */
388
  public function create_translations() {
389
- if (isset($this->translations)) {
390
- foreach ($this->translations as $locale => $status)
391
- if ('pending' == $status || 'ready' == $status)
392
- $this->create_translation($locale);
 
 
393
  }
394
  }
395
 
396
- /*
397
  * sets document status to edited
398
  *
399
  * @since 0.1
@@ -403,7 +405,7 @@ abstract class Lingotek_Group {
403
  // $this->translations = array_fill_keys(array_keys($this->translations), 'not-current');
404
  $this->save();
405
  }
406
- /*
407
  * sets document status to failed_import
408
  *
409
  * @since 1.4.3
@@ -413,7 +415,7 @@ abstract class Lingotek_Group {
413
  $this->save();
414
  }
415
 
416
- /*
417
  * returns true if at least one of the translations has the requested status
418
  *
419
  * @since 0.2
@@ -421,11 +423,11 @@ abstract class Lingotek_Group {
421
  * @param string $status
422
  * @return bool
423
  */
424
- public function has_translation_status($status) {
425
- return isset($this->translations) && array_intersect(array_keys($this->translations, $status), $this->pllm->get_languages_list(array('fields' => 'locale')));
426
  }
427
 
428
- /*
429
  * checks if target should be automatically downloaded
430
  *
431
  * @since 0.2
@@ -433,27 +435,27 @@ abstract class Lingotek_Group {
433
  * @param string $locale
434
  * @return bool
435
  */
436
- public function is_automatic_download($locale) {
437
- return 'automatic' == Lingotek_Model::get_profile_option('download', $this->type, $this->get_source_language(), $this->pllm->get_language($locale), $this->source);
438
  }
439
 
440
  public function is_automatic_upload() {
441
- $workflow = $this->get_workflow_object($this->get_source_language(), false, $this->type, $this->source);
442
  $can_auto_upload = $workflow->auto_upload_allowed();
443
- if ($can_auto_upload) {
444
  /**
445
  * Check each of the translations and if one of them doesn't allow automatic upload then we don't auto upload the doc.
446
  */
447
- foreach ($this->translations as $locale => $progress) {
448
- $workflow = $this->get_workflow_object($this->get_source_language(), $locale, $this->type, $this->source);
449
  $can_auto_upload = $can_auto_upload && $workflow->auto_upload_allowed();
450
  }
451
  }
452
-
453
  return $can_auto_upload;
454
  }
455
 
456
- /*
457
  * checks if translation is disabled for a target language
458
  *
459
  * @since 0.2
@@ -461,13 +463,12 @@ abstract class Lingotek_Group {
461
  * @param string $type post type or taxonomy
462
  * @param object $language
463
  */
464
- public function is_disabled_target($language, $target = null) {
465
- $profile = Lingotek_Model::get_profile($this->type, $language, $this->source);
466
- if ($target) {
467
- return isset($profile['targets'][$target->slug]) && ('disabled' == $profile['targets'][$target->slug] || 'copy' == $profile['targets'][$target->slug]);
468
- }
469
- else {
470
- return isset($profile['targets'][$language->slug]) && ('disabled' == $profile['targets'][$language->slug] || 'copy' == $profile['targets'][$language->slug]);
471
  }
472
  }
473
 
@@ -480,15 +481,15 @@ abstract class Lingotek_Group {
480
  * @param object $source_language
481
  * @return void
482
  */
483
- public function pre_upload_to_lingotek($item_id, $type, $source_language, $item_type) {
484
- $workflow = $this->get_workflow_object($source_language, false, $type, $item_id);
485
- $workflow->pre_upload_to_lingotek($item_id, $item_type);
486
- foreach ($this->pllm->get_languages_list() as $lang) {
487
- if ($this->_is_disabled_target($lang, $type, $item_id)) {
488
  continue;
489
  }
490
- $workflow = $this->get_workflow_object($source_language, $lang->locale, $type, $item_id);
491
- $workflow->pre_upload_to_lingotek($item_id, $item_type);
492
  }
493
  }
494
 
@@ -501,14 +502,14 @@ abstract class Lingotek_Group {
501
  * @param object $source_language
502
  * @return void
503
  */
504
- public function pre_save_post($item_id, $type, $source_language) {
505
- $workflow = $this->get_workflow_object($source_language, false, $type, $item_id);
506
  $workflow->save_post_hook();
507
- foreach ($this->pllm->get_languages_list() as $lang) {
508
- if ($this->_is_disabled_target($lang, $type, $item_id)) {
509
  continue;
510
  }
511
- $workflow = $this->get_workflow_object($source_language, $lang->locale, $type, $item_id);
512
  $workflow->save_post_hook();
513
  }
514
  }
@@ -522,25 +523,25 @@ abstract class Lingotek_Group {
522
  * @param object $source_language
523
  * @return void
524
  */
525
- public function pre_save_terms($item_id, $type, $source_language) {
526
- $workflow = $this->get_workflow_object($source_language, false, $type, $item_id);
527
  $workflow->save_term_hook();
528
- foreach ($this->pllm->get_languages_list() as $lang) {
529
- if ($this->_is_disabled_target($lang, $type, $item_id)) {
530
  continue;
531
  }
532
- $workflow = $this->get_workflow_object($source_language, $lang->locale, $type, $item_id);
533
  $workflow->save_term_hook();
534
  }
535
  }
536
 
537
- public function get_custom_in_progress_icon($language) {
538
- $workflow = $this->get_workflow_object($this->get_source_language(), $language->locale, $this->type, $this->source);
539
  return $workflow->get_custom_in_progress_icon();
540
  }
541
 
542
  /**
543
- * Checks the source language and all of its target language's workflows to determine whether a bulk translation request is allowed.
544
  * If one or more of the workflows return true on has_custom_request_procedure() then the bulk translation request will be aborted.
545
  *
546
  * @param object $source_language
@@ -548,16 +549,18 @@ abstract class Lingotek_Group {
548
  * @param string $item_id
549
  * @return boolean
550
  */
551
- private function can_bulk_request_translations($source_language, $type, $item_id) {
552
- $workflow = $this->get_workflow_object($source_language, false, $type, $item_id);
553
- if ($workflow->has_custom_request_procedure()) { return false; }
 
554
 
555
- foreach ($this->pllm->get_languages_list() as $lang) {
556
- if ($this->_is_disabled_target($lang, $type, $item_id)) {
557
  continue;
558
  }
559
- $workflow = $this->get_workflow_object($source_language, $lang->locale, $type, $item_id);
560
- if ($workflow->has_custom_request_procedure()) { return false; }
 
561
  }
562
 
563
  return true;
@@ -565,30 +568,30 @@ abstract class Lingotek_Group {
565
 
566
  /**
567
  * Instantiates and returns a workflow object. If only the source language is passed in then it will return the workflow object
568
- * for the source locale; however, if a locale is passed in with the source language then a workflow object will be returned
569
  * for the locale.
570
  *
571
- * @param string $source_language
572
  * @param boolean | string $locale
573
- * @param string $type
574
- * @param string $item_id
575
  * @return void
576
  */
577
- private function get_workflow_object( $source_language, $locale = false, $type = null, $item_id = null ) {
578
- $target_language = ($locale) ? $this->pllm->get_language($locale) : false;
579
- $source_language = (!$source_language) ? PLL()->model->post->get_language( $this->source ) : $source_language;
580
- if ($type === 'post') {
581
- $post = ($item_id) ? get_post($item_id) : get_post( $this->source );
582
- $workflow_id = Lingotek_Model::get_profile_option( 'workflow_id', $post->post_type, $source_language, $target_language , $this->source );
583
  } else {
584
  $workflow_id = Lingotek_Model::get_profile_option( 'workflow_id', $type, $source_language, $target_language );
585
  }
586
- $workflow = Lingotek_Workflow_Factory::get_workflow_instance( $workflow_id );
587
  return $workflow;
588
  }
589
 
590
  /**
591
- * Checks if a target language has been disabled. Is different than the other is_disabled_target method by
592
  * allowing the caller to supply all of the arguments used.
593
  *
594
  * @param object $target_language
@@ -596,8 +599,8 @@ abstract class Lingotek_Group {
596
  * @param string $item_id
597
  * @return void
598
  */
599
- private function _is_disabled_target($target_language, $type, $item_id) {
600
- $profile = Lingotek_Model::get_profile($type, $target_language, $item_id);
601
- return isset($profile['targets'][$target_language->slug]) && ('disabled' == $profile['targets'][$target_language->slug] || 'cancelled' == $profile['targets'][$target_language->slug] || 'copy' == $profile['targets'][$target_language->slug]);
602
  }
603
- }
1
  <?php
2
 
3
+ /**
4
  * Abstract class for Translations groups objects
5
  *
6
  * @since 0.2
7
  */
8
  abstract class Lingotek_Group {
9
+ // used to avoid uploading a translation when using automatinc upload
10
+ public static $creating_translation;
11
 
12
+ /**
13
  * constructor
14
  *
15
  * @since 0.2
16
  */
17
+ public function __construct( $term, &$pllm ) {
18
  $this->pllm = &$pllm;
19
+ $this->load( $term );
20
  }
21
 
22
+ /**
23
  * assigns this object properties from the underlying term
24
  *
25
  * @since 0.2
26
  *
27
  * @param object $term term translation object
28
  */
29
+ protected function load( $term ) {
30
+ $this->term_id = (int) $term->term_id;
31
+ $this->tt_id = (int) $term->term_taxonomy_id;
32
  $this->document_id = $term->slug;
33
+ $this->taxonomy = $term->taxonomy;
34
+ $this->desc_array = unserialize( $term->description );
35
 
36
+ foreach ( array( 'type', 'source', 'status', 'translations' ) as $prop ) {
37
+ $this->$prop = &$this->desc_array['lingotek'][ $prop ];
38
+ }
39
  }
40
 
41
+ /**
42
  * updates the translation term in DB
43
  *
44
  * @since 0.2
45
  */
46
  public function save() {
47
  $args = array(
48
+ 'description' => serialize( $this->desc_array ),
49
+ 'slug' => $this->document_id,
50
+ 'name' => $this->document_id,
51
  );
52
+ wp_update_term( (int) $this->term_id, $this->taxonomy, $args );
 
 
 
 
53
  }
54
 
55
+ /**
56
  * provides a safe way to update the translations statuses when receiving "simultaneous" TMS callbacks
57
  *
58
  * @since 0.2
59
  *
60
  * @param string $locale
61
  * @param string $status
62
+ * @param array $arr translations to add
63
  */
64
+ protected function safe_translation_status_update( $locale, $status, $arr = array() ) {
65
  global $wpdb;
66
+ $wpdb->query( "LOCK TABLES $wpdb->term_taxonomy WRITE" );
67
+ $d = $wpdb->get_var( $wpdb->prepare( "SELECT description FROM $wpdb->term_taxonomy WHERE term_taxonomy_id = %d", $this->tt_id ) );
68
+ $d = unserialize( $d );
69
+ $this->translations[ $locale ] = $d['lingotek']['translations'][ $locale ] = $status;
70
+ // Optionally add a new translation.
71
+ $d = array_merge( $d, $arr );
72
+ $d = serialize( $d );
73
+ $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->term_taxonomy SET description = %s WHERE term_taxonomy_id = %d", $d, $this->tt_id ) );
74
+ $wpdb->query( 'UNLOCK TABLES' );
75
  }
76
 
77
+ /**
78
  * creates a new term translation object in DB
79
  *
80
  * @since 0.2
81
  *
82
+ * @param int $object_id the id of the object to translate
83
  * @param string $document_id Lingotek document id
84
+ * @param array $desc data to store in the Lingotek array
85
  * @param string $taxonomy either 'post_translations' or 'term_translations'
86
  */
87
+ protected static function _create( $object_id, $document_id, $desc, $taxonomy ) {
88
+ $terms = wp_get_object_terms( $object_id, $taxonomy );
89
+ $term = array_pop( $terms );
90
 
91
+ if ( empty( $term ) ) {
92
+ wp_insert_term( $document_id, $taxonomy, array( 'description' => serialize( $desc ) ) );
93
  }
94
 
95
  // the translation already exists but was not managed by Lingotek
96
  else {
97
+ if ( is_array( $old_desc = maybe_unserialize( $term->description ) ) ) {
98
+ $desc = array_merge( $old_desc, $desc );
99
+ }
100
+ wp_update_term(
101
+ (int) $term->term_id,
102
+ $taxonomy,
103
+ array(
104
+ 'slug' => $document_id,
105
+ 'name' => $document_id,
106
+ 'description' => serialize( $desc ),
107
+ )
108
+ );
109
  }
110
 
111
+ wp_set_object_terms( $object_id, $document_id, $taxonomy );
112
  }
113
 
114
+ /**
115
  * deletes translations downloaded from the Lingotek TMS
 
116
  *
117
  * @since 0.2
118
  *
120
  */
121
  public function delete() {
122
  $client = new Lingotek_API();
123
+ if ( $client->cancel_document( $this->document_id, $this->source ) ) {
124
+ update_option( 'ignore_delete_pref', true );
125
+ unset( $this->desc_array['lingotek'] );
126
+ foreach ( $this->desc_array as $locale ) {
127
+ if ( $locale !== $this->source ) {
128
  wp_trash_post( $locale );
129
+ unset( $this->desc_array[ $locale ] );
130
  }
131
  }
132
  $this->save();
133
+ wp_delete_term( $this->term_id, $this->taxonomy );
134
+ update_option( 'ignore_delete_pref', false );
135
  } else {
136
+ update_option( 'disassociate_source_failed', true );
137
  }
138
  }
139
 
140
 
141
  /**
142
  * cancels translations from the Lingotek TMS
143
+ *
144
  * @param bool $cancel whether to cancel the Lingotek document or not
145
  */
146
  public function cancel() {
147
  $client = new Lingotek_API();
148
+ if ( $client->cancel_document( $this->document_id, $this->source ) ) {
149
+ if ( isset( $this->desc_array['lingotek']['translations'] ) && count( $this->desc_array['lingotek']['translations'] ) > 0 ) {
150
+ unset( $this->desc_array['lingotek']['translations'] );
151
  $this->desc_array['lingotek']['status'] = 'cancelled';
152
  } else {
153
+ unset( $this->desc_array['lingotek'] );
154
  }
155
  } else {
156
+ update_option( 'cancel_source_failed', true );
157
  }
158
  $this->save();
159
  }
160
 
161
  /**
162
  * delete translation from the Lingotek TMS
163
+ *
164
  * @param bool $cancel whether to cancel the Lingotek document or not
165
  */
166
+ public function delete_translation( $language, $id ) {
167
  $client = new Lingotek_API();
168
+ if ( $client->cancel_translation( $this->document_id, $language->lingotek_locale, $id ) ) {
169
+ update_option( 'ignore_delete_pref', true );
170
+ $this->desc_array['lingotek']['translations'][ $language->locale ] = 'cancelled';
171
+ unset( $this->desc_array[ $language->locale ] );
172
+ wp_trash_post( $id );
173
  $this->save();
174
+ update_option( 'ignore_delete_pref', false );
175
  } else {
176
+ update_option( 'disassociate_target_failed', true );
177
  }
178
  }
179
 
180
  /**
181
  * cancel target from the Lingotek TMS
182
+ *
183
  * @param bool $cancel whether to cancel the Lingotek document or not
184
  */
185
+ public function cancel_translation( $language, $id ) {
186
  $client = new Lingotek_API();
187
+ if ( $client->cancel_translation( $this->document_id, $language->lingotek_locale, $id ) ) {
188
+ $this->desc_array['lingotek']['translations'][ $language->locale ] = 'cancelled';
189
  $this->save();
190
  } else {
191
+ update_option( 'cancel_target_failed', true );
192
  }
193
  }
194
 
195
+ /**
196
  * uploads a modified source
197
  *
198
  * @since 0.2
200
  * @param string $title
201
  * @param object $content can be a post object, a term object
202
  */
203
+ public function patch( $params ) {
204
  $client = new Lingotek_API();
205
+ $res = $client->patch_document( $this->document_id, $params, $this->source );
206
 
207
+ if ( $res !== false ) {
208
+ $this->document_id = $res;
209
+ $this->status = 'importing';
210
+ $this->translations = isset( $this->translations ) ? array_fill_keys( array_keys( $this->translations ), 'pending' ) : null;
211
  $this->save();
212
  }
213
  }
214
 
215
+ /**
216
  * checks the status of source document
217
  *
218
  * @since 0.2
219
  */
220
+ public function source_status() {
221
  $client = new Lingotek_API();
222
 
223
+ if ( 'importing' == $this->status && $client->get_document_status( $this->document_id ) ) {
224
  $this->status = 'current';
225
  $this->save();
226
  }
227
  }
228
 
229
+ /**
230
  * sets source status to ready
231
  *
232
  * @since 0.2
236
  $this->save();
237
  }
238
 
239
+ /**
240
  * requests a translation to Lingotek TMS
241
  *
242
  * @since 0.2
243
  *
244
  * @param string $locale
245
  */
246
+ public function request_translation( $locale ) {
247
+ $workflow = $this->get_workflow_object( $this->get_source_language(), $locale, $this->type, $this->source );
248
+ if ( $workflow->has_custom_request_procedure() ) {
249
  $workflow->do_custom_request();
250
  } else {
251
+ $client = new Lingotek_API();
252
+ $language = $this->pllm->get_language( $locale );
253
+ $workflow = Lingotek_Model::get_profile_option( 'workflow_id', $this->type, $this->get_source_language(), $language, $this->source );
254
+ if ( 'project-default' === $workflow ) {
255
  $workflow = null;
256
  }
257
+ $args = $workflow ? array( 'workflow_id' => $workflow ) : array();
258
 
259
+ if ( ! $this->is_disabled_target( $language ) && empty( $this->translations[ $language->locale ] ) ) {
260
  // don't change translations to pending if the api call failed
261
+ if ( $client->request_translation( $this->document_id, $language->locale, $args, $this->source ) ) {
262
+ $this->status = 'current';
263
+ $this->translations[ $language->locale ] = 'pending';
264
  }
265
 
266
  $this->save();
267
  }
268
+ }//end if
269
  }
270
 
271
+ /**
272
  * requests translations to Lingotek TMS
273
  *
274
  * @since 0.2
275
  *
276
  * @param object $source_language language of the source
277
  */
278
+ protected function _request_translations( $source_language ) {
279
+ $type_id = null;
280
+ $client = new Lingotek_API();
281
 
282
+ foreach ( $this->pllm->get_languages_list() as $lang ) {
283
+ $workflow = $this->get_workflow_object( $source_language, $lang->locale, $this->type, $this->source );
284
+ if ( $workflow->has_custom_request_procedure() ) {
 
 
 
285
  $workflow->do_custom_request();
286
  } else {
287
+ if ( $source_language->slug != $lang->slug && ! $this->is_disabled_target( $source_language, $lang ) && empty( $this->translations[ $lang->locale ] ) ) {
288
+ $workflow = Lingotek_Model::get_profile_option( 'workflow_id', $this->type, $source_language, $lang, $this->source );
289
+ if ( 'project-default' === $workflow ) {
290
  $workflow = null;
291
  }
292
+ $args = $workflow ? array( 'workflow_id' => $workflow ) : array();
293
 
294
+ if ( $this->type == 'string' ) {
295
  $type_id = $this->name;
296
+ } else {
 
297
  $type_id = $this->source;
298
  }
299
  // don't change translations to pending if the api call failed
300
+ if ( $client->request_translation( $this->document_id, $lang->locale, $args, $type_id ) ) {
301
 
302
  /**
303
+ * This is a fix that reloads the object before editing & saving it. The problem
304
+ * was that the callbacks were coming back before this method finished so the
305
  * $this->translations array was out of sync with what was in the database. We fix this
306
  * by reading the DB only when we need to -> make our edit -> save the edit. This keeps us from holding on to
307
  * old data and overwritting the new data.
308
  */
309
+ if ( 'post_translations' === $this->taxonomy ) {
310
+ $this->load( PLL()->model->post->get_object_term( (int) $this->source, 'post_translations' ) );
311
+ } elseif ( 'term_translations' === $this->taxonomy ) {
312
+ $this->load( PLL()->model->term->get_object_term( (int) $this->source, 'term_translations' ) );
313
  }
314
  $this->status = 'current';
315
+ if ( ! isset( $this->translations[ $lang->locale ] ) || isset( $this->translations[ $lang->locale ] ) && $this->translations[ $lang->locale ] != 'current' ) {
316
+ $this->translations[ $lang->locale ] = 'pending';
317
  }
318
  $this->save();
319
  }
320
+ }//end if
321
+ }//end if
322
+ }//end foreach
323
  }
324
 
325
  /**
326
+ * Publicly exposes the safe_translation_status_update method that allows us to safely update
327
+ * translation statuses. This method is used when a request translation call is made to bridge and that
328
+ * translation was requested successfully.
329
+ */
330
+ public function update_translation_status( $locale, $status ) {
331
+ $this->safe_translation_status_update( $locale, $status );
 
332
  }
333
 
334
+ /**
335
  * checks the translations status of a document
336
  *
337
  * @since 0.1
338
  */
339
  public function translations_status() {
 
 
 
 
 
 
 
 
 
340
  $this->translation_status_hard_refresh();
341
  }
342
 
343
  public function translation_status_hard_refresh() {
344
  $client = new Lingotek_API();
345
+ // Keys are Lingotek locales.
346
+ $translations = $client->get_translations_status( $this->document_id, $this->source );
347
  $lingotek_locale_to_pll_locale = array();
348
+ foreach ( PLL()->model->get_languages_list() as $pll_language ) {
349
+ $lingotek_locale_to_pll_locale[ $pll_language->lingotek_locale ] = $pll_language->locale;
350
  }
351
+ foreach ( $translations as $lingotek_locale => $locale_status ) {
352
+ if ( ! isset( $lingotek_locale_to_pll_locale[ $lingotek_locale ] ) ) {
353
+ continue;
 
 
 
 
 
 
 
354
  }
355
+ $wp_locale = $lingotek_locale_to_pll_locale[ $lingotek_locale ];
356
+
357
+ if ( $locale_status['percent_complete'] < 100 && $this->translations[ $wp_locale ] !== 'interim' ) {
358
+ if ( strtolower( $locale_status['progress'] ) === 'in_progress' ) {
359
+ $this->translations[ $wp_locale ] = 'ready';
360
+ } else {
361
+ $this->translations[ $wp_locale ] = 'pending';
362
+ }
363
+ } elseif ( $this->translations[ $wp_locale ] === 'interim' && $locale_status['percent_complete'] === 100 ) {
364
+ $this->translations[ $wp_locale ] = 'ready';
365
+ } elseif ( ( ! isset( $this->translations[ $wp_locale ] ) ) || ( $this->translations[ $wp_locale ] !== 'current' ) && $this->translations[ $wp_locale ] !== 'interim' ) {
366
+ $this->translations[ $wp_locale ] = 'ready';
367
  }
368
  }
369
 
370
  $this->save();
371
  }
372
 
373
+ /**
374
  * sets translation status to ready
375
  *
376
  * @since 0.1
377
  * @uses Lingotek_Group::safe_translation_status_update() as the status can be automatically set by the TMS callback
378
  */
379
+ public function translation_ready( $locale ) {
380
+ $this->safe_translation_status_update( $locale, 'ready' );
381
  }
382
 
383
+ /**
384
  * attempts to create all translations from an object
385
  *
386
  * @since 0.2
387
  */
388
  public function create_translations() {
389
+ if ( isset( $this->translations ) ) {
390
+ foreach ( $this->translations as $locale => $status ) {
391
+ if ( 'pending' == $status || 'ready' == $status ) {
392
+ $this->create_translation( $locale );
393
+ }
394
+ }
395
  }
396
  }
397
 
398
+ /**
399
  * sets document status to edited
400
  *
401
  * @since 0.1
405
  // $this->translations = array_fill_keys(array_keys($this->translations), 'not-current');
406
  $this->save();
407
  }
408
+ /**
409
  * sets document status to failed_import
410
  *
411
  * @since 1.4.3
415
  $this->save();
416
  }
417
 
418
+ /**
419
  * returns true if at least one of the translations has the requested status
420
  *
421
  * @since 0.2
423
  * @param string $status
424
  * @return bool
425
  */
426
+ public function has_translation_status( $status ) {
427
+ return isset( $this->translations ) && array_intersect( array_keys( $this->translations, $status ), $this->pllm->get_languages_list( array( 'fields' => 'locale' ) ) );
428
  }
429
 
430
+ /**
431
  * checks if target should be automatically downloaded
432
  *
433
  * @since 0.2
435
  * @param string $locale
436
  * @return bool
437
  */
438
+ public function is_automatic_download( $locale ) {
439
+ return 'automatic' == Lingotek_Model::get_profile_option( 'download', $this->type, $this->get_source_language(), $this->pllm->get_language( $locale ), $this->source );
440
  }
441
 
442
  public function is_automatic_upload() {
443
+ $workflow = $this->get_workflow_object( $this->get_source_language(), false, $this->type, $this->source );
444
  $can_auto_upload = $workflow->auto_upload_allowed();
445
+ if ( $can_auto_upload ) {
446
  /**
447
  * Check each of the translations and if one of them doesn't allow automatic upload then we don't auto upload the doc.
448
  */
449
+ foreach ( $this->translations as $locale => $progress ) {
450
+ $workflow = $this->get_workflow_object( $this->get_source_language(), $locale, $this->type, $this->source );
451
  $can_auto_upload = $can_auto_upload && $workflow->auto_upload_allowed();
452
  }
453
  }
454
+
455
  return $can_auto_upload;
456
  }
457
 
458
+ /**
459
  * checks if translation is disabled for a target language
460
  *
461
  * @since 0.2
463
  * @param string $type post type or taxonomy
464
  * @param object $language
465
  */
466
+ public function is_disabled_target( $language, $target = null ) {
467
+ $profile = Lingotek_Model::get_profile( $this->type, $language, $this->source );
468
+ if ( $target ) {
469
+ return isset( $profile['targets'][ $target->slug ] ) && ( 'disabled' == $profile['targets'][ $target->slug ] || 'copy' == $profile['targets'][ $target->slug ] );
470
+ } else {
471
+ return isset( $profile['targets'][ $language->slug ] ) && ( 'disabled' == $profile['targets'][ $language->slug ] || 'copy' == $profile['targets'][ $language->slug ] );
 
472
  }
473
  }
474
 
481
  * @param object $source_language
482
  * @return void
483
  */
484
+ public function pre_upload_to_lingotek( $item_id, $type, $source_language, $item_type ) {
485
+ $workflow = $this->get_workflow_object( $source_language, false, $type, $item_id );
486
+ $workflow->pre_upload_to_lingotek( $item_id, $item_type );
487
+ foreach ( $this->pllm->get_languages_list() as $lang ) {
488
+ if ( $this->_is_disabled_target( $lang, $type, $item_id ) ) {
489
  continue;
490
  }
491
+ $workflow = $this->get_workflow_object( $source_language, $lang->locale, $type, $item_id );
492
+ $workflow->pre_upload_to_lingotek( $item_id, $item_type );
493
  }
494
  }
495
 
502
  * @param object $source_language
503
  * @return void
504
  */
505
+ public function pre_save_post( $item_id, $type, $source_language ) {
506
+ $workflow = $this->get_workflow_object( $source_language, false, $type, $item_id );
507
  $workflow->save_post_hook();
508
+ foreach ( $this->pllm->get_languages_list() as $lang ) {
509
+ if ( $this->_is_disabled_target( $lang, $type, $item_id ) ) {
510
  continue;
511
  }
512
+ $workflow = $this->get_workflow_object( $source_language, $lang->locale, $type, $item_id );
513
  $workflow->save_post_hook();
514
  }
515
  }
523
  * @param object $source_language
524
  * @return void
525
  */
526
+ public function pre_save_terms( $item_id, $type, $source_language ) {
527
+ $workflow = $this->get_workflow_object( $source_language, false, $type, $item_id );
528
  $workflow->save_term_hook();
529
+ foreach ( $this->pllm->get_languages_list() as $lang ) {
530
+ if ( $this->_is_disabled_target( $lang, $type, $item_id ) ) {
531
  continue;
532
  }
533
+ $workflow = $this->get_workflow_object( $source_language, $lang->locale, $type, $item_id );
534
  $workflow->save_term_hook();
535
  }
536
  }
537
 
538
+ public function get_custom_in_progress_icon( $language ) {
539
+ $workflow = $this->get_workflow_object( $this->get_source_language(), $language->locale, $this->type, $this->source );
540
  return $workflow->get_custom_in_progress_icon();
541
  }
542
 
543
  /**
544
+ * Checks the source language and all of its target language's workflows to determine whether a bulk translation request is allowed.
545
  * If one or more of the workflows return true on has_custom_request_procedure() then the bulk translation request will be aborted.
546
  *
547
  * @param object $source_language
549
  * @param string $item_id
550
  * @return boolean
551
  */
552
+ private function can_bulk_request_translations( $source_language, $type, $item_id ) {
553
+ $workflow = $this->get_workflow_object( $source_language, false, $type, $item_id );
554
+ if ( $workflow->has_custom_request_procedure() ) {
555
+ return false; }
556
 
557
+ foreach ( $this->pllm->get_languages_list() as $lang ) {
558
+ if ( $this->_is_disabled_target( $lang, $type, $item_id ) ) {
559
  continue;
560
  }
561
+ $workflow = $this->get_workflow_object( $source_language, $lang->locale, $type, $item_id );
562
+ if ( $workflow->has_custom_request_procedure() ) {
563
+ return false; }
564
  }
565
 
566
  return true;
568
 
569
  /**
570
  * Instantiates and returns a workflow object. If only the source language is passed in then it will return the workflow object
571
+ * for the source locale; however, if a locale is passed in with the source language then a workflow object will be returned
572
  * for the locale.
573
  *
574
+ * @param string $source_language
575
  * @param boolean | string $locale
576
+ * @param string $type
577
+ * @param string $item_id
578
  * @return void
579
  */
580
+ private function get_workflow_object( $source_language, $locale = false, $type = null, $item_id = null ) {
581
+ $target_language = ( $locale ) ? $this->pllm->get_language( $locale ) : false;
582
+ $source_language = ( ! $source_language ) ? PLL()->model->post->get_language( $this->source ) : $source_language;
583
+ if ( $type === 'post' ) {
584
+ $post = ( $item_id ) ? get_post( $item_id ) : get_post( $this->source );
585
+ $workflow_id = Lingotek_Model::get_profile_option( 'workflow_id', $post->post_type, $source_language, $target_language, $this->source );
586
  } else {
587
  $workflow_id = Lingotek_Model::get_profile_option( 'workflow_id', $type, $source_language, $target_language );
588
  }
589
+ $workflow = Lingotek_Workflow_Factory::get_workflow_instance( $workflow_id );
590
  return $workflow;
591
  }
592
 
593
  /**
594
+ * Checks if a target language has been disabled. Is different than the other is_disabled_target method by
595
  * allowing the caller to supply all of the arguments used.
596
  *
597
  * @param object $target_language
599
  * @param string $item_id
600
  * @return void
601
  */
602
+ private function _is_disabled_target( $target_language, $type, $item_id ) {
603
+ $profile = Lingotek_Model::get_profile( $type, $target_language, $item_id );
604
+ return isset( $profile['targets'][ $target_language->slug ] ) && ( 'disabled' == $profile['targets'][ $target_language->slug ] || 'cancelled' == $profile['targets'][ $target_language->slug ] || 'copy' == $profile['targets'][ $target_language->slug ] );
605
  }
606
+ }
include/http.php CHANGED
@@ -11,31 +11,32 @@ class Lingotek_HTTP {
11
  const TIMEOUT = 30;
12
  /*
13
  * formats a request as multipart
14
- * greatly inspired from mailgun wordpress plugin
15
  *
16
  * @since 0.1
17
  */
18
- public function format_as_multipart(&$body) {
19
- $boundary = '----------------------------32052ee8fd2c'; // arbitrary boundary
 
20
 
21
  $this->headers['Content-Type'] = 'multipart/form-data; boundary=' . $boundary;
22
 
23
  $data = '';
24
 
25
- foreach ($body as $key => $value) {
26
- if (is_array($value)) {
27
- foreach($value as $k => $v) {
28
  $data .= '--' . $boundary . "\r\n";
29
  $data .= 'Content-Disposition: form-data; name="' . $key;
30
- if ($key !== 'translation_locale_code' && $key !== 'translation_workflow_id'){ //request targets cannot be in an array, they need to have the same key
 
31
  $data .= '[' . $k . ']';
32
- }
33
- $data.= "\"\r\n\r\n";
34
  $data .= $v . "\r\n";
35
  }
36
- }
37
- else {
38
- $data .= '--' . $boundary ."\r\n";
39
  $data .= 'Content-Disposition: form-data; name="' . $key . '"' . "\r\n\r\n";
40
  $data .= $value . "\r\n";
41
  }
@@ -49,12 +50,19 @@ class Lingotek_HTTP {
49
  *
50
  * @since 0.1
51
  */
52
- public function post($url, $args = array(), $custom_timeout = false) {
53
- Lingotek::log("POST $url");
54
- if (!empty($args)) {
55
- Lingotek::log($args);
56
- }
57
- return wp_remote_post($url, array('headers' => $this->headers, 'body' => $args, 'timeout' => ($custom_timeout) ? $custom_timeout : self::TIMEOUT));
 
 
 
 
 
 
 
58
  }
59
 
60
  /*
@@ -62,25 +70,40 @@ class Lingotek_HTTP {
62
  *
63
  * @since 0.1
64
  */
65
- public function get($url, $args = array()) {
66
- Lingotek::log("GET $url");
67
- if (!empty($args)) {
68
- Lingotek::log($args);
69
- }
70
- return wp_remote_get($url, array('headers' => $this->headers, 'body' => $args, 'timeout' => self::TIMEOUT));
71
- }
 
 
 
 
 
 
 
72
 
73
- /*
74
  * send a DELETE request
75
  *
76
  * @since 0.1
77
  */
78
- public function delete($url, $args = array()) {
79
- Lingotek::log("DELETE $url");
80
- if (!empty($args)) {
81
- Lingotek::log($args);
82
- }
83
- return wp_remote_request($url, array('method' => 'DELETE', 'headers' => $this->headers, 'body' => $args, 'timeout' => self::TIMEOUT));
 
 
 
 
 
 
 
 
84
  }
85
 
86
  /*
@@ -88,11 +111,19 @@ class Lingotek_HTTP {
88
  *
89
  * @since 0.1
90
  */
91
- public function patch($url, $args = array()) {
92
- Lingotek::log("PATCH $url");
93
- if (!empty($args)) {
94
- Lingotek::log($args);
95
- }
96
- return wp_remote_request($url, array('method' => 'PATCH', 'headers' => $this->headers, 'body' => $args, 'timeout' => self::TIMEOUT));
 
 
 
 
 
 
 
 
97
  }
98
  }
11
  const TIMEOUT = 30;
12
  /*
13
  * formats a request as multipart
14
+ * greatly inspired from mailgun WordPress plugin
15
  *
16
  * @since 0.1
17
  */
18
+ public function format_as_multipart( &$body ) {
19
+ // Arbitrary boundary.
20
+ $boundary = '----------------------------32052ee8fd2c';
21
 
22
  $this->headers['Content-Type'] = 'multipart/form-data; boundary=' . $boundary;
23
 
24
  $data = '';
25
 
26
+ foreach ( $body as $key => $value ) {
27
+ if ( is_array( $value ) ) {
28
+ foreach ( $value as $k => $v ) {
29
  $data .= '--' . $boundary . "\r\n";
30
  $data .= 'Content-Disposition: form-data; name="' . $key;
31
+ // Request targets cannot be in an array, as they need to have the same key.
32
+ if ( $key !== 'translation_locale_code' && $key !== 'translation_workflow_id' ) {
33
  $data .= '[' . $k . ']';
34
+ }
35
+ $data .= "\"\r\n\r\n";
36
  $data .= $v . "\r\n";
37
  }
38
+ } else {
39
+ $data .= '--' . $boundary . "\r\n";
 
40
  $data .= 'Content-Disposition: form-data; name="' . $key . '"' . "\r\n\r\n";
41
  $data .= $value . "\r\n";
42
  }
50
  *
51
  * @since 0.1
52
  */
53
+ public function post( $url, $args = array(), $custom_timeout = false ) {
54
+ Lingotek::log( "POST $url" );
55
+ if ( ! empty( $args ) ) {
56
+ Lingotek::log( $args );
57
+ }
58
+ return wp_remote_post(
59
+ $url,
60
+ array(
61
+ 'headers' => $this->headers,
62
+ 'body' => $args,
63
+ 'timeout' => ( $custom_timeout ) ? $custom_timeout : self::TIMEOUT,
64
+ )
65
+ );
66
  }
67
 
68
  /*
70
  *
71
  * @since 0.1
72
  */
73
+ public function get( $url, $args = array() ) {
74
+ Lingotek::log( "GET $url" );
75
+ if ( ! empty( $args ) ) {
76
+ Lingotek::log( $args );
77
+ }
78
+ return wp_remote_get(
79
+ $url,
80
+ array(
81
+ 'headers' => $this->headers,
82
+ 'body' => $args,
83
+ 'timeout' => self::TIMEOUT,
84
+ )
85
+ );
86
+ }
87
 
88
+ /*
89
  * send a DELETE request
90
  *
91
  * @since 0.1
92
  */
93
+ public function delete( $url, $args = array() ) {
94
+ Lingotek::log( "DELETE $url" );
95
+ if ( ! empty( $args ) ) {
96
+ Lingotek::log( $args );
97
+ }
98
+ return wp_remote_request(
99
+ $url,
100
+ array(
101
+ 'method' => 'DELETE',
102
+ 'headers' => $this->headers,
103
+ 'body' => $args,
104
+ 'timeout' => self::TIMEOUT,
105
+ )
106
+ );
107
  }
108
 
109
  /*
111
  *
112
  * @since 0.1
113
  */
114
+ public function patch( $url, $args = array() ) {
115
+ Lingotek::log( "PATCH $url" );
116
+ if ( ! empty( $args ) ) {
117
+ Lingotek::log( $args );
118
+ }
119
+ return wp_remote_request(
120
+ $url,
121
+ array(
122
+ 'method' => 'PATCH',
123
+ 'headers' => $this->headers,
124
+ 'body' => $args,
125
+ 'timeout' => self::TIMEOUT,
126
+ )
127
+ );
128
  }
129
  }
include/logger.php CHANGED
@@ -1,44 +1,48 @@
1
  <?php
2
 
3
  /*
4
- * This class handles logging events by giving the option to report / subscribe to logging events
5
  *
6
  * @since 1.3.1
7
  */
8
  class Lingotek_Logger {
9
 
10
- public static function fatal($message, $extra_data = null, $error = null){ Lingotek_Logger::log("fatal", $message, $extra_data, $error); }
11
- public static function error($message, $extra_data = null, $error = null){ Lingotek_Logger::log("error", $message, $extra_data, $error); }
12
- public static function warning($message, $extra_data = null, $error = null){ Lingotek_Logger::log("warning", $message, $extra_data, $error); }
13
- public static function info($message, $extra_data = null){ Lingotek_Logger::log("info", $message, $extra_data); }
14
- public static function debug($message, $extra_data = null){ Lingotek_Logger::log("debug", $message, $extra_data); }
 
 
 
 
 
15
 
16
- private static function log($level, $message, $extra_data, $error = null){
17
- try{
18
- do_action( 'lingotek_log', $level, $message, $extra_data, $error );
19
- do_action( 'lingotek_log_'.$level, $message, $extra_data, $error );
20
- $prefs = Lingotek_Model::get_prefs();
21
- $logging = isset($prefs['enable_lingotek_logs']) && '1' === $prefs['enable_lingotek_logs']['enabled'] ? true : false;
22
- $is_logging = $logging ? "true" : "false";
23
- if ($logging){
24
- $serialized_extra_data = Lingotek_Logger::serialize_extra_data($extra_data);
25
- $errorMessage = isset($error) && !isempty($error) ? ", Error: ".$error : "";
26
- error_log($level.": ".$message.$errorMessage.", ExtraData: ".$serialized_extra_data);
27
- }
28
- }
29
- catch (Exception $e){
30
- error_log('error occured while trying to write Lingotek log entry');
31
- }
32
- }
33
 
34
- private static function serialize_extra_data($extra_data){
35
- try
36
- {
37
- if (is_string($extra_data)) return $extra_data;
38
- return json_encode($extra_data, JSON_PRETTY_PRINT);
39
- }
40
- catch (Exception $e){
41
- return "";
42
- }
43
- }
44
- }
1
  <?php
2
 
3
  /*
4
+ * This class handles logging events by giving the option to report / subscribe to logging events
5
  *
6
  * @since 1.3.1
7
  */
8
  class Lingotek_Logger {
9
 
10
+ public static function fatal( $message, $extra_data = null, $error = null ) {
11
+ self::log( 'fatal', $message, $extra_data, $error ); }
12
+ public static function error( $message, $extra_data = null, $error = null ) {
13
+ self::log( 'error', $message, $extra_data, $error ); }
14
+ public static function warning( $message, $extra_data = null, $error = null ) {
15
+ self::log( 'warning', $message, $extra_data, $error ); }
16
+ public static function info( $message, $extra_data = null ) {
17
+ self::log( 'info', $message, $extra_data ); }
18
+ public static function debug( $message, $extra_data = null ) {
19
+ self::log( 'debug', $message, $extra_data ); }
20
 
21
+ private static function log( $level, $message, $extra_data, $error = null ) {
22
+ try {
23
+ do_action( 'lingotek_log', $level, $message, $extra_data, $error );
24
+ do_action( 'lingotek_log_' . $level, $message, $extra_data, $error );
25
+ $prefs = Lingotek_Model::get_prefs();
26
+ $logging = isset( $prefs['enable_lingotek_logs'] ) && '1' === $prefs['enable_lingotek_logs']['enabled'] ? true : false;
27
+ $is_logging = $logging ? 'true' : 'false';
28
+ if ( $logging ) {
29
+ $serialized_extra_data = self::serialize_extra_data( $extra_data );
30
+ $errorMessage = isset( $error ) && ! isempty( $error ) ? ', Error: ' . $error : '';
31
+ error_log( $level . ': ' . $message . $errorMessage . ', ExtraData: ' . $serialized_extra_data );
32
+ }
33
+ } catch ( Exception $e ) {
34
+ error_log( 'error occured while trying to write Lingotek log entry' );
35
+ }
36
+ }
 
37
 
38
+ private static function serialize_extra_data( $extra_data ) {
39
+ try {
40
+ if ( is_string( $extra_data ) ) {
41
+ return $extra_data;
42
+ }
43
+ return json_encode( $extra_data, JSON_PRETTY_PRINT );
44
+ } catch ( Exception $e ) {
45
+ return '';
46
+ }
47
+ }
48
+ }
include/model.php CHANGED
@@ -1,17 +1,24 @@
1
  <?php
2
 
3
- /*
4
  * Manages interactions with database
5
  * Factory for Lingotek_Group objects
6
  *
7
  * @since 0.1
8
  */
9
  class Lingotek_Model {
10
- public $pllm; // Polylang model
11
- static public $copying_post;
12
- static public $copying_term;
13
 
14
- /*
 
 
 
 
 
 
 
 
 
 
15
  * constructor
16
  *
17
  * @since 0.1
@@ -19,11 +26,29 @@ class Lingotek_Model {
19
  public function __construct() {
20
  $this->pllm = $GLOBALS['polylang']->model;
21
 
22
- register_taxonomy('lingotek_profile', null , array('label' => false, 'public' => false, 'query_var' => false, 'rewrite' => false));
23
- register_taxonomy('lingotek_hash', null , array('label' => false, 'public' => false, 'query_var' => false, 'rewrite' => false));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  }
25
 
26
- /*
27
  * get the strings groups as well as their count
28
  *
29
  * @since 0.2
@@ -32,19 +57,20 @@ class Lingotek_Model {
32
  */
33
  public static function get_strings() {
34
  static $strings = array();
35
- if (empty($strings)) {
36
- PLL_Admin_Strings::init(); // enables sanitization filter
 
37
 
38
- foreach (PLL_Admin_Strings::get_strings() as $string) {
39
- $strings[$string['context']]['context'] = $string['context'];
40
- $strings[$string['context']]['count'] = empty($strings[$string['context']]['count']) ? 1 : $strings[$string['context']]['count'] + 1;
41
  }
42
- $strings = array_values($strings);
43
  }
44
  return $strings;
45
  }
46
 
47
- /*
48
  * create a translation group object from a translation term
49
  *
50
  * @since 0.2
@@ -52,59 +78,59 @@ class Lingotek_Model {
52
  * @param object $term
53
  * @return object
54
  */
55
- protected function convert_term($term) {
56
- switch($term->taxonomy) {
57
  case 'term_translations':
58
- return new Lingotek_Group_Term($term, $this->pllm);
59
 
60
  case 'post_translations':
61
- $class = $term->name == $term->slug ? 'Lingotek_Group_Post' : 'Lingotek_Group_String';
62
- return new $class($term, $this->pllm);
63
  }
64
  }
65
 
66
- /*
67
  * get the translation term of an object
68
  *
69
  * @since 0.2
70
  *
71
- * @param string $type either 'post' or 'term' or 'string'
72
- * @param int|string $id post id or term id or strings translations group name
73
- * @return object translation term
74
  */
75
- public function get_group($type, $id) {
76
- switch ($type) {
77
  case 'post':
78
- return ($post = PLL()->model->post->get_object_term((int) $id, $type . '_translations')) && !empty($post) ? $this->convert_term($post) : false;
79
  case 'term':
80
- return ($term = PLL()->model->term->get_object_term((int) $id, $type . '_translations')) && !empty($term) ? $this->convert_term($term) : false;
81
  case 'string':
82
- if (is_numeric($id)) {
83
  $strings = self::get_strings();
84
- $id = $strings[$id]['context'];
85
  }
86
- return ($term = get_term_by('name', $id, 'post_translations')) && !empty($term) ? $this->convert_term($term) : false;
87
  default:
88
  return false;
89
  }
90
  }
91
 
92
- /*
93
- * get document id of an object, false if it wasn't uploaded yet.
94
- *
95
- * @since 1.4.11
96
- *
97
- * @param string $type either 'post' or 'term' or 'string'
98
- * @param int|string $id post id or term id or strings translations group name
99
- * @return string|bool document id or false
100
- */
101
- public function get_document_id($type, $id) {
102
- $document_term = $this->get_group($type, $id );
103
- $document_id = $document_term != false ? $document_term->document_id : false;
104
- return $document_id;
105
- }
106
-
107
- /*
108
  * get the translation term of an object by its Lingotek document id
109
  *
110
  * @since 0.2
@@ -112,16 +138,17 @@ class Lingotek_Model {
112
  * @param string|object $document_id
113
  * @return object translation term
114
  */
115
- public function get_group_by_id($document_id) {
116
  // we already passed a translation group object
117
- if (is_object($document_id))
118
  return $document_id;
 
119
 
120
- $terms = get_terms(array('post_translations', 'term_translations'), array('slug' => $document_id));
121
- return is_wp_error($terms) || empty($terms) ? false : $this->convert_term(reset($terms));
122
  }
123
 
124
- /*
125
  * get a translation profile
126
  *
127
  * @since 0.2
@@ -130,96 +157,106 @@ class Lingotek_Model {
130
  * @param object $language
131
  * @return array
132
  */
133
- static public function get_profile($type, $language, $post_id = null) {
134
  global $profileInformation, $ltk_profiles, $ltk_contentTypes;
135
 
136
- if (is_null($ltk_profiles)) {
137
- $ltk_profiles = get_option('lingotek_profiles');
138
  }
139
- if ($post_id && $profileInformation && isset($profileInformation[$type]) && isset($profileInformation[$type][$language->locale]) && isset($profileInformation[$type][$language->locale][$post_id])) {
140
- return $ltk_profiles[$profileInformation[$type][$language->locale][$post_id]];
141
  }
142
 
143
- if (is_null($ltk_contentTypes)) {
144
- $ltk_contentTypes = get_option('lingotek_content_type');
145
  }
146
 
147
  // If a profile is set for a specific post/page get that first
148
- if ($post_id) {
149
- $profileOverride = get_term_by('name', 'lingotek_profile_' . $post_id, 'lingotek_profile');
150
- if ($profileOverride) {
151
- if (!isset($profileInformation)) { $profileInformation = array(); }
152
- if (!isset($profileInformation[$type])) { $profileInformation[$type] = array(); }
153
- if (!isset($profileInformation[$type][$language->locale])) { $profileInformation[$type][$language->locale] = array(); }
154
- $profileInformation[$type][$language->locale][$post_id] = $profileOverride->description;
155
- return $ltk_profiles[$profileOverride->description];
 
 
 
156
  }
157
  }
158
 
159
- // default profile is manual except for post. Custom types are set to disabled by default.
160
  $default = 'post' === $type || 'page' === $type ? 'manual' : 'disabled';
161
 
162
- $profile = is_object($language) && isset($content_types[$type]['sources'][$language->slug]) ?
163
- $ltk_contentTypes[$type]['sources'][$language->slug] :
164
- (isset($ltk_contentTypes[$type]['profile']) ? $ltk_contentTypes[$type]['profile'] : $default);
165
-
166
- if ($post_id) {
167
- if (!isset($profileInformation)) { $profileInformation = array(); }
168
- if (!isset($profileInformation[$type])) { $profileInformation[$type] = array(); }
169
- if (!isset($profileInformation[$type][$language->locale])) { $profileInformation[$type][$language->locale] = array(); }
170
- $profileInformation[$type][$language->locale][$post_id] = $profile;
 
 
 
171
  }
172
 
173
- return $ltk_profiles[$profile];
174
  }
175
 
176
- static public function get_prefs() {
177
  $default = array(
178
- 'download_post_status' => Lingotek_Group_Post::SAME_AS_SOURCE,
179
  'auto_upload_post_statuses' => array(
180
- 'draft' => 0, // ignore auto-upload
181
- 'pending' => 1, // auto-upload
 
 
182
  'publish' => 1,
183
- 'future' => 1,
184
  'private' => 0,
185
  ),
186
- 'trash_linked_content' => array(
187
-
188
- ),
189
- 'auto_update_status' => '10',
190
- 'enable_lingotek_logs' => 0,
191
  );
192
- $prefs = array_merge($default, get_option('lingotek_prefs', $default)); // ensure defaults are set for missing keys
 
193
  return $prefs;
194
  }
195
 
196
- /*
197
  * get a profile option
198
  *
199
  * @since 0.2
200
  *
201
- * @param string $item 'project_id' | 'workflow_id' | 'upload' | 'download'
202
- * @param string $type post type or taxonomy
203
  * @param object $source_language
204
- * @param object $target_language optional, needed to get custom target informations 'workflow_id' | 'download'
205
- * @return string | bool either the option or false if the translation is disabled
206
  */
207
- static public function get_profile_option($item, $type, $source_language, $target_language = false, $post_id = null) {
208
- $profile = self::get_profile($type, $source_language, $post_id);
209
- if ('disabled' === $profile['profile'] || is_object($target_language) && isset($profile['targets'][$target_language->slug]) && 'disabled' === $profile['targets'][$target_language->slug])
210
  return false;
 
 
 
 
 
211
 
212
- if (!empty($target_language) && isset($profile['targets'][$target_language->slug]) && !empty($profile['custom'][$item][$target_language->slug]))
213
- return $profile['custom'][$item][$target_language->slug];
 
214
 
215
- if (!empty($profile[$item]))
216
- return $profile[$item];
217
-
218
- $defaults = get_option('lingotek_defaults');
219
- return isset($defaults[$item]) ? $defaults[$item] : null;
220
  }
221
 
222
- /*
223
  * find targets that are set to copy in a profile
224
  *
225
  * @since 1.1.1
@@ -227,17 +264,16 @@ class Lingotek_Model {
227
  * @param array $profile (use get_profile to retrieve)
228
  * @return array of targets that should be copied. if none exist returns empty array
229
  */
230
- public function targets_to_be_copied($profile) {
231
- if (isset($profile['targets']) && in_array('copy', $profile['targets'])) {
232
- $targets_to_copy = array_keys($profile['targets'], 'copy');
233
  return $targets_to_copy;
234
- }
235
- else {
236
  return array();
237
  }
238
  }
239
 
240
- /*
241
  * copy a post from the source language to a target language
242
  *
243
  * @since 1.1.1
@@ -246,87 +282,93 @@ class Lingotek_Model {
246
  * @param string $target polylang language slug (ex: en, de, fr, etc)
247
  * @return $new_post_id if copy of post is successful, false otherwise
248
  */
249
- public function copy_post($post, $target) {
250
- self::$copying_post = true;
251
- $document = $this->get_group('post', $post->ID);
252
- $prefs = self::get_prefs();
253
- $cp_lang = $this->pllm->get_language($target);
254
- $cp_post = (array) $post;
255
- $cp_post['post_status'] = ($prefs['download_post_status'] === 'SAME_AS_SOURCE')? $post->post_status : $prefs['download_post_status']; // status
256
- $slug = $cp_post['post_name'];
257
- unset($cp_post['ID']);
258
- unset($cp_post['post_name']);
259
- if (!isset($document->desc_array[$target])) {
260
- $new_post_id = wp_insert_post($cp_post, true);
261
- if (!is_wp_error($new_post_id)) {
262
- PLL()->model->post->set_language($new_post_id, $cp_lang);
263
- wp_set_object_terms($new_post_id, $document->term_id, 'post_translations');
264
- $GLOBALS['polylang']->sync->taxonomies->copy($document->source, $new_post_id, $cp_lang->slug);
265
- $GLOBALS['polylang']->sync->post_metas->copy($document->source, $new_post_id, $cp_lang->slug);
266
- Lingotek_Group_Post::copy_or_ignore_metas($post->ID, $new_post_id);
267
- $document->desc_array[$target] = $new_post_id;
268
  $document->save();
269
- if (class_exists('PLL_Share_Post_Slug', true)) {
270
- wp_update_post(array('ID' => $new_post_id ,'post_name' => $slug));
 
 
 
 
 
271
  }
272
  }
273
  }
274
  self::$copying_post = false;
275
  }
276
 
277
- public function copy_term($term, $target, $taxonomy) {
278
  self::$copying_term = true;
279
- $document = $this->get_group('term', $term->term_id);
280
- $cp_lang = $this->pllm->get_language($target);
281
- $cp_term = (array) $term;
282
- //unset($cp_term['term_id']);
283
 
284
- if (class_exists('PLL_Share_Term_Slug', true)) {
285
  remove_action( 'create_term', array( PLL()->filters_term, 'save_term' ), 999, 3 );
286
  remove_action( 'edit_term', array( PLL()->filters_term, 'save_term' ), 999, 3 );
287
- remove_action( 'pre_post_update', array( PLL()->filters_term, 'pre_post_update' ));
288
- remove_filter( 'pre_term_name', array( PLL()->filters_term, 'pre_term_name' ));
289
- remove_filter( 'pre_term_slug', array( PLL()->filters_term, 'pre_term_slug' ), 10, 2);
290
  add_action( 'pre_post_update', array( PLL()->share_term_slug, 'pre_post_update' ) );
291
  add_filter( 'pre_term_name', array( PLL()->share_term_slug, 'pre_term_name' ) );
292
  add_filter( 'pre_term_slug', array( PLL()->share_term_slug, 'pre_term_slug' ), 10, 2 );
293
  add_action( 'create_term', array( PLL()->share_term_slug, 'save_term' ), 1, 3 );
294
  add_action( 'edit_term', array( PLL()->share_term_slug, 'save_term' ), 1, 3 );
295
  $_POST['term_lang_choice'] = $cp_lang->slug;
296
- }
297
- else {
298
- if (isset($cp_term['slug']) && term_exists($cp_term['slug'])) {
299
  $cp_term['slug'] .= '-' . $cp_lang->slug;
300
  }
301
  }
302
 
303
- $new_term = wp_insert_term($cp_term['name'], $taxonomy, $cp_term);
304
 
305
- if (!is_wp_error($new_term)) {
306
- PLL()->model->term->set_language($new_term['term_id'], $cp_lang);
307
- wp_set_object_terms($new_term['term_id'], $document->term_id, 'term_translations');
308
- $document->desc_array[$target] = $new_term['term_id'];
309
  $document->save();
310
  }
311
  self::$copying_term = false;
312
  }
313
 
314
- private function format_patch_params($params, $profile, $source_lang) {
315
- $params['translation_locale_code'] = [];
316
- $params['translation_workflow_id'] = [];
317
 
318
- foreach ($this->pllm->get_languages_list() as $lang) {
319
- if ($lang->lingotek_locale == $source_lang->lingotek_locale
320
- || (isset($profile['targets'][$lang->slug]) && $profile['targets'][$lang->slug] == 'disabled')) {
321
  continue;
322
  }
323
  $params['translation_locale_code'][] = $lang->lingotek_locale;
324
- if (isset($profile['custom']['workflow_id'][$lang->slug])) {
325
- $params['translation_workflow_id'][] = $profile['custom']['workflow_id'][$lang->slug];
 
 
 
326
  }
327
  }
328
- if (empty($params['translation_workflow_id'])) {
329
- unset($params['translation_workflow_id']);
330
  }
331
  return $params;
332
  }
@@ -337,75 +379,86 @@ class Lingotek_Model {
337
  * @since 0.1
338
  *
339
  * @param int $post_id
 
340
  */
341
- public function upload_post($post_id) {
342
- $post = get_post($post_id);
343
- $language = PLL()->model->post->get_language($post_id);
344
- $profile = self::get_profile($post->post_type, $language, $post_id);
345
- if ('disabled' == $profile['profile'] || empty($post) || empty($language)) {
346
  return;
347
  }
348
- $document_id = self::get_document_id('post', $post_id);
 
 
 
 
 
349
  $content = null;
350
  // If we already uploaded this doc, check if it changed and prevent the upload if it didn't.
351
- if ($document_id) {
352
- $content = Lingotek_Group_Post::get_content($post);
353
- $hash_terms = wp_get_object_terms($post->ID, 'lingotek_hash');
354
- $hash_term = array_pop($hash_terms);
355
- $new_hash = md5( $content );
356
- if (!empty($hash_term)) {
357
  if ( $hash_term->description == $new_hash ) {
358
  return;
359
  }
360
  }
361
  }
362
- $document = $this->get_group('post', $post_id);
363
  // Customized workflows have the option to do any sort of pre-processing before a document
364
  // is uploaded to lingotek.
365
- if ($document) {
366
- $document->pre_upload_to_lingotek($post_id, $post->post_type, $language, 'post');
367
- }
368
-
369
- $client = new Lingotek_API();
370
- $external_url = get_page_link($post_id);
371
- if (!$content) {
372
- $content = Lingotek_Group_Post::get_content($post);
373
- }
374
- $params = $this->build_params($external_url, $post->post_title, $post->post_type, $content, $language, $profile, $post_id, $wp_target_locales);
375
- $filter_ids = $this->get_filter_ids($post->post_type, $language, $post_id);
376
- $params = array_merge($params, $filter_ids);
377
- if ($document && in_array($document->status, array('edited', 'importing', 'current', 'cancelled')) && $document_id) {
378
- $document->patch($this->format_patch_params($params, $profile, $language));
379
- // Re-establish hash relation if needed
380
- if (!isset($hash_term->term_id)) {
381
- $hash_terms = wp_set_post_terms($post->ID, 'lingotek_hash_' . $post->ID, "lingotek_hash");
382
- $hash_term_id = array_pop($hash_terms);
383
- } else {
384
- $hash_term_id = $hash_term->id;
385
- }
386
- wp_update_term($hash_term_id, 'lingotek_hash', array('description' => $new_hash));
387
- } elseif (!Lingotek_Group::$creating_translation && !self::$copying_post && (!$document || $document->document_id )) {
388
- $document_id = $client->upload_document($params, $post->ID);
389
 
390
- if ($document_id) {
391
- Lingotek_Group_Post::create($post->ID , $language, $document_id);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
392
  $document = $this->get_group_by_id( $document_id );
393
- if (isset($wp_target_locales)) {
394
- foreach ($wp_target_locales as $locale){
395
- $document->translations[$locale] = 'pending';
396
  }
397
  }
398
  $document->save();
399
  // If a translation profile has targets set to copy then copy them
400
- $targets_to_copy = $this->targets_to_be_copied($profile);
401
- $upload = self::get_profile_option('upload', $post->post_type, $language, false, $post_id);
402
- if (!empty($targets_to_copy) && $upload == 'automatic') {
403
- foreach ($targets_to_copy as $target) {
404
- $this->copy_post($post, $target);
405
  }
406
  }
 
407
  }
408
- }
 
409
  }
410
 
411
  /**
@@ -413,122 +466,124 @@ class Lingotek_Model {
413
  *
414
  * @since 0.2
415
  *
416
- * @param int $term_id
417
  * @param string $taxonomy
418
  */
419
- public function upload_term($term_id, $taxonomy) {
420
- $term = get_term($term_id, $taxonomy);
421
- $language = PLL()->model->term->get_language($term_id);
422
- if (empty($term) || empty($language))
423
  return;
 
424
 
425
- $profile = self::get_profile($taxonomy, $language);
426
- if ('disabled' == $profile['profile'])
427
  return;
 
428
 
429
  /**
430
  * Customized workflows have the option to do any sort of pre-processing before a document is uploaded to lingotek.
431
  */
432
- $document = $this->get_group('term', $term_id);
433
- if ($document) {
434
- $document->pre_upload_to_lingotek($term_id, $taxonomy, $language, 'term');
435
  }
436
 
437
- $client = new Lingotek_API();
438
- $content = Lingotek_Group_Term::get_content($term);
439
- $params = $this->build_params(get_term_link( $term_id, $taxonomy ), $term->name, $taxonomy, $content, $language, $profile, $term_id, $wp_target_locales);
440
- $filter_ids = $this->get_filter_ids($taxonomy, $language, $term_id);
441
- $params = array_merge($params, $filter_ids);
442
-
443
- if (($document = $this->get_group('term', $term_id)) && 'edited' == $document->status) {
444
- $document->patch($this->format_patch_params($params, $profile, $language), $term->name, $term);
445
- }
446
 
447
- elseif (!Lingotek_Group::$creating_translation && !self::$copying_term) {
448
- $document_id = $client->upload_document($params, $term_id);
 
 
449
 
450
- if ($document_id) {
451
- Lingotek_Group_Term::create($term_id, $taxonomy , $language, $document_id);
452
  $document = $this->get_group_by_id( $document_id );
453
- foreach ($wp_target_locales as $locale){
454
- $document->translations[$locale] = 'pending';
455
  }
456
  $document->save();
457
-
458
  // If a translation profile has targets set to copy then copy them
459
- $targets_to_copy = $this->targets_to_be_copied($profile);
460
- if (!empty($targets_to_copy) && $profile['upload'] == 'automatic') {
461
- foreach ($targets_to_copy as $target) {
462
- $this->copy_term($term, $target, $taxonomy);
463
  }
464
  }
465
  }
466
- }
467
  }
468
 
469
- /*
470
  * uploads a strings group to Lingotek TMS
471
  *
472
  * @since 0.2
473
  *
474
  * @param string $group
475
  */
476
- public function upload_strings($group) {
477
- $type = 'string';
478
- $language = $this->pllm->get_language($this->pllm->options['default_lang']);
479
- $profile = self::get_profile($type, $language);
480
 
481
- if ('disabled' == $profile['profile'])
482
  return;
 
483
 
484
- if (is_numeric($group)) {
485
  $strings = self::get_strings();
486
- $group = $strings[$group]['context'];
487
  }
488
 
489
  // check that we have a valid string group
490
- if (!in_array($group, wp_list_pluck(self::get_strings(), 'context')))
491
  return;
 
492
 
493
- $client = new Lingotek_API();
494
- $content = Lingotek_Group_String::get_content($group);
495
- $params = $this->build_params('', $group, $type, $content, $language, $profile, null);
496
- $filter_ids = $this->get_filter_ids($type, $language, null);
497
- $params = array_merge($params, $filter_ids);
498
 
499
- if (($document = $this->get_group($type, $group)) && 'edited' == $document->status) {
500
- $document->patch($this->format_patch_params($params, $profile, $language));
501
- }
502
- else {
503
- $document_id = $client->upload_document($params, $group);
504
 
505
- if ($document_id) {
506
- Lingotek_Group_String::create($group, $language, $document_id);
507
  }
508
  }
509
  }
510
 
511
- /*
512
  * checks if the document can be upload to Lingotek
513
  *
514
  * @since 0.1
515
  *
516
  * @param string $type either 'post' or 'term'
517
- * @param int $object_id post id or term id
518
  * @return bool
519
  */
520
- // FIXME should I check for disabled profile here?
521
- public function can_upload($type, $object_id) {
522
- $document = $this->get_group($type, $object_id);
523
- if ($document && $document->status === 'failed') {
524
  return false;
525
  }
526
- switch ($type) {
527
  case 'string':
528
- if (empty($document))
529
  return true;
530
-
531
- elseif ($document->md5 != md5(Lingotek_Group_String::get_content($object_id))) { // check if source strings have not been modified
 
532
  $document->source_edited();
533
  return true;
534
  }
@@ -536,123 +591,123 @@ class Lingotek_Model {
536
  return false;
537
 
538
  case 'post':
539
- $language = PLL()->model->post->get_language($object_id);
540
- $allow_status = $document && 'edited' == $document->status ? true : ($document && 'cancelled' === $document->status ? true: false);
541
- return !empty($language) && (empty($document) ||
542
- (isset($document) && $allow_status && $document->source == $object_id));
543
  case 'term':
544
  // first check that a language is associated to the object
545
- $language = PLL()->model->term->get_language($object_id);
546
 
547
  // FIXME how to get profile to check if disabled?
548
 
549
- return !empty($language) && (empty($document) ||
550
- (empty($document->translations) && empty($document->source)) || // specific for terms as document is never empty
551
- (isset($document) && 'edited' == $document->status && $document->source == $object_id));
552
- }
 
553
  }
554
 
555
- /*
556
  * deletes a post
557
  *
558
  * @since 0.1
559
  *
560
  * @param int $object_id post id
561
  */
562
- public function delete_post($object_id) {
563
- if ($document = $this->get_group('post', $object_id)) {
564
  $client = new Lingotek_API();
565
 
566
- if ($document->source == $object_id) {
567
- $client->cancel_document($document->document_id, $object_id);
568
- }
569
- else {
570
- PLL()->model->post->delete_translation($object_id);
571
- $lang = PLL()->model->post->get_language($object_id);
572
- $client->cancel_translation($document->document_id, $lang->lingotek_locale, $object_id);
573
  }
574
  }
575
  }
576
 
577
- public function cancel_post($object_id) {
578
- if ($document = $this->get_group('post', $object_id)) {
579
  $client = new Lingotek_API();
580
 
581
- if($document->source == $object_id) {
582
- $client->cancel_document($document->document_id, $object_id);
583
- }
584
- else {
585
- $lang = PLL()->model->post->get_language($object_id);
586
  $locale = $lang->locale;
587
- if(isset($document->desc_array['lingotek']['translations'][$locale])){
588
- $document->desc_array['lingotek']['translations'][$locale] = 'cancelled';
589
  }
590
  $document->save();
591
- $client->cancel_translation($document->document_id, $lang->lingotek_locale, $object_id);
592
  }
593
  }
594
  }
595
 
596
- /*
597
  * deletes a term
598
  *
599
  * @since 0.2
600
  *
601
  * @param int $object_id term id
602
  */
603
- public function delete_term($object_id) {
604
- if ($document = $this->get_group('term', $object_id)) {
605
  $client = new Lingotek_API();
606
- if ($document->source == $object_id) {
607
- $client->cancel_document($document->document_id, $object_id);
608
- }
609
- else {
610
- $lang = PLL()->model->term->get_language($object_id);
611
- PLL()->model->term->delete_language($object_id);
612
- PLL()->model->term->delete_translation($object_id);
613
- $client->cancel_translation($document->document_id, $lang->lingotek_locale, $object_id);
614
  }
615
  }
616
  }
617
 
618
- public function cancel_term($object_id){
619
- if ($document = $this->get_group('term', $object_id)){
620
  $client = new Lingotek_API();
621
- if($document->source == $object_id){
622
- $client->cancel_document($document->document_id, $object_id);
623
  } else {
624
- $lang = PLL()->model->term->get_language($object_id);
625
- PLL()->model->term->cancel_translation($object_id);
626
- PLL()->model->term->delete_translation($object_id);
627
- $client->cancel_translation($document->document_id, $lang->lingotek_locale, $object_id);
628
  }
629
  }
630
  }
631
 
632
- /*
633
  * counts the number of targets per language
634
  *
635
  * @since 0.2
636
  *
637
- * @param array $groups array of serialized 'post_translations' or 'term_translations' description
638
  * @return array number of targets per language
639
  */
640
- protected function get_target_count($groups) {
641
- $targets = array_fill_keys($this->pllm->get_languages_list(array('fields' => 'slug')), 0);
642
-
643
- foreach ($groups as $group) {
644
- $group = unserialize($group);
645
- if (isset($group['lingotek']['translations'])) {
646
- foreach ($group['lingotek']['translations'] as $locale => $status) {
647
- if ('current' == $status && $language = $this->pllm->get_language($locale))
648
- $targets[$language->slug]++;
 
 
649
  }
650
  }
651
  }
652
  return $targets;
653
  }
654
 
655
- /*
656
  * counts the number of sources and targets per language for a certain post type
657
  *
658
  * @since 0.2
@@ -660,101 +715,119 @@ class Lingotek_Model {
660
  * @param string $post_type
661
  * @return array
662
  */
663
- public function count_posts($post_type) {
664
  global $wpdb;
665
 
666
  static $r = array();
667
- if (!empty($r[$post_type]))
668
- return $r[$post_type];
 
669
 
670
- if (!post_type_exists($post_type))
671
  return;
 
672
 
673
  // gets all translations groups for the post type
674
- $groups = $wpdb->get_col($wpdb->prepare("
 
 
675
  SELECT DISTINCT tt.description FROM $wpdb->term_taxonomy AS tt
676
  INNER JOIN $wpdb->term_relationships AS tr ON tt.term_taxonomy_id = tr.term_taxonomy_id
677
  INNER JOIN $wpdb->posts AS p ON p.ID = tr.object_id
678
  WHERE tt.taxonomy = %s
679
  AND p.post_type = %s
680
  AND p.post_status NOT IN ('trash', 'auto-draft')",
681
- 'post_translations', $post_type
682
- ));
683
-
684
- $targets = $this->get_target_count($groups);
685
 
 
686
 
687
  $group_ids = array();
688
- $disabled = array();
689
 
690
- foreach ($this->pllm->get_languages_list() as $language) {
691
  // counts all the posts in one language
692
- $n = $wpdb->get_var($wpdb->prepare("
 
 
693
  SELECT COUNT(*) FROM $wpdb->term_relationships AS tr
694
  INNER JOIN $wpdb->posts AS p ON p.ID = tr.object_id
695
  WHERE tr.term_taxonomy_id = %d
696
  AND p.post_type = %s
697
  AND p.post_status NOT IN ('trash', 'auto-draft')",
698
- $language->term_taxonomy_id, $post_type
699
- ));
700
-
701
- $objects = $wpdb->get_col($wpdb->prepare("
 
 
 
 
702
  SELECT object_id FROM $wpdb->term_relationships AS tr
703
  INNER JOIN $wpdb->posts AS p ON p.ID = tr.object_id
704
  WHERE tr.term_taxonomy_id = %d
705
  AND p.post_type = %s
706
  AND p.post_status NOT IN ('trash', 'auto-draft')",
707
- $language->term_taxonomy_id, $post_type
708
- ));
709
-
710
- foreach ($groups as $group) {
711
- $group = unserialize($group);
712
- if (array_key_exists($language->slug, $group)) {
713
- $group_ids[] = $group[$language->slug];
 
 
714
  }
715
  }
716
 
717
  $count = 0;
718
- foreach ($objects as $object) {
719
  $id = $object;
720
- if (!in_array($id, $group_ids)) {
721
- $profile = self::get_profile($post_type, $language, $id);
722
- if ($profile['profile'] == 'disabled' && in_array($id, $objects)) {
723
- $count += 1;
724
  }
725
  }
726
  }
727
- $disabled[$language->slug] = $count;
728
 
729
  // if a post is not a target, then it is source
730
- $sources[$language->slug] = $n - $targets[$language->slug];
731
  // $sources[$language->slug] -= $disabled[$language->slug];
732
- }
733
 
734
  // untranslated posts have no associated translation group in DB
735
  // so let's count them indirectly
736
 
737
  // counts the number of translated posts
738
- $n_translated = $wpdb->get_var($wpdb->prepare("
 
 
739
  SELECT COUNT(*) FROM $wpdb->term_relationships AS tr
740
  INNER JOIN $wpdb->posts AS p ON p.ID = tr.object_id
741
  INNER JOIN $wpdb->term_taxonomy AS tt ON tt.term_taxonomy_id = tr.term_taxonomy_id
742
  WHERE tt.taxonomy = %s
743
  AND p.post_type = %s
744
  AND p.post_status NOT IN ('trash', 'auto-draft')",
745
- 'post_translations', $post_type
746
- ));
 
 
747
 
748
  // untranslated = total - translated
749
  // total of posts translations groups = untranslated + number of translation groups stored in DB
750
- $count_posts = (array) wp_count_posts($post_type);
751
- unset($count_posts['trash'], $count_posts['auto-draft']); // don't count trash and auto-draft
752
- $total = array_sum($count_posts) - $n_translated + count($groups);
 
753
 
754
- return $r[$post_type] = compact('sources', 'targets', 'total');
755
  }
756
 
757
- /*
758
  * counts the number of sources and targets per language for a certain taxonomy
759
  *
760
  * @since 0.2
@@ -762,192 +835,206 @@ class Lingotek_Model {
762
  * @param string $taxonomy
763
  * @return array
764
  */
765
- public function count_terms($taxonomy) {
766
  global $wpdb;
767
 
768
  static $r = array();
769
- if (!empty($r[$taxonomy]))
770
- return $r[$taxonomy];
 
771
 
772
- if (!taxonomy_exists($taxonomy))
773
  return;
 
774
 
775
  // gets all translations groups for the taxonomy
776
- $groups = $wpdb->get_col($wpdb->prepare("
 
 
777
  SELECT DISTINCT tt1.description FROM $wpdb->term_taxonomy AS tt1
778
  INNER JOIN $wpdb->term_relationships AS tr ON tt1.term_taxonomy_id = tr.term_taxonomy_id
779
  INNER JOIN $wpdb->term_taxonomy AS tt2 ON tt2.term_id = tr.object_id
780
  WHERE tt1.taxonomy = %s
781
  AND tt2.taxonomy = %s",
782
- 'term_translations', $taxonomy
783
- ));
 
 
784
 
785
- $targets = $this->get_target_count($groups);
786
 
787
  $group_ids = array();
788
- $disabled = array();
789
 
790
- foreach ($this->pllm->get_languages_list() as $language) {
791
  // counts all the terms in one language
792
- $n = $wpdb->get_var($wpdb->prepare("
 
 
793
  SELECT COUNT(*) FROM $wpdb->term_relationships AS tr
794
  INNER JOIN $wpdb->term_taxonomy AS tt ON tt.term_id = tr.object_id
795
  WHERE tr.term_taxonomy_id = %d
796
  AND tt.taxonomy = %s",
797
- $language->tl_term_taxonomy_id, $taxonomy
798
- ));
799
-
800
- $objects = $wpdb->get_col($wpdb->prepare("
 
 
 
 
801
  SELECT object_id FROM $wpdb->term_relationships AS tr
802
  INNER JOIN $wpdb->term_taxonomy AS tt ON tt.term_id = tr.object_id
803
  WHERE tr.term_taxonomy_id = %d
804
  AND tt.taxonomy = %s",
805
- $language->tl_term_taxonomy_id, $taxonomy
806
- ));
 
 
807
 
808
  $count = 0;
809
- foreach ($groups as $group) {
810
- $group = unserialize($group);
811
- if (array_key_exists($language->slug, $group)) {
812
- $group_ids[] = $group[$language->slug];
813
- $profile = self::get_profile($taxonomy, $language, $group[$language->slug]);
814
- if ($profile['profile'] == 'disabled' && !isset($group['lingotek'])) {
815
- $count += 1;
816
  }
817
  }
818
  }
819
 
820
-
821
- $disabled[$language->slug] = $count;
822
 
823
  // if a term is not a target, then it is a source
824
- $sources[$language->slug] = $n - $targets[$language->slug];
825
  // $sources[$language->slug] -= $disabled[$language->slug];
826
- }
827
 
828
- $total = count($groups);
829
 
830
  // default categories are created by Polylang in all languages
831
  // don't count them as sources if they are not associated to the TMS
832
- if ('category' === $taxonomy) {
833
- $term_id = get_option('default_category');
834
- $group = $this->get_group('term', $term_id);
835
- foreach($this->pllm->get_languages_list() as $language) {
836
- if (empty($group->source) || ($group->get_source_language()->slug != $language->slug && empty($group->translations[$language->locale]))) {
837
- if ($language->slug != $this->pllm->options['default_lang']) {
838
- $sources[$language->slug]--;
839
  }
840
  }
841
  }
842
  // Remove category targets from being counted until they are downloaded. Fixed target categories being counted as source languages.
843
- foreach ($groups as $group) {
844
- $group = unserialize($group);
845
- if (isset($group['lingotek']['translations'])) {
846
- foreach ($group['lingotek']['translations'] as $locale => $status) {
847
- if (('pending' == $status || 'ready' == $status) && $language = $this->pllm->get_language($locale)) {
848
- if ($sources[$language->slug] > 0) {
849
- $sources[$language->slug]--;
 
850
  }
851
  }
852
  }
853
  }
854
  }
855
- if (count($sources) == 1 && $total != $sources[$this->pllm->options['default_lang']]) {
856
- $total = $sources[$this->pllm->options['default_lang']];
857
  }
858
- }
859
- return $r[$taxonomy] = compact('sources', 'targets', 'total');
 
860
  }
861
 
862
- private function build_params($external_url, $title, $type, $content, $language, $profile, $wp_id, &$wp_target_locales = array()) {
863
-
864
- $translation_workflow_id = self::get_profile_option('workflow_id', $type, $language, false, $wp_id);
865
- if ($translation_workflow_id === 'project-default' || $translation_workflow_id === false) {
866
  $translation_workflow_id = null;
867
  }
868
 
869
  $params = array(
870
- 'title' => $title,
871
- 'content' => $content,
872
- 'locale_code' => $language->lingotek_locale,
873
- 'project_id' => self::get_profile_option('project_id', $type, $language, false, $wp_id),
874
- 'external_url' => $external_url
875
  );
876
 
877
- $lingotek_metadata_keys = array('author_email',
878
- 'author_name',
879
- 'division',
880
- 'unit',
881
- 'campaign_id',
882
- 'channel',
883
- 'contact_email',
884
- 'contact_name',
885
- 'description',
886
- 'domain',
887
- 'style_id',
888
- 'purchase_order',
889
- 'reference_url',
890
- 'region',
891
- 'require_review',
892
- );
893
-
894
- foreach ($lingotek_metadata_keys as $key) {
895
- if (isset($profile[$key]) )
896
- $params[$key] = $profile[$key];
897
- }
898
-
899
- if ($translation_workflow_id !== null) {
 
 
900
  $params['translation_workflow_id'] = $translation_workflow_id;
901
  }
902
 
903
  // Get target locales to send up from profile
904
  $target_locales = array();
905
- if (!empty($profile['target_locales'])) {
906
- if (isset($profile['target_locales'][$language->slug])) {
907
- unset($profile['target_locales'][$language->slug]);
908
  }
909
- if (isset($profile['custom']['workflow_id'][$language->slug])) {
910
- unset($profile['custom']['workflow_id'][$language->slug]);
911
  }
912
- $target_locales['translation_locale_code'] = array_values($profile['target_locales']);
913
- $wp_target_locales = array_keys($profile['target_locales']);
914
 
915
  // Add workflows
916
- if (!empty($profile['custom']['workflow_id'])) {
917
- $temp_workflow_ids = [];
918
- $workflow_id = null;
919
- foreach ($wp_target_locales as $language_slug) {
920
- if (isset($profile['custom']['workflow_id'][$language_slug])) {
921
- $profile_override = $profile['custom']['workflow_id'][$language_slug];
922
- $workflow_id = $profile_override === 'project-default' ? $translation_workflow_id : $profile_override;
923
- }
924
- else {
925
  $workflow_id = $translation_workflow_id;
926
  }
927
- if ($workflow_id) {
928
  $temp_workflow_ids[] = $workflow_id;
929
  }
930
  }
931
  $params['translation_workflow_id'] = $temp_workflow_ids;
932
  }
933
- }
934
- else {
935
  // No targets being sent up to TMS, unset the workflow
936
- unset($params['translation_workflow_id']);
937
- }
938
 
939
- $params = array_merge($params, $target_locales);
940
 
941
  return $params;
942
  }
943
 
944
- private function get_filter_ids($type, $language, $wp_id) {
945
  $filter_ids = array();
946
- if (self::get_profile_option('primary_filter_id', $type, $language, false, $wp_id)) {
947
- $filter_ids['fprm_id'] = self::get_profile_option('primary_filter_id',$type, $language, false, $wp_id);
948
  }
949
- if (self::get_profile_option('secondary_filter_id', $type, $language, false, $wp_id)) {
950
- $filter_ids['fprm_subfilter_id'] = self::get_profile_option('secondary_filter_id',$type, $language, false, $wp_id);
951
  }
952
  return $filter_ids;
953
  }
1
  <?php
2
 
3
+ /**
4
  * Manages interactions with database
5
  * Factory for Lingotek_Group objects
6
  *
7
  * @since 0.1
8
  */
9
  class Lingotek_Model {
 
 
 
10
 
11
+ /**
12
+ * Polylang model.
13
+ *
14
+ * @var obj
15
+ */
16
+ public $pllm;
17
+
18
+ public static $copying_post;
19
+ public static $copying_term;
20
+
21
+ /**
22
  * constructor
23
  *
24
  * @since 0.1
26
  public function __construct() {
27
  $this->pllm = $GLOBALS['polylang']->model;
28
 
29
+ register_taxonomy(
30
+ 'lingotek_profile',
31
+ null,
32
+ array(
33
+ 'label' => false,
34
+ 'public' => false,
35
+ 'query_var' => false,
36
+ 'rewrite' => false,
37
+ )
38
+ );
39
+ register_taxonomy(
40
+ 'lingotek_hash',
41
+ null,
42
+ array(
43
+ 'label' => false,
44
+ 'public' => false,
45
+ 'query_var' => false,
46
+ 'rewrite' => false,
47
+ )
48
+ );
49
  }
50
 
51
+ /**
52
  * get the strings groups as well as their count
53
  *
54
  * @since 0.2
57
  */
58
  public static function get_strings() {
59
  static $strings = array();
60
+ if ( empty( $strings ) ) {
61
+ // Enables sanitization filter.
62
+ PLL_Admin_Strings::init();
63
 
64
+ foreach ( PLL_Admin_Strings::get_strings() as $string ) {
65
+ $strings[ $string['context'] ]['context'] = $string['context'];
66
+ $strings[ $string['context'] ]['count'] = empty( $strings[ $string['context'] ]['count'] ) ? 1 : $strings[ $string['context'] ]['count'] + 1;
67
  }
68
+ $strings = array_values( $strings );
69
  }
70
  return $strings;
71
  }
72
 
73
+ /**
74
  * create a translation group object from a translation term
75
  *
76
  * @since 0.2
78
  * @param object $term
79
  * @return object
80
  */
81
+ protected function convert_term( $term ) {
82
+ switch ( $term->taxonomy ) {
83
  case 'term_translations':
84
+ return new Lingotek_Group_Term( $term, $this->pllm );
85
 
86
  case 'post_translations':
87
+ $class = $term->name === $term->slug ? 'Lingotek_Group_Post' : 'Lingotek_Group_String';
88
+ return new $class( $term, $this->pllm );
89
  }
90
  }
91
 
92
+ /**
93
  * get the translation term of an object
94
  *
95
  * @since 0.2
96
  *
97
+ * @param string $type Either 'post' or 'term' or 'string'.
98
+ * @param int|string $id Post id or term id or strings translations group name.
99
+ * @return object Translation term.
100
  */
101
+ public function get_group( $type, $id ) {
102
+ switch ( $type ) {
103
  case 'post':
104
+ return ( $post = PLL()->model->post->get_object_term( (int) $id, $type . '_translations' ) ) && ! empty( $post ) ? $this->convert_term( $post ) : false;
105
  case 'term':
106
+ return ( $term = PLL()->model->term->get_object_term( (int) $id, $type . '_translations' ) ) && ! empty( $term ) ? $this->convert_term( $term ) : false;
107
  case 'string':
108
+ if ( is_numeric( $id ) ) {
109
  $strings = self::get_strings();
110
+ $id = $strings[ $id ]['context'];
111
  }
112
+ return ( $term = get_term_by( 'name', $id, 'post_translations' ) ) && ! empty( $term ) ? $this->convert_term( $term ) : false;
113
  default:
114
  return false;
115
  }
116
  }
117
 
118
+ /**
119
+ * get document id of an object, false if it wasn't uploaded yet.
120
+ *
121
+ * @since 1.4.11
122
+ *
123
+ * @param string $type either 'post' or 'term' or 'string'
124
+ * @param int|string $id post id or term id or strings translations group name
125
+ * @return string|bool document id or false
126
+ */
127
+ public function get_document_id( $type, $id ) {
128
+ $document_term = $this->get_group( $type, $id );
129
+ $document_id = $document_term != false ? $document_term->document_id : false;
130
+ return $document_id;
131
+ }
132
+
133
+ /**
134
  * get the translation term of an object by its Lingotek document id
135
  *
136
  * @since 0.2
138
  * @param string|object $document_id
139
  * @return object translation term
140
  */
141
+ public function get_group_by_id( $document_id ) {
142
  // we already passed a translation group object
143
+ if ( is_object( $document_id ) ) {
144
  return $document_id;
145
+ }
146
 
147
+ $terms = get_terms( array( 'post_translations', 'term_translations' ), array( 'slug' => $document_id ) );
148
+ return is_wp_error( $terms ) || empty( $terms ) ? false : $this->convert_term( reset( $terms ) );
149
  }
150
 
151
+ /**
152
  * get a translation profile
153
  *
154
  * @since 0.2
157
  * @param object $language
158
  * @return array
159
  */
160
+ public static function get_profile( $type, $language, $post_id = null ) {
161
  global $profileInformation, $ltk_profiles, $ltk_contentTypes;
162
 
163
+ if ( is_null( $ltk_profiles ) ) {
164
+ $ltk_profiles = get_option( 'lingotek_profiles' );
165
  }
166
+ if ( $post_id && $profileInformation && isset( $profileInformation[ $type ] ) && isset( $profileInformation[ $type ][ $language->locale ] ) && isset( $profileInformation[ $type ][ $language->locale ][ $post_id ] ) ) {
167
+ return $ltk_profiles[ $profileInformation[ $type ][ $language->locale ][ $post_id ] ];
168
  }
169
 
170
+ if ( is_null( $ltk_contentTypes ) ) {
171
+ $ltk_contentTypes = get_option( 'lingotek_content_type' );
172
  }
173
 
174
  // If a profile is set for a specific post/page get that first
175
+ if ( $post_id ) {
176
+ $profile_override = get_term_by( 'name', 'lingotek_profile_' . $post_id, 'lingotek_profile' );
177
+ if ( $profile_override ) {
178
+ if ( ! isset( $profileInformation ) ) {
179
+ $profileInformation = array(); }
180
+ if ( ! isset( $profileInformation[ $type ] ) ) {
181
+ $profileInformation[ $type ] = array(); }
182
+ if ( ! isset( $profileInformation[ $type ][ $language->locale ] ) ) {
183
+ $profileInformation[ $type ][ $language->locale ] = array(); }
184
+ $profileInformation[ $type ][ $language->locale ][ $post_id ] = $profile_override->description;
185
+ return $ltk_profiles[ $profile_override->description ];
186
  }
187
  }
188
 
189
+ // Default profile is manual for posts and pages, custom types are set to disabled by default.
190
  $default = 'post' === $type || 'page' === $type ? 'manual' : 'disabled';
191
 
192
+ $profile = is_object( $language ) && isset( $content_types[ $type ]['sources'][ $language->slug ] ) ?
193
+ $ltk_contentTypes[ $type ]['sources'][ $language->slug ] :
194
+ ( isset( $ltk_contentTypes[ $type ]['profile'] ) ? $ltk_contentTypes[ $type ]['profile'] : $default );
195
+
196
+ if ( $post_id ) {
197
+ if ( ! isset( $profileInformation ) ) {
198
+ $profileInformation = array(); }
199
+ if ( ! isset( $profileInformation[ $type ] ) ) {
200
+ $profileInformation[ $type ] = array(); }
201
+ if ( ! isset( $profileInformation[ $type ][ $language->locale ] ) ) {
202
+ $profileInformation[ $type ][ $language->locale ] = array(); }
203
+ $profileInformation[ $type ][ $language->locale ][ $post_id ] = $profile;
204
  }
205
 
206
+ return $ltk_profiles[ $profile ];
207
  }
208
 
209
+ public static function get_prefs() {
210
  $default = array(
211
+ 'download_post_status' => Lingotek_Group_Post::SAME_AS_SOURCE,
212
  'auto_upload_post_statuses' => array(
213
+ // ignore auto-upload
214
+ 'draft' => 0,
215
+ // auto-upload
216
+ 'pending' => 1,
217
  'publish' => 1,
218
+ 'future' => 1,
219
  'private' => 0,
220
  ),
221
+ 'trash_linked_content' => array(),
222
+ 'auto_update_status' => '10',
223
+ 'enable_lingotek_logs' => 0,
 
 
224
  );
225
+ // Ensure defaults are set for missing keys.
226
+ $prefs = array_merge( $default, get_option( 'lingotek_prefs', $default ) );
227
  return $prefs;
228
  }
229
 
230
+ /**
231
  * get a profile option
232
  *
233
  * @since 0.2
234
  *
235
+ * @param string $item 'project_id' | 'workflow_id' | 'upload' | 'download'.
236
+ * @param string $type Post type or taxonomy.
237
  * @param object $source_language
238
+ * @param object $target_language Optional, needed to get custom target informations 'workflow_id' | 'download'.
239
+ * @return string | bool either the option or false if the translation is disabled.
240
  */
241
+ public static function get_profile_option( $item, $type, $source_language, $target_language = false, $post_id = null ) {
242
+ $profile = self::get_profile( $type, $source_language, $post_id );
243
+ if ( 'disabled' === $profile['profile'] || is_object( $target_language ) && isset( $profile['targets'][ $target_language->slug ] ) && 'disabled' === $profile['targets'][ $target_language->slug ] ) {
244
  return false;
245
+ }
246
+
247
+ if ( ! empty( $target_language ) && isset( $profile['targets'][ $target_language->slug ] ) && ! empty( $profile['custom'][ $item ][ $target_language->slug ] ) ) {
248
+ return $profile['custom'][ $item ][ $target_language->slug ];
249
+ }
250
 
251
+ if ( ! empty( $profile[ $item ] ) ) {
252
+ return $profile[ $item ];
253
+ }
254
 
255
+ $defaults = get_option( 'lingotek_defaults', array() );
256
+ return isset( $defaults[ $item ] ) ? $defaults[ $item ] : null;
 
 
 
257
  }
258
 
259
+ /**
260
  * find targets that are set to copy in a profile
261
  *
262
  * @since 1.1.1
264
  * @param array $profile (use get_profile to retrieve)
265
  * @return array of targets that should be copied. if none exist returns empty array
266
  */
267
+ public function targets_to_be_copied( $profile ) {
268
+ if ( isset( $profile['targets'] ) && in_array( 'copy', $profile['targets'] ) ) {
269
+ $targets_to_copy = array_keys( $profile['targets'], 'copy' );
270
  return $targets_to_copy;
271
+ } else {
 
272
  return array();
273
  }
274
  }
275
 
276
+ /**
277
  * copy a post from the source language to a target language
278
  *
279
  * @since 1.1.1
282
  * @param string $target polylang language slug (ex: en, de, fr, etc)
283
  * @return $new_post_id if copy of post is successful, false otherwise
284
  */
285
+ public function copy_post( $post, $target ) {
286
+ self::$copying_post = true;
287
+ $document = $this->get_group( 'post', $post->ID );
288
+ $prefs = self::get_prefs();
289
+ $cp_lang = $this->pllm->get_language( $target );
290
+ $cp_post = (array) $post;
291
+ $cp_post['post_status'] = ( $prefs['download_post_status'] === 'SAME_AS_SOURCE' ) ? $post->post_status : $prefs['download_post_status'];
292
+ $slug = $cp_post['post_name'];
293
+ unset( $cp_post['ID'] );
294
+ unset( $cp_post['post_name'] );
295
+ if ( ! isset( $document->desc_array[ $target ] ) ) {
296
+ $new_post_id = wp_insert_post( $cp_post, true );
297
+ if ( ! is_wp_error( $new_post_id ) ) {
298
+ PLL()->model->post->set_language( $new_post_id, $cp_lang );
299
+ wp_set_object_terms( $new_post_id, $document->term_id, 'post_translations' );
300
+ $GLOBALS['polylang']->sync->taxonomies->copy( $document->source, $new_post_id, $cp_lang->slug );
301
+ $GLOBALS['polylang']->sync->post_metas->copy( $document->source, $new_post_id, $cp_lang->slug );
302
+ Lingotek_Group_Post::copy_or_ignore_metas( $post->ID, $new_post_id );
303
+ $document->desc_array[ $target ] = $new_post_id;
304
  $document->save();
305
+ if ( class_exists( 'PLL_Share_Post_Slug', true ) ) {
306
+ wp_update_post(
307
+ array(
308
+ 'ID' => $new_post_id,
309
+ 'post_name' => $slug,
310
+ )
311
+ );
312
  }
313
  }
314
  }
315
  self::$copying_post = false;
316
  }
317
 
318
+ public function copy_term( $term, $target, $taxonomy ) {
319
  self::$copying_term = true;
320
+ $document = $this->get_group( 'term', $term->term_id );
321
+ $cp_lang = $this->pllm->get_language( $target );
322
+ $cp_term = (array) $term;
 
323
 
324
+ if ( class_exists( 'PLL_Share_Term_Slug', true ) ) {
325
  remove_action( 'create_term', array( PLL()->filters_term, 'save_term' ), 999, 3 );
326
  remove_action( 'edit_term', array( PLL()->filters_term, 'save_term' ), 999, 3 );
327
+ remove_action( 'pre_post_update', array( PLL()->filters_term, 'pre_post_update' ) );
328
+ remove_filter( 'pre_term_name', array( PLL()->filters_term, 'pre_term_name' ) );
329
+ remove_filter( 'pre_term_slug', array( PLL()->filters_term, 'pre_term_slug' ), 10, 2 );
330
  add_action( 'pre_post_update', array( PLL()->share_term_slug, 'pre_post_update' ) );
331
  add_filter( 'pre_term_name', array( PLL()->share_term_slug, 'pre_term_name' ) );
332
  add_filter( 'pre_term_slug', array( PLL()->share_term_slug, 'pre_term_slug' ), 10, 2 );
333
  add_action( 'create_term', array( PLL()->share_term_slug, 'save_term' ), 1, 3 );
334
  add_action( 'edit_term', array( PLL()->share_term_slug, 'save_term' ), 1, 3 );
335
  $_POST['term_lang_choice'] = $cp_lang->slug;
336
+ } else {
337
+ if ( isset( $cp_term['slug'] ) && term_exists( $cp_term['slug'] ) ) {
 
338
  $cp_term['slug'] .= '-' . $cp_lang->slug;
339
  }
340
  }
341
 
342
+ $new_term = wp_insert_term( $cp_term['name'], $taxonomy, $cp_term );
343
 
344
+ if ( ! is_wp_error( $new_term ) ) {
345
+ PLL()->model->term->set_language( $new_term['term_id'], $cp_lang );
346
+ wp_set_object_terms( $new_term['term_id'], $document->term_id, 'term_translations' );
347
+ $document->desc_array[ $target ] = $new_term['term_id'];
348
  $document->save();
349
  }
350
  self::$copying_term = false;
351
  }
352
 
353
+ private function format_patch_params( $params, $profile, $source_lang ) {
354
+ $params['translation_locale_code'] = array();
355
+ $params['translation_workflow_id'] = array();
356
 
357
+ foreach ( $this->pllm->get_languages_list() as $lang ) {
358
+ if ( $lang->lingotek_locale == $source_lang->lingotek_locale
359
+ || ( isset( $profile['targets'][ $lang->slug ] ) && 'disabled' === $profile['targets'][ $lang->slug ] ) ) {
360
  continue;
361
  }
362
  $params['translation_locale_code'][] = $lang->lingotek_locale;
363
+ if ( isset( $profile['custom']['workflow_id'][ $lang->slug ], $profile['targets'][ $lang->lingotek_locale ] ) ) {
364
+ $params['translation_workflow_id'][] = $profile['custom']['workflow_id'][ $lang->slug ];
365
+ } elseif ( ! isset( $profile['targets'][ $lang->lingotek_locale ] ) && isset( $profile['workflow_id'] ) && $profile['workflow_id'] !== 'project-default' ) {
366
+ // Target is not using a custom workflow so we use the default workflow.
367
+ $params['translation_workflow_id'][] = $profile['workflow_id'];
368
  }
369
  }
370
+ if ( empty( $params['translation_workflow_id'] ) ) {
371
+ unset( $params['translation_workflow_id'] );
372
  }
373
  return $params;
374
  }
379
  * @since 0.1
380
  *
381
  * @param int $post_id
382
+ * @return boolean|string false if post failed to upload
383
  */
384
+ public function upload_post( $post_id ) {
385
+ $post = get_post( $post_id );
386
+ $language = PLL()->model->post->get_language( $post_id );
387
+ $profile = self::get_profile( $post->post_type, $language, $post_id );
388
+ if ( 'disabled' === $profile['profile'] || empty( $post ) || empty( $language ) ) {
389
  return;
390
  }
391
+ // Returns type string or boolean
392
+ $document_id = self::get_document_id( 'post', $post_id );
393
+ // Slug can't be empty or duplicated, so we prefix `disassociated` to show the document id is no longer associated with this post
394
+ if ( is_string( $document_id ) && strpos( $document_id, 'disassociated_' ) === 0 ) {
395
+ $document_id = false;
396
+ }
397
  $content = null;
398
  // If we already uploaded this doc, check if it changed and prevent the upload if it didn't.
399
+ if ( $document_id ) {
400
+ $content = Lingotek_Group_Post::get_content( $post );
401
+ $hash_terms = wp_get_object_terms( $post->ID, 'lingotek_hash' );
402
+ $hash_term = array_pop( $hash_terms );
403
+ $new_hash = md5( $content );
404
+ if ( ! empty( $hash_term ) ) {
405
  if ( $hash_term->description == $new_hash ) {
406
  return;
407
  }
408
  }
409
  }
410
+ $document = $this->get_group( 'post', $post_id );
411
  // Customized workflows have the option to do any sort of pre-processing before a document
412
  // is uploaded to lingotek.
413
+ if ( $document ) {
414
+ $document->pre_upload_to_lingotek( $post_id, $post->post_type, $language, 'post' );
415
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
416
 
417
+ $client = new Lingotek_API();
418
+ $external_url = get_page_link( $post_id );
419
+ if ( ! $content ) {
420
+ $content = Lingotek_Group_Post::get_content( $post );
421
+ }
422
+ $params = $this->build_params( $external_url, $post->post_title, $post->post_type, $content, $language, $profile, $post_id, $wp_target_locales );
423
+ $filter_ids = $this->get_filter_ids( $post->post_type, $language, $post_id );
424
+ $params = array_merge( $params, $filter_ids );
425
+ if ( $document && in_array( $document->status, array( 'edited', 'importing', 'current' ) ) && $document_id ) {
426
+ $response = $document->patch( $this->format_patch_params( $params, $profile, $language ) );
427
+ if ( $response ) {
428
+ // Only save the hash if the patch function is successful
429
+ // Re-establish hash relation if needed
430
+ if ( ! isset( $hash_term->term_id ) ) {
431
+ $hash_terms = wp_set_post_terms( $post->ID, 'lingotek_hash_' . $post->ID, 'lingotek_hash' );
432
+ $hash_term_id = array_pop( $hash_terms );
433
+ } else {
434
+ $hash_term_id = $hash_term->id;
435
+ }
436
+ wp_update_term( $hash_term_id, 'lingotek_hash', array( 'description' => $new_hash ) );
437
+ }
438
+ return $response;
439
+ } elseif ( ! Lingotek_Group::$creating_translation && ! self::$copying_post && ( ! $document || $document->status === 'cancelled' ) ) {
440
+ $document_id = $client->upload_document( $params, $post->ID );
441
+ if ( $document_id ) {
442
+ Lingotek_Group_Post::create( $post->ID, $language, $document_id );
443
  $document = $this->get_group_by_id( $document_id );
444
+ if ( isset( $wp_target_locales ) ) {
445
+ foreach ( $wp_target_locales as $locale ) {
446
+ $document->translations[ $locale ] = 'pending';
447
  }
448
  }
449
  $document->save();
450
  // If a translation profile has targets set to copy then copy them
451
+ $targets_to_copy = $this->targets_to_be_copied( $profile );
452
+ $upload = self::get_profile_option( 'upload', $post->post_type, $language, false, $post_id );
453
+ if ( ! empty( $targets_to_copy ) && $upload === 'automatic' ) {
454
+ foreach ( $targets_to_copy as $target ) {
455
+ $this->copy_post( $post, $target );
456
  }
457
  }
458
+ return $document_id;
459
  }
460
+ return false;
461
+ }//end if
462
  }
463
 
464
  /**
466
  *
467
  * @since 0.2
468
  *
469
+ * @param int $term_id
470
  * @param string $taxonomy
471
  */
472
+ public function upload_term( $term_id, $taxonomy ) {
473
+ $term = get_term( $term_id, $taxonomy );
474
+ $language = PLL()->model->term->get_language( $term_id );
475
+ if ( empty( $term ) || empty( $language ) ) {
476
  return;
477
+ }
478
 
479
+ $profile = self::get_profile( $taxonomy, $language );
480
+ if ( 'disabled' === $profile['profile'] ) {
481
  return;
482
+ }
483
 
484
  /**
485
  * Customized workflows have the option to do any sort of pre-processing before a document is uploaded to lingotek.
486
  */
487
+ $document = $this->get_group( 'term', $term_id );
488
+ if ( $document ) {
489
+ $document->pre_upload_to_lingotek( $term_id, $taxonomy, $language, 'term' );
490
  }
491
 
492
+ $client = new Lingotek_API();
493
+ $content = Lingotek_Group_Term::get_content( $term );
494
+ $params = $this->build_params( get_term_link( $term_id, $taxonomy ), $term->name, $taxonomy, $content, $language, $profile, $term_id, $wp_target_locales );
495
+ $filter_ids = $this->get_filter_ids( $taxonomy, $language, $term_id );
496
+ $params = array_merge( $params, $filter_ids );
 
 
 
 
497
 
498
+ if ( ( $document = $this->get_group( 'term', $term_id ) ) && 'edited' === $document->status ) {
499
+ $document->patch( $this->format_patch_params( $params, $profile, $language ), $term->name, $term );
500
+ } elseif ( ! Lingotek_Group::$creating_translation && ! self::$copying_term ) {
501
+ $document_id = $client->upload_document( $params, $term_id );
502
 
503
+ if ( $document_id ) {
504
+ Lingotek_Group_Term::create( $term_id, $taxonomy, $language, $document_id );
505
  $document = $this->get_group_by_id( $document_id );
506
+ foreach ( $wp_target_locales as $locale ) {
507
+ $document->translations[ $locale ] = 'pending';
508
  }
509
  $document->save();
510
+
511
  // If a translation profile has targets set to copy then copy them
512
+ $targets_to_copy = $this->targets_to_be_copied( $profile );
513
+ if ( ! empty( $targets_to_copy ) && 'automatic' === $profile['upload'] ) {
514
+ foreach ( $targets_to_copy as $target ) {
515
+ $this->copy_term( $term, $target, $taxonomy );
516
  }
517
  }
518
  }
519
+ }//end if
520
  }
521
 
522
+ /**
523
  * uploads a strings group to Lingotek TMS
524
  *
525
  * @since 0.2
526
  *
527
  * @param string $group
528
  */
529
+ public function upload_strings( $group ) {
530
+ $type = 'string';
531
+ $language = $this->pllm->get_language( $this->pllm->options['default_lang'] );
532
+ $profile = self::get_profile( $type, $language );
533
 
534
+ if ( 'disabled' === $profile['profile'] ) {
535
  return;
536
+ }
537
 
538
+ if ( is_numeric( $group ) ) {
539
  $strings = self::get_strings();
540
+ $group = $strings[ $group ]['context'];
541
  }
542
 
543
  // check that we have a valid string group
544
+ if ( ! in_array( $group, wp_list_pluck( self::get_strings(), 'context' ) ) ) {
545
  return;
546
+ }
547
 
548
+ $client = new Lingotek_API();
549
+ $content = Lingotek_Group_String::get_content( $group );
550
+ $params = $this->build_params( '', $group, $type, $content, $language, $profile, null );
551
+ $filter_ids = $this->get_filter_ids( $type, $language, null );
552
+ $params = array_merge( $params, $filter_ids );
553
 
554
+ if ( ( $document = $this->get_group( $type, $group ) ) && 'edited' === $document->status ) {
555
+ $document->patch( $this->format_patch_params( $params, $profile, $language ) );
556
+ } else {
557
+ $document_id = $client->upload_document( $params, $group );
 
558
 
559
+ if ( $document_id ) {
560
+ Lingotek_Group_String::create( $group, $language, $document_id );
561
  }
562
  }
563
  }
564
 
565
+ /**
566
  * checks if the document can be upload to Lingotek
567
  *
568
  * @since 0.1
569
  *
570
  * @param string $type either 'post' or 'term'
571
+ * @param int $object_id post id or term id
572
  * @return bool
573
  */
574
+ public function can_upload( $type, $object_id ) {
575
+ // FIXME should I check for disabled profile here?
576
+ $document = $this->get_group( $type, $object_id );
577
+ if ( $document && 'failed' === $document->status ) {
578
  return false;
579
  }
580
+ switch ( $type ) {
581
  case 'string':
582
+ if ( empty( $document ) ) {
583
  return true;
584
+ }
585
+ // Check if source strings have not been modified.
586
+ elseif ( $document->md5 !== md5( Lingotek_Group_String::get_content( $object_id ) ) ) {
587
  $document->source_edited();
588
  return true;
589
  }
591
  return false;
592
 
593
  case 'post':
594
+ $language = PLL()->model->post->get_language( $object_id );
595
+ $allow_status = $document && 'edited' === $document->status ? true : ( $document && 'cancelled' === $document->status ? true : false );
596
+ return ! empty( $language ) && ( empty( $document ) ||
597
+ ( isset( $document ) && $allow_status && $document->source == $object_id ) );
598
  case 'term':
599
  // first check that a language is associated to the object
600
+ $language = PLL()->model->term->get_language( $object_id );
601
 
602
  // FIXME how to get profile to check if disabled?
603
 
604
+ return ! empty( $language ) && ( empty( $document ) ||
605
+ // Specific for terms as document is never empty.
606
+ ( empty( $document->translations ) && empty( $document->source ) ) ||
607
+ ( isset( $document ) && 'edited' == $document->status && $document->source == $object_id ) );
608
+ }//end switch
609
  }
610
 
611
+ /**
612
  * deletes a post
613
  *
614
  * @since 0.1
615
  *
616
  * @param int $object_id post id
617
  */
618
+ public function delete_post( $object_id ) {
619
+ if ( $document = $this->get_group( 'post', $object_id ) ) {
620
  $client = new Lingotek_API();
621
 
622
+ if ( $document->source == $object_id ) {
623
+ $client->cancel_document( $document->document_id, $object_id );
624
+ } else {
625
+ PLL()->model->post->delete_translation( $object_id );
626
+ $lang = PLL()->model->post->get_language( $object_id );
627
+ $client->cancel_translation( $document->document_id, $lang->lingotek_locale, $object_id );
 
628
  }
629
  }
630
  }
631
 
632
+ public function cancel_post( $object_id ) {
633
+ if ( $document = $this->get_group( 'post', $object_id ) ) {
634
  $client = new Lingotek_API();
635
 
636
+ if ( $document->source == $object_id ) {
637
+ $client->cancel_document( $document->document_id, $object_id );
638
+ } else {
639
+ $lang = PLL()->model->post->get_language( $object_id );
 
640
  $locale = $lang->locale;
641
+ if ( isset( $document->desc_array['lingotek']['translations'][ $locale ] ) ) {
642
+ $document->desc_array['lingotek']['translations'][ $locale ] = 'cancelled';
643
  }
644
  $document->save();
645
+ $client->cancel_translation( $document->document_id, $lang->lingotek_locale, $object_id );
646
  }
647
  }
648
  }
649
 
650
+ /**
651
  * deletes a term
652
  *
653
  * @since 0.2
654
  *
655
  * @param int $object_id term id
656
  */
657
+ public function delete_term( $object_id ) {
658
+ if ( $document = $this->get_group( 'term', $object_id ) ) {
659
  $client = new Lingotek_API();
660
+ if ( $document->source == $object_id ) {
661
+ $client->cancel_document( $document->document_id, $object_id );
662
+ } else {
663
+ $lang = PLL()->model->term->get_language( $object_id );
664
+ PLL()->model->term->delete_language( $object_id );
665
+ PLL()->model->term->delete_translation( $object_id );
666
+ $client->cancel_translation( $document->document_id, $lang->lingotek_locale, $object_id );
 
667
  }
668
  }
669
  }
670
 
671
+ public function cancel_term( $object_id ) {
672
+ if ( $document = $this->get_group( 'term', $object_id ) ) {
673
  $client = new Lingotek_API();
674
+ if ( $document->source == $object_id ) {
675
+ $client->cancel_document( $document->document_id, $object_id );
676
  } else {
677
+ $lang = PLL()->model->term->get_language( $object_id );
678
+ PLL()->model->term->cancel_translation( $object_id );
679
+ PLL()->model->term->delete_translation( $object_id );
680
+ $client->cancel_translation( $document->document_id, $lang->lingotek_locale, $object_id );
681
  }
682
  }
683
  }
684
 
685
+ /**
686
  * counts the number of targets per language
687
  *
688
  * @since 0.2
689
  *
690
+ * @param array $groups Array of serialized 'post_translations' or 'term_translations' description.
691
  * @return array number of targets per language
692
  */
693
+ protected function get_target_count( $groups ) {
694
+ $targets = array_fill_keys( $this->pllm->get_languages_list( array( 'fields' => 'slug' ) ), 0 );
695
+
696
+ foreach ( $groups as $group ) {
697
+ $group = unserialize( $group );
698
+ if ( isset( $group['lingotek']['translations'] ) ) {
699
+ foreach ( $group['lingotek']['translations'] as $locale => $status ) {
700
+ $language = $this->pllm->get_language( $locale );
701
+ if ( 'current' === $status && $language ) {
702
+ $targets[ $language->slug ]++;
703
+ }
704
  }
705
  }
706
  }
707
  return $targets;
708
  }
709
 
710
+ /**
711
  * counts the number of sources and targets per language for a certain post type
712
  *
713
  * @since 0.2
715
  * @param string $post_type
716
  * @return array
717
  */
718
+ public function count_posts( $post_type ) {
719
  global $wpdb;
720
 
721
  static $r = array();
722
+ if ( ! empty( $r[ $post_type ] ) ) {
723
+ return $r[ $post_type ];
724
+ }
725
 
726
+ if ( ! post_type_exists( $post_type ) ) {
727
  return;
728
+ }
729
 
730
  // gets all translations groups for the post type
731
+ $groups = $wpdb->get_col(
732
+ $wpdb->prepare(
733
+ "
734
  SELECT DISTINCT tt.description FROM $wpdb->term_taxonomy AS tt
735
  INNER JOIN $wpdb->term_relationships AS tr ON tt.term_taxonomy_id = tr.term_taxonomy_id
736
  INNER JOIN $wpdb->posts AS p ON p.ID = tr.object_id
737
  WHERE tt.taxonomy = %s
738
  AND p.post_type = %s
739
  AND p.post_status NOT IN ('trash', 'auto-draft')",
740
+ 'post_translations',
741
+ $post_type
742
+ )
743
+ );
744
 
745
+ $targets = $this->get_target_count( $groups );
746
 
747
  $group_ids = array();
748
+ $disabled = array();
749
 
750
+ foreach ( $this->pllm->get_languages_list() as $language ) {
751
  // counts all the posts in one language
752
+ $n = $wpdb->get_var(
753
+ $wpdb->prepare(
754
+ "
755
  SELECT COUNT(*) FROM $wpdb->term_relationships AS tr
756
  INNER JOIN $wpdb->posts AS p ON p.ID = tr.object_id
757
  WHERE tr.term_taxonomy_id = %d
758
  AND p.post_type = %s
759
  AND p.post_status NOT IN ('trash', 'auto-draft')",
760
+ $language->term_taxonomy_id,
761
+ $post_type
762
+ )
763
+ );
764
+
765
+ $objects = $wpdb->get_col(
766
+ $wpdb->prepare(
767
+ "
768
  SELECT object_id FROM $wpdb->term_relationships AS tr
769
  INNER JOIN $wpdb->posts AS p ON p.ID = tr.object_id
770
  WHERE tr.term_taxonomy_id = %d
771
  AND p.post_type = %s
772
  AND p.post_status NOT IN ('trash', 'auto-draft')",
773
+ $language->term_taxonomy_id,
774
+ $post_type
775
+ )
776
+ );
777
+
778
+ foreach ( $groups as $group ) {
779
+ $group = unserialize( $group );
780
+ if ( array_key_exists( $language->slug, $group ) ) {
781
+ $group_ids[] = $group[ $language->slug ];
782
  }
783
  }
784
 
785
  $count = 0;
786
+ foreach ( $objects as $object ) {
787
  $id = $object;
788
+ if ( ! in_array( $id, $group_ids, true ) ) {
789
+ $profile = self::get_profile( $post_type, $language, $id );
790
+ if ( 'disabled' === $profile['profile'] && in_array( $id, $objects, true ) ) {
791
+ ++$count;
792
  }
793
  }
794
  }
795
+ $disabled[ $language->slug ] = $count;
796
 
797
  // if a post is not a target, then it is source
798
+ $sources[ $language->slug ] = $n - $targets[ $language->slug ];
799
  // $sources[$language->slug] -= $disabled[$language->slug];
800
+ }//end foreach
801
 
802
  // untranslated posts have no associated translation group in DB
803
  // so let's count them indirectly
804
 
805
  // counts the number of translated posts
806
+ $n_translated = $wpdb->get_var(
807
+ $wpdb->prepare(
808
+ "
809
  SELECT COUNT(*) FROM $wpdb->term_relationships AS tr
810
  INNER JOIN $wpdb->posts AS p ON p.ID = tr.object_id
811
  INNER JOIN $wpdb->term_taxonomy AS tt ON tt.term_taxonomy_id = tr.term_taxonomy_id
812
  WHERE tt.taxonomy = %s
813
  AND p.post_type = %s
814
  AND p.post_status NOT IN ('trash', 'auto-draft')",
815
+ 'post_translations',
816
+ $post_type
817
+ )
818
+ );
819
 
820
  // untranslated = total - translated
821
  // total of posts translations groups = untranslated + number of translation groups stored in DB
822
+ $count_posts = (array) wp_count_posts( $post_type );
823
+ // Don't count trash and auto-draft.
824
+ unset( $count_posts['trash'], $count_posts['auto-draft'] );
825
+ $total = array_sum( $count_posts ) - $n_translated + count( $groups );
826
 
827
+ return $r[ $post_type ] = compact( 'sources', 'targets', 'total' );
828
  }
829
 
830
+ /**
831
  * counts the number of sources and targets per language for a certain taxonomy
832
  *
833
  * @since 0.2
835
  * @param string $taxonomy
836
  * @return array
837
  */
838
+ public function count_terms( $taxonomy ) {
839
  global $wpdb;
840
 
841
  static $r = array();
842
+ if ( ! empty( $r[ $taxonomy ] ) ) {
843
+ return $r[ $taxonomy ];
844
+ }
845
 
846
+ if ( ! taxonomy_exists( $taxonomy ) ) {
847
  return;
848
+ }
849
 
850
  // gets all translations groups for the taxonomy
851
+ $groups = $wpdb->get_col(
852
+ $wpdb->prepare(
853
+ "
854
  SELECT DISTINCT tt1.description FROM $wpdb->term_taxonomy AS tt1
855
  INNER JOIN $wpdb->term_relationships AS tr ON tt1.term_taxonomy_id = tr.term_taxonomy_id
856
  INNER JOIN $wpdb->term_taxonomy AS tt2 ON tt2.term_id = tr.object_id
857
  WHERE tt1.taxonomy = %s
858
  AND tt2.taxonomy = %s",
859
+ 'term_translations',
860
+ $taxonomy
861
+ )
862
+ );
863
 
864
+ $targets = $this->get_target_count( $groups );
865
 
866
  $group_ids = array();
867
+ $disabled = array();
868
 
869
+ foreach ( $this->pllm->get_languages_list() as $language ) {
870
  // counts all the terms in one language
871
+ $n = $wpdb->get_var(
872
+ $wpdb->prepare(
873
+ "
874
  SELECT COUNT(*) FROM $wpdb->term_relationships AS tr
875
  INNER JOIN $wpdb->term_taxonomy AS tt ON tt.term_id = tr.object_id
876
  WHERE tr.term_taxonomy_id = %d
877
  AND tt.taxonomy = %s",
878
+ $language->tl_term_taxonomy_id,
879
+ $taxonomy
880
+ )
881
+ );
882
+
883
+ $objects = $wpdb->get_col(
884
+ $wpdb->prepare(
885
+ "
886
  SELECT object_id FROM $wpdb->term_relationships AS tr
887
  INNER JOIN $wpdb->term_taxonomy AS tt ON tt.term_id = tr.object_id
888
  WHERE tr.term_taxonomy_id = %d
889
  AND tt.taxonomy = %s",
890
+ $language->tl_term_taxonomy_id,
891
+ $taxonomy
892
+ )
893
+ );
894
 
895
  $count = 0;
896
+ foreach ( $groups as $group ) {
897
+ $group = unserialize( $group );
898
+ if ( array_key_exists( $language->slug, $group ) ) {
899
+ $group_ids[] = $group[ $language->slug ];
900
+ $profile = self::get_profile( $taxonomy, $language, $group[ $language->slug ] );
901
+ if ( 'disabled' === $profile['profile'] && ! isset( $group['lingotek'] ) ) {
902
+ ++$count;
903
  }
904
  }
905
  }
906
 
907
+ $disabled[ $language->slug ] = $count;
 
908
 
909
  // if a term is not a target, then it is a source
910
+ $sources[ $language->slug ] = $n - $targets[ $language->slug ];
911
  // $sources[$language->slug] -= $disabled[$language->slug];
912
+ }//end foreach
913
 
914
+ $total = count( $groups );
915
 
916
  // default categories are created by Polylang in all languages
917
  // don't count them as sources if they are not associated to the TMS
918
+ if ( 'category' === $taxonomy ) {
919
+ $term_id = get_option( 'default_category' );
920
+ $group = $this->get_group( 'term', $term_id );
921
+ foreach ( $this->pllm->get_languages_list() as $language ) {
922
+ if ( empty( $group->source ) || ( $group->get_source_language()->slug !== $language->slug && empty( $group->translations[ $language->locale ] ) ) ) {
923
+ if ( $language->slug !== $this->pllm->options['default_lang'] ) {
924
+ $sources[ $language->slug ]--;
925
  }
926
  }
927
  }
928
  // Remove category targets from being counted until they are downloaded. Fixed target categories being counted as source languages.
929
+ foreach ( $groups as $group ) {
930
+ $group = unserialize( $group );
931
+ if ( isset( $group['lingotek']['translations'] ) ) {
932
+ foreach ( $group['lingotek']['translations'] as $locale => $status ) {
933
+ $language = $this->pllm->get_language( $locale );
934
+ if ( ( 'pending' === $status || 'ready' === $status ) && $language ) {
935
+ if ( $sources[ $language->slug ] > 0 ) {
936
+ $sources[ $language->slug ]--;
937
  }
938
  }
939
  }
940
  }
941
  }
942
+ if ( 1 === count( $sources ) && $total !== $sources[ $this->pllm->options['default_lang'] ] ) {
943
+ $total = $sources[ $this->pllm->options['default_lang'] ];
944
  }
945
+ }//end if
946
+ $r[ $taxonomy ] = compact( 'sources', 'targets', 'total' );
947
+ return $r[ $taxonomy ];
948
  }
949
 
950
+ private function build_params( $external_url, $title, $type, $content, $language, $profile, $wp_id, &$wp_target_locales = array() ) {
951
+ $translation_workflow_id = self::get_profile_option( 'workflow_id', $type, $language, false, $wp_id );
952
+ if ( 'project-default' === $translation_workflow_id || false === $translation_workflow_id ) {
 
953
  $translation_workflow_id = null;
954
  }
955
 
956
  $params = array(
957
+ 'title' => $title,
958
+ 'content' => $content,
959
+ 'locale_code' => $language->lingotek_locale,
960
+ 'project_id' => self::get_profile_option( 'project_id', $type, $language, false, $wp_id ),
961
+ 'external_url' => $external_url,
962
  );
963
 
964
+ $lingotek_metadata_keys = array(
965
+ 'author_email',
966
+ 'author_name',
967
+ 'division',
968
+ 'unit',
969
+ 'campaign_id',
970
+ 'channel',
971
+ 'contact_email',
972
+ 'contact_name',
973
+ 'description',
974
+ 'domain',
975
+ 'style_id',
976
+ 'purchase_order',
977
+ 'reference_url',
978
+ 'region',
979
+ 'require_review',
980
+ );
981
+
982
+ foreach ( $lingotek_metadata_keys as $key ) {
983
+ if ( isset( $profile[ $key ] ) ) {
984
+ $params[ $key ] = $profile[ $key ];
985
+ }
986
+ }
987
+
988
+ if ( null !== $translation_workflow_id ) {
989
  $params['translation_workflow_id'] = $translation_workflow_id;
990
  }
991
 
992
  // Get target locales to send up from profile
993
  $target_locales = array();
994
+ if ( ! empty( $profile['target_locales'] ) ) {
995
+ if ( isset( $profile['target_locales'][ $language->slug ] ) ) {
996
+ unset( $profile['target_locales'][ $language->slug ] );
997
  }
998
+ if ( isset( $profile['custom']['workflow_id'][ $language->slug ] ) ) {
999
+ unset( $profile['custom']['workflow_id'][ $language->slug ] );
1000
  }
1001
+ $target_locales['translation_locale_code'] = array_values( $profile['target_locales'] );
1002
+ $wp_target_locales = array_keys( $profile['target_locales'] );
1003
 
1004
  // Add workflows
1005
+ if ( ! empty( $profile['custom']['workflow_id'] ) ) {
1006
+ $temp_workflow_ids = array();
1007
+ $workflow_id = null;
1008
+ foreach ( $wp_target_locales as $language_slug ) {
1009
+ if ( isset( $profile['custom']['workflow_id'][ $language_slug ] ) ) {
1010
+ $profile_override = $profile['custom']['workflow_id'][ $language_slug ];
1011
+ $workflow_id = 'project-default' === $profile_override ? $translation_workflow_id : $profile_override;
1012
+ } else {
 
1013
  $workflow_id = $translation_workflow_id;
1014
  }
1015
+ if ( $workflow_id ) {
1016
  $temp_workflow_ids[] = $workflow_id;
1017
  }
1018
  }
1019
  $params['translation_workflow_id'] = $temp_workflow_ids;
1020
  }
1021
+ } else {
 
1022
  // No targets being sent up to TMS, unset the workflow
1023
+ unset( $params['translation_workflow_id'] );
1024
+ }//end if
1025
 
1026
+ $params = array_merge( $params, $target_locales );
1027
 
1028
  return $params;
1029
  }
1030
 
1031
+ private function get_filter_ids( $type, $language, $wp_id ) {
1032
  $filter_ids = array();
1033
+ if ( self::get_profile_option( 'primary_filter_id', $type, $language, false, $wp_id ) ) {
1034
+ $filter_ids['fprm_id'] = self::get_profile_option( 'primary_filter_id', $type, $language, false, $wp_id );
1035
  }
1036
+ if ( self::get_profile_option( 'secondary_filter_id', $type, $language, false, $wp_id ) ) {
1037
+ $filter_ids['fprm_subfilter_id'] = self::get_profile_option( 'secondary_filter_id', $type, $language, false, $wp_id );
1038
  }
1039
  return $filter_ids;
1040
  }
include/plugins-compat.php CHANGED
@@ -8,33 +8,34 @@
8
  * @since 1.0.6
9
  */
10
  class Lingotek_Plugins_Compat {
11
- static protected $instance;
12
 
13
  protected function __construct() {
14
  // WordPress Importer
15
- add_action('init', array(&$this, 'lingotek_maybe_wordpress_importer'));
16
  }
17
 
18
- static public function instance() {
19
- if (empty(self::$instance))
20
  self::$instance = new self();
 
21
 
22
  return self::$instance;
23
  }
24
 
25
  function lingotek_maybe_wordpress_importer() {
26
- if (defined('WP_LOAD_IMPORTERS') && class_exists('WP_Import')) {
27
- remove_action('admin_init', 'lingotek_wordpress_importer_init');
28
- add_action('admin_init', array(&$this, 'lingotek_wordpress_importer_init'));
29
  }
30
  }
31
 
32
  function lingotek_wordpress_importer_init() {
33
- $class = new ReflectionClass('WP_Import');
34
- load_plugin_textdomain( 'wordpress-importer', false, basename(dirname( $class->getFileName() )) . '/languages' );
35
 
36
  $GLOBALS['wp_import'] = new Lingotek_WP_Import();
37
- register_importer( 'wordpress', 'WordPress', __('Import <strong>posts, pages, comments, custom fields, categories, and tags</strong> from a WordPress export file.', 'wordpress-importer'), array( $GLOBALS['wp_import'], 'dispatch' ) );
38
  }
39
  }
40
- ?>
8
  * @since 1.0.6
9
  */
10
  class Lingotek_Plugins_Compat {
11
+ protected static $instance;
12
 
13
  protected function __construct() {
14
  // WordPress Importer
15
+ add_action( 'init', array( &$this, 'lingotek_maybe_wordpress_importer' ) );
16
  }
17
 
18
+ public static function instance() {
19
+ if ( empty( self::$instance ) ) {
20
  self::$instance = new self();
21
+ }
22
 
23
  return self::$instance;
24
  }
25
 
26
  function lingotek_maybe_wordpress_importer() {
27
+ if ( defined( 'WP_LOAD_IMPORTERS' ) && class_exists( 'WP_Import' ) ) {
28
+ remove_action( 'admin_init', 'lingotek_wordpress_importer_init' );
29
+ add_action( 'admin_init', array( &$this, 'lingotek_wordpress_importer_init' ) );
30
  }
31
  }
32
 
33
  function lingotek_wordpress_importer_init() {
34
+ $class = new ReflectionClass( 'WP_Import' );
35
+ load_plugin_textdomain( 'wordpress-importer', false, basename( dirname( $class->getFileName() ) ) . '/languages' );
36
 
37
  $GLOBALS['wp_import'] = new Lingotek_WP_Import();
38
+ register_importer( 'WordPress', 'WordPress', __( 'Import <strong>posts, pages, comments, custom fields, categories, and tags</strong> from a WordPress export file.', 'wordpress-importer' ), array( $GLOBALS['wp_import'], 'dispatch' ) );
39
  }
40
  }
41
+
include/pointer.php CHANGED
@@ -12,22 +12,22 @@ class Lingotek_Pointer {
12
  * pointer => required, unique identifier of the pointer
13
  * id => required, the pointer will be attached to this html id
14
  * position => optional array, if used both sub parameters are required
15
- * edge => 'top' or 'bottom'
16
- * align => 'right' or 'left'
17
  * width => optional, the width in px
18
  * title => required, title
19
  * content => required, content
20
  * buttons => optional array of arrays, by default the pointer uses the standard dismiss button offered by WP
21
- * label => the label of the button
22
- * link => optional link for the button. By default, the button just dismisses the pointer
23
  *
24
  * @since 1.0.1
25
  *
26
  * @param array $args
27
  */
28
- public function __construct($args) {
29
  $this->args = $args;
30
- add_action('admin_enqueue_scripts', array(&$this, 'enqueue_scripts'));
31
  }
32
 
33
  /**
@@ -36,17 +36,18 @@ class Lingotek_Pointer {
36
  * @since 1.0.1
37
  */
38
  public function enqueue_scripts() {
39
- $dismissed = explode(',', get_user_meta(get_current_user_id(), 'dismissed_wp_pointers', true));
40
 
41
  // comment the two lines below to make the pointer non dismissable
42
- if (in_array($this->args['pointer'], $dismissed) || !current_user_can('manage_options'))
43
  return;
 
44
 
45
  // Add pointer JavaScript
46
- add_action('admin_print_footer_scripts', array(&$this, 'print_js'));
47
 
48
- wp_enqueue_style('wp-pointer');
49
- wp_enqueue_script('wp-pointer');
50
  }
51
 
52
  /**
@@ -57,15 +58,17 @@ class Lingotek_Pointer {
57
  public function print_js() {
58
 
59
  // add optional buttons
60
- if (!empty($this->args['buttons'])) {
 
61
  $b = "
62
  var widget = pointer.pointer('widget');
63
  var buttons = $('.wp-pointer-buttons', widget);
64
- $('a.close', widget).remove();"; // removes the WP button
65
 
66
  // all the buttons use the standard WP ajax action to remember the pointer has been dismissed
67
- foreach ($this->args['buttons'] as $button) {
68
- $b .= sprintf("
 
69
  $('<a>').addClass('%s').html('%s').css('margin-left', '10px').click(function() {
70
  $.post(ajaxurl, {
71
  pointer: '%s',
@@ -74,15 +77,16 @@ class Lingotek_Pointer {
74
  %s
75
  });
76
  }).appendTo(buttons);",
77
- empty($button['link']) ? 'button' : 'button button-primary',
78
  $button['label'],
79
  $this->args['pointer'],
80
- empty($button['link']) ? "pointer.pointer('close')" : sprintf("location.href = '%s'", $button['link'])
81
  );
82
  }
83
- }
84
 
85
- $js = sprintf("
 
86
  //<![CDATA[
87
  jQuery(document).ready(function($) {
88
  var pointer = $('#%s').pointer({
@@ -95,13 +99,13 @@ class Lingotek_Pointer {
95
  });
96
  // ]]>",
97
  $this->args['id'],
98
- sprintf('<h3>%s</h3><p>%s</p>', $this->args['title'], $this->args['content']),
99
- empty($this->args['position']) ? '' : sprintf('position: {edge: "%s", align: "%s",},', $this->args['position']['edge'], $this->args['position']['align']),
100
- empty($this->args['width']) ? '' : sprintf('pointerWidth: %d,', $this->args['width']),
101
- empty($b) ? '' : $b
102
  );
103
- echo "<script type='text/javascript'>" .$js. "</script>";
104
  }
105
  }
106
 
107
- ?>
12
  * pointer => required, unique identifier of the pointer
13
  * id => required, the pointer will be attached to this html id
14
  * position => optional array, if used both sub parameters are required
15
+ * edge => 'top' or 'bottom'
16
+ * align => 'right' or 'left'
17
  * width => optional, the width in px
18
  * title => required, title
19
  * content => required, content
20
  * buttons => optional array of arrays, by default the pointer uses the standard dismiss button offered by WP
21
+ * label => the label of the button
22
+ * link => optional link for the button. By default, the button just dismisses the pointer
23
  *
24
  * @since 1.0.1
25
  *
26
  * @param array $args
27
  */
28
+ public function __construct( $args ) {
29
  $this->args = $args;
30
+ add_action( 'admin_enqueue_scripts', array( &$this, 'enqueue_scripts' ) );
31
  }
32
 
33
  /**
36
  * @since 1.0.1
37
  */
38
  public function enqueue_scripts() {
39
+ $dismissed = explode( ',', get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) );
40
 
41
  // comment the two lines below to make the pointer non dismissable
42
+ if ( in_array( $this->args['pointer'], $dismissed ) || ! current_user_can( 'manage_options' ) ) {
43
  return;
44
+ }
45
 
46
  // Add pointer JavaScript
47
+ add_action( 'admin_print_footer_scripts', array( &$this, 'print_js' ) );
48
 
49
+ wp_enqueue_style( 'wp-pointer' );
50
+ wp_enqueue_script( 'wp-pointer' );
51
  }
52
 
53
  /**
58
  public function print_js() {
59
 
60
  // add optional buttons
61
+ if ( ! empty( $this->args['buttons'] ) ) {
62
+ // Removes the WordPress button.
63
  $b = "
64
  var widget = pointer.pointer('widget');
65
  var buttons = $('.wp-pointer-buttons', widget);
66
+ $('a.close', widget).remove();";
67
 
68
  // all the buttons use the standard WP ajax action to remember the pointer has been dismissed
69
+ foreach ( $this->args['buttons'] as $button ) {
70
+ $b .= sprintf(
71
+ "
72
  $('<a>').addClass('%s').html('%s').css('margin-left', '10px').click(function() {
73
  $.post(ajaxurl, {
74
  pointer: '%s',
77
  %s
78
  });
79
  }).appendTo(buttons);",
80
+ empty( $button['link'] ) ? 'button' : 'button button-primary',
81
  $button['label'],
82
  $this->args['pointer'],
83
+ empty( $button['link'] ) ? "pointer.pointer('close')" : sprintf( "location.href = '%s'", $button['link'] )
84
  );
85
  }
86
+ }//end if
87
 
88
+ $js = sprintf(
89
+ "
90
  //<![CDATA[
91
  jQuery(document).ready(function($) {
92
  var pointer = $('#%s').pointer({
99
  });
100
  // ]]>",
101
  $this->args['id'],
102
+ sprintf( '<h3>%s</h3><p>%s</p>', $this->args['title'], $this->args['content'] ),
103
+ empty( $this->args['position'] ) ? '' : sprintf( 'position: {edge: "%s", align: "%s",},', $this->args['position']['edge'], $this->args['position']['align'] ),
104
+ empty( $this->args['width'] ) ? '' : sprintf( 'pointerWidth: %d,', $this->args['width'] ),
105
+ empty( $b ) ? '' : $b
106
  );
107
+ echo "<script type='text/javascript'>" . $js . '</script>';
108
  }
109
  }
110
 
111
+
js/updater.js CHANGED
@@ -125,11 +125,13 @@ jQuery(document).ready(function($) {
125
  var source = data[key]['source'];
126
  if(locale === data[key]['source']){
127
  $(td).find('.lingotek-color').remove();
 
128
  $(td).find('.pll_icon_edit').remove();
129
  updateUploadIndicator(td, data, key, locale);
130
  }
131
  else if (data[key][locale]['status'] === 'disabled' || data[key]['source'] === 'disabled') {
132
  $(td).find('.lingotek-color').remove();
 
133
  }
134
  else if ($(td).find('.pll_icon_add').length > 0 && (data[key][data[key]['source']]['status'] === 'none' || data[key][data[key]['source']]['status'] === 'cancelled')){
135
  break;
@@ -143,6 +145,7 @@ jQuery(document).ready(function($) {
143
  $(td).find('.pll_icon_tick').remove();
144
  $(td).find('.pll_icon_edit').remove();
145
  $(td).find('.lingotek-color').remove();
 
146
  updateIndicator(td, data, key, locale, 'request', 'Request a translation', 'plus');
147
  updateGenericBulkLink(tr, data, key, 'request' , 'Request translations of this item to Lingotek TMS', 'Request translations');
148
  }
@@ -151,6 +154,7 @@ jQuery(document).ready(function($) {
151
  $(td).find('.pll_icon_tick').remove();
152
  $(td).find('.pll_icon_edit').remove();
153
  $(td).find('.lingotek-color').remove();
 
154
  var indicator = $('<div></div>').addClass('lingotek-color dashicons dashicons-no');
155
  $(td).prepend(indicator);
156
  }
@@ -186,6 +190,7 @@ jQuery(document).ready(function($) {
186
  }
187
  $(td).find('.pll_icon_edit').remove();
188
  $(td).find('.lingotek-color').remove();
 
189
  var request_link = $('<a></a>').attr('href', data[key][locale]['workbench_link'])
190
  .attr('title',title)
191
  .attr('target','_blank')
@@ -194,6 +199,13 @@ jQuery(document).ready(function($) {
194
  }
195
 
196
  function updateInterimIcon(td, data, key, locale) {
 
 
 
 
 
 
 
197
  $(td).find('.lingotek-professional-icon').remove();
198
  var icon = 'edit';
199
  $(td).find('.lingotek-interim-color').remove();
@@ -278,6 +290,7 @@ jQuery(document).ready(function($) {
278
 
279
  function updateUploadIndicator(td, data, key, locale){
280
  $(td).find('.lingotek-color').remove();
 
281
  var request_link = $('<a></a>').attr('href', relative_url
282
  + page_params + 'post=' + key
283
  + '&locale=' + locale
@@ -291,6 +304,7 @@ jQuery(document).ready(function($) {
291
 
292
  function updateFailedIndicator(td, data, key, locale) {
293
  $(td).find('.lingotek-color').remove();
 
294
  $(td).find('.lingotek-failed-color').remove();
295
  var reupload_failed_doc = $('<a></a>').attr('title', 'Upload Failed. Click to re-upload')
296
  .attr('href', relative_url
@@ -307,14 +321,15 @@ jQuery(document).ready(function($) {
307
  $(td).find('.lingotek-professional-icon').remove();
308
  }
309
  $(td).find('.lingotek-color').remove();
310
- var request_link = $('<a></a>').attr('href', relative_url
311
- + page_params + 'document_id=' + data[key]['doc_id']
312
- + '&locale=' + locale
313
- + '&action=lingotek-' + action
314
- + '&noheader=1'
315
- + '&_wpnonce='+data[action + '_nonce'])
316
- .attr('title', title)
317
- .addClass('lingotek-color dashicons dashicons-' + dashicon + ' dashicons-' + dashicon + '-lingotek');
 
318
  $(td).prepend(request_link);
319
  }
320
 
@@ -322,6 +337,7 @@ jQuery(document).ready(function($) {
322
  $(td).find('.pll_icon_edit').remove();
323
  if(locale === data[key]['source']){
324
  $(td).find('.lingotek-color').remove();
 
325
  if(post_data['terms_translations'] === true){
326
  var request_link = $('<a></a>').attr('href', relative_url
327
  + '/edit-tags.php?action=edit'
125
  var source = data[key]['source'];
126
  if(locale === data[key]['source']){
127
  $(td).find('.lingotek-color').remove();
128
+ $(td).find('.lingotek-interim-color').remove();
129
  $(td).find('.pll_icon_edit').remove();
130
  updateUploadIndicator(td, data, key, locale);
131
  }
132
  else if (data[key][locale]['status'] === 'disabled' || data[key]['source'] === 'disabled') {
133
  $(td).find('.lingotek-color').remove();
134
+ $(td).find('.lingotek-interim-color').remove();
135
  }
136
  else if ($(td).find('.pll_icon_add').length > 0 && (data[key][data[key]['source']]['status'] === 'none' || data[key][data[key]['source']]['status'] === 'cancelled')){
137
  break;
145
  $(td).find('.pll_icon_tick').remove();
146
  $(td).find('.pll_icon_edit').remove();
147
  $(td).find('.lingotek-color').remove();
148
+ $(td).find('.lingotek-interim-color').remove();
149
  updateIndicator(td, data, key, locale, 'request', 'Request a translation', 'plus');
150
  updateGenericBulkLink(tr, data, key, 'request' , 'Request translations of this item to Lingotek TMS', 'Request translations');
151
  }
154
  $(td).find('.pll_icon_tick').remove();
155
  $(td).find('.pll_icon_edit').remove();
156
  $(td).find('.lingotek-color').remove();
157
+ $(td).find('.lingotek-interim-color').remove();
158
  var indicator = $('<div></div>').addClass('lingotek-color dashicons dashicons-no');
159
  $(td).prepend(indicator);
160
  }
190
  }
191
  $(td).find('.pll_icon_edit').remove();
192
  $(td).find('.lingotek-color').remove();
193
+ $(td).find('.lingotek-interim-color').remove();
194
  var request_link = $('<a></a>').attr('href', data[key][locale]['workbench_link'])
195
  .attr('title',title)
196
  .attr('target','_blank')
199
  }
200
 
201
  function updateInterimIcon(td, data, key, locale) {
202
+ $(td).find('.lingotek-color').remove();
203
+ $(td).find('.lingotek-interim-color').remove();
204
+ if ($(td).find('dashicons-no').length > 0) {
205
+ $(td).find('.dashicons-no').remove();
206
+ } else if ($(td).find('.dashicons-clock').length > 0) {
207
+ $(td).find('.dashicons-clock').remove();
208
+ }
209
  $(td).find('.lingotek-professional-icon').remove();
210
  var icon = 'edit';
211
  $(td).find('.lingotek-interim-color').remove();
290
 
291
  function updateUploadIndicator(td, data, key, locale){
292
  $(td).find('.lingotek-color').remove();
293
+ $(td).find('.lingotek-interim-color').remove();
294
  var request_link = $('<a></a>').attr('href', relative_url
295
  + page_params + 'post=' + key
296
  + '&locale=' + locale
304
 
305
  function updateFailedIndicator(td, data, key, locale) {
306
  $(td).find('.lingotek-color').remove();
307
+ $(td).find('.lingotek-interim-color').remove();
308
  $(td).find('.lingotek-failed-color').remove();
309
  var reupload_failed_doc = $('<a></a>').attr('title', 'Upload Failed. Click to re-upload')
310
  .attr('href', relative_url
321
  $(td).find('.lingotek-professional-icon').remove();
322
  }
323
  $(td).find('.lingotek-color').remove();
324
+ $(td).find('.lingotek-interim-color').remove();
325
+ var request_link = $('<a></a>').attr('href', relative_url
326
+ + page_params + 'document_id=' + data[key]['doc_id']
327
+ + '&locale=' + locale
328
+ + '&action=lingotek-' + action
329
+ + '&noheader=1'
330
+ + '&_wpnonce='+data[action + '_nonce'])
331
+ .attr('title', title)
332
+ .addClass('lingotek-color dashicons dashicons-' + dashicon + ' dashicons-' + dashicon + '-lingotek');
333
  $(td).prepend(request_link);
334
  }
335
 
337
  $(td).find('.pll_icon_edit').remove();
338
  if(locale === data[key]['source']){
339
  $(td).find('.lingotek-color').remove();
340
+ $(td).find('.lingotek-interim-color').remove();
341
  if(post_data['terms_translations'] === true){
342
  var request_link = $('<a></a>').attr('href', relative_url
343
  + '/edit-tags.php?action=edit'
lingotek.php CHANGED
@@ -2,7 +2,7 @@
2
  /**
3
  Plugin name: Lingotek Translation
4
  Plugin URI: http://lingotek.com/wordpress#utm_source=wpadmin&utm_medium=plugin&utm_campaign=wplingotektranslationplugin
5
- Version: 1.4.13
6
  Author: Lingotek and Frédéric Demarle
7
  Author uri: http://lingotek.com
8
  Description: Lingotek offers convenient cloud-based localization and translation.
@@ -16,218 +16,222 @@ if ( ! function_exists( 'add_action' ) ) {
16
  exit();
17
  }
18
 
19
- define( 'LINGOTEK_VERSION', '1.4.13' ); // plugin version (should match above meta).
 
20
  define( 'LINGOTEK_MIN_PLL_VERSION', '1.8' );
21
- define( 'LINGOTEK_BASENAME', plugin_basename( __FILE__ ) ); // plugin name as known by WP.
22
- define( 'LINGOTEK_PLUGIN_SLUG', 'lingotek-translation' );// plugin slug (should match above meta: Text Domain).
23
- define( 'LINGOTEK_DIR', dirname( __FILE__ ) ); // our directory.
 
 
 
24
  define( 'LINGOTEK_INC', LINGOTEK_DIR . '/include' );
25
- define( 'LINGOTEK_ADMIN_INC', LINGOTEK_DIR . '/admin' );
26
- define( 'LINGOTEK_WORKFLOWS', LINGOTEK_ADMIN_INC . '/workflows' );
27
  define( 'LINGOTEK_URL', plugins_url( '', __FILE__ ) );
28
  define( 'BRIDGE_URL', 'https://marketplace.lingotek.com' );
29
 
30
  class Lingotek {
31
  /**
32
- * Lingotek model.
33
  *
34
- * @var object
35
  */
36
  public $model;
37
 
38
  /**
39
- * Callback method
40
  *
41
- * @var method
42
  */
43
  public $callback;
44
 
45
  /**
46
- * Array to map Lingotek locales to WP locales.
47
- * map as 'WP locale' => 'Lingotek locale'.
48
  *
49
  * TODO: update this list!!!!
50
- * @var array
 
51
  */
52
  public static $lingotek_locales = array(
53
- 'af' => 'af-ZA',
54
- 'ak' => 'ak-GH',
55
- 'am' => 'am-ET',
56
- 'ar' => 'ar',
57
- 'ar_AE' => 'ar-AE',
58
- 'ar_AF' => 'ar-AF',
59
- 'ar_BH' => 'ar-BH',
60
- 'ar_DZ' => 'ar-DZ',
61
- 'ar_EG' => 'ar-EG',
62
- 'ar_IQ' => 'ar-IQ',
63
- 'ar_JO' => 'ar-JO',
64
- 'ar_LY' => 'ar-LY',
65
- 'ar_MA' => 'ar-MA',
66
- 'ar_MR' => 'ar-MR',
67
- 'ar_OM' => 'ar-OM',
68
- 'ar_SA' => 'ar-SA',
69
- 'ar_SD' => 'ar-SD',
70
- 'ar_SY' => 'ar-SY',
71
- 'ar_TD' => 'ar-TD',
72
- 'ar_TN' => 'ar-TN',
73
- 'ar_UZ' => 'ar-UZ',
74
- 'ar_YE' => 'ar-YE',
75
- 'as' => 'as-IN',
76
- 'az' => 'az-AZ',
77
- 'ba' => 'ba-RU',
78
- 'bel' => 'be-BY',
79
- 'bg_BG' => 'bg-BG',
80
- 'bn_BD' => 'bn-BD',
81
- 'bo' => 'bo-CN',
82
- 'bs_BA' => 'bs-BA',
83
- 'ca' => 'ca-ES',
84
- 'ca_ES' => 'ca-ES',
85
- 'co' => 'co-FR',
86
- 'cs_CZ' => 'cs-CZ',
87
- 'cy' => 'cy-GB',
88
- 'cy_GB' => 'cy-GB',
89
- 'de_AT' => 'de-AT',
90
- 'da_DK' => 'da-DK',
91
- 'de_CH' => 'de-CH',
92
- 'de_DE' => 'de-DE',
93
- 'dv' => 'dv-MV',
94
- 'el' => 'el-GR',
95
- 'el_GR' => 'el-GR',
96
- 'en_AU' => 'en-AU',
97
- 'en_CA' => 'en-CA',
98
- 'en_GB' => 'en-GB',
99
- 'en_US' => 'en-US',
100
- 'en_IE' => 'en-IE',
101
- 'en_IN' => 'en-IN',
102
- 'en_ZA' => 'en-ZA',
103
- 'eo' => 'eo-FR',
104
- 'es_419' => 'es-419',
105
- 'es_AR' => 'es-AR',
106
- 'es_BO' => 'es-BO',
107
- 'es_CL' => 'es-CL',
108
- 'es_CO' => 'es-CO',
109
- 'es_ES' => 'es-ES',
110
- 'es_MX' => 'es-MX',
111
- 'es_PE' => 'es-PE',
112
- 'es_PR' => 'es-PR',
113
- 'es_VE' => 'es-VE',
114
- 'es_HN' => 'es-HN',
115
- 'es_CR' => 'es-CR',
116
- 'es_CU' => 'es-CU',
117
- 'es_DO' => 'es-DO',
118
- 'es_EC' => 'es-EC',
119
- 'es_GT' => 'es-GT',
120
- 'es_NI' => 'es-NI',
121
- 'es_PA' => 'es-PA',
122
- 'es_PY' => 'es-PY',
123
- 'es_SV' => 'es-SV',
124
- 'es_UY' => 'es-UY',
125
- 'es_US' => 'es-US',
126
- 'et' => 'et-EE',
127
- 'et_EE' => 'et-EE',
128
- 'eu' => 'eu-ES',
129
- 'fa_IR' => 'fa-IR',
130
- 'fi' => 'fi-FI',
131
- 'fi_FI' => 'fi-FI',
132
- 'fr_FR' => 'fr-FR',
133
- 'fr_BE' => 'fr-BE',
134
- 'fr_CA' => 'fr-CA',
135
- 'fr_CH' => 'fr-CH',
136
- 'fr_US' => 'fr-US',
137
- 'ga' => 'ga-IE',
138
- 'gd' => 'gd-GB',
139
- 'gl_ES' => 'gl-ES',
140
- 'gn' => 'gn-BO',
141
  'haw_US' => 'haw-US',
142
- 'he_IL' => 'he-IL',
143
- 'hi_IN' => 'hi-IN',
144
- 'hr' => 'hr-HR',
145
- 'ht_HT' => 'ht-HT',
146
- 'hu_HU' => 'hu-HU',
147
- 'hy' => 'hy-AM',
148
- 'id_ID' => 'id-ID',
149
- 'is_IS' => 'is-IS',
150
- 'it_IT' => 'it-IT',
151
- 'it_CH' => 'it-CH',
152
- 'ja' => 'ja-JP',
153
- 'ja_JP' => 'ja-JP',
154
- 'jv_ID' => 'jv-ID',
155
- 'ka_GE' => 'ka-GE',
156
- 'kin' => 'kin-RW',
157
- 'kk' => 'kk-KZ',
158
- 'kn' => 'kn-IN',
159
- 'ko_KR' => 'ko-KR',
160
- 'ky_KY' => 'ky-KG',
161
- 'lb_LU' => 'lb-LU',
162
- 'lo' => 'lo-LA',
163
- 'lt_LT' => 'lt-LT',
164
- 'lv' => 'lv-LV',
165
- 'lv_LV' => 'lv-LV',
166
- 'mg_MG' => 'mg-MG',
167
- 'mk_MK' => 'mk-MK',
168
- 'ml_IN' => 'ml-IN',
169
- 'mn' => 'mn-MN',
170
- 'mr' => 'mr-IN',
171
- 'ms_MY' => 'ms-MY',
172
- 'mt_MT' => 'mt-MT',
173
- 'my_MM' => 'my-MM',
174
- 'ne_NP' => 'ne-NP',
175
- 'nl_BE' => 'nl-BE',
176
- 'nl_NL' => 'nl-NL',
177
- 'nn_NO' => 'nn-NO',
178
- 'no_NO' => 'no-NO',
179
- 'pa_IN' => 'pa-IN',
180
- 'pl_PL' => 'pl-PL',
181
- 'ps' => 'ps-AF',
182
- 'pt_BR' => 'pt-BR',
183
- 'pt_PT' => 'pt-PT',
184
- 'ro_RO' => 'ro-RO',
185
- 'ru_RU' => 'ru-RU',
186
- 'sa_IN' => 'sa-IN',
187
- 'sd_PK' => 'sd-PK',
188
- 'si_LK' => 'si-LK',
189
- 'sk_SK' => 'sk-SK',
190
- 'sl_SI' => 'sl-SI',
191
- 'so_SO' => 'so-SO',
192
- 'sq' => 'sq-SQ',
193
- 'sr_RS' => 'sr-CS',
194
- 'su_ID' => 'su-ID',
195
- 'sv_SE' => 'sv-SE',
196
- 'sw' => 'sw-TZ',
197
- 'sw_TZ' => 'sw-TZ',
198
- 'ta_IN' => 'ta-IN',
199
- 'te' => 'te-IN',
200
- 'tg' => 'tg-TJ',
201
- 'th' => 'th-TH',
202
- 'th_TH' => 'th-TH',
203
- 'tir' => 'ti-ER',
204
- 'tl' => 'tl-PH',
205
- 'tr_TR' => 'tr-TR',
206
- 'ug_CN' => 'ug-CN',
207
- 'uk' => 'uk-UA',
208
- 'uk_UA' => 'uk-UA',
209
- 'ur' => 'ur-PK',
210
- 'ur_PK' => 'ur-PK',
211
- 'uz_UZ' => 'uz-UZ',
212
- 'vi' => 'vi-VN',
213
- 'vi_VN' => 'vi-VN',
214
- 'zh_CN' => 'zh-CN',
215
- 'zh_HK' => 'zh-HK',
216
- 'zh_TW' => 'zh-TW',
217
- 'zh_SG' => 'zh-SG',
218
  );
219
 
220
 
221
  /**
222
- * Verifies that a lingotek-locale (ie. es-ES) is an allowed
223
  * TMS locale.
224
  *
225
  * @param string $lingotek_locale
226
  * @return boolean
227
  */
228
- public static function is_allowed_tms_locale($lingotek_locale)
229
- {
230
- return isset(self::$lingotek_locales[$lingotek_locale]) || in_array($lingotek_locale, self::$lingotek_locales);
231
  }
232
 
233
  /**
@@ -277,11 +281,12 @@ class Lingotek {
277
  // loads the admin side of Polylang for the dashboard.
278
  if ( defined( 'DOING_AJAX' ) && DOING_AJAX && isset( $action ) && 'lingotek_language' === $action ) {
279
  define( 'PLL_AJAX_ON_FRONT', false );
280
-
281
  add_filter( 'pll_model', array( &$this, 'PLL_Admin_Model' ) );
282
  }
283
 
284
- spl_autoload_register( array( &$this, 'autoload' ) ); // autoload classes.
 
285
 
286
  // init.
287
  add_filter( 'pll_model', array( &$this, 'pll_model' ) );
@@ -325,94 +330,97 @@ class Lingotek {
325
  // If any update happened, inform the user and update the version.
326
  if ( $updatesHaveRun ) {
327
  update_option( 'lingotek_plugin_version', LINGOTEK_VERSION, false );
328
- add_action( 'admin_notices', function () {
329
- echo '<div class="notice notice-success is-dismissible">
 
 
330
  <p>' . __( 'Upgrades for the lingotek translation module have completed.', 'lingotek-translation' ) . '</p>
331
  </div>';
332
- } );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
333
  }
334
  }
335
 
336
- /**
337
- * Check if we need to run these updates.
338
- *
339
- * It will check that the installed version is newer than the db one, even if we
340
- * had skipped any version, and ensures we don't run any update if we already did.
341
- *
342
- * @param $versionUpdates
343
- * The version where these updates were introduced.
344
- * @return bool
345
- * true if needs to run, false otherwise
346
- *
347
- * @since 1.4.11
348
- */
349
- public function needs_to_run_updates($versionUpdates) {
350
- $db_version = get_option('lingotek_plugin_version');
351
- return (version_compare(LINGOTEK_VERSION, $versionUpdates, '>=') &&
352
- version_compare($versionUpdates, $db_version, '>'));
353
- }
354
-
355
- /**
356
- * As we already have the metas in the lingotek_custom_fields options, we can
357
- * remove them from the lingotek_content_type option.
358
- *
359
- * @since 1.4.11
360
- */
361
- public function update_1_4_11_for_removing_custom_fields_from_postTypes_settings() {
362
- $settings = get_option('lingotek_content_type');
363
- foreach ($settings as $postType => &$postTypeSettings) {
364
- unset($postTypeSettings['fields']['metas']);
365
- }
366
- update_option('lingotek_content_type', $settings, false);
367
- }
368
-
369
- /**
370
- * Set the lingotek_custom_fields option as not autoloaded.
371
- *
372
- * @since 1.4.11
373
- */
374
- public function update_1_4_11_for_removing_custom_fields_autoload() {
375
- $settings = get_option('lingotek_custom_fields');
376
- update_option('lingotek_custom_fields', 'fakeValueSoWeForceAutoloadToFalse', false);
377
- update_option('lingotek_custom_fields', $settings, false);
378
- }
379
-
380
- /**
381
- * Set the lingotek_community_resources option as not autoloaded.
382
- *
383
- * @since 1.4.11
384
- */
385
- public function update_1_4_11_for_removing_community_resources_autoload() {
386
- $settings = get_option('lingotek_community_resources');
387
- update_option('lingotek_community_resources', 'fakeValueSoWeForceAutoloadToFalse', false);
388
- update_option('lingotek_community_resources', $settings, false);
389
- }
390
-
391
- /**
392
- * Set the lingotek_custom_fields option as not autoloaded.
393
- *
394
- * @since 1.4.13
395
- */
396
- public function update_1_4_13_for_disabling_autoload_for_all_wpoptions()
397
- {
398
- $wpoptions = array(
399
- 'lingotek_base_url',
400
- 'lingotek_plugin_version',
401
- 'lingotek_community',
402
- 'lingotek_defaults',
403
- 'lingotek_profiles',
404
- 'lingotek_token',
405
- );
406
- foreach ($wpoptions as $wpoption) {
407
- $settings = get_option($wpoption);
408
- if ($wpoption !== false) {
409
- update_option($wpoption, 'fakeValueSoWeForceAutoloadToFalse', false);
410
- update_option($wpoption, $settings, false);
411
- }
412
- }
413
- }
414
-
415
- /**
416
  * Return the plugin slug.
417
  *
418
  * @since 0.1
@@ -434,7 +442,7 @@ class Lingotek {
434
 
435
  // If the single instance hasn't been set, set it now.
436
  if ( null === self::$instance ) {
437
- self::$instance = new self;
438
  }
439
 
440
  return self::$instance;
@@ -460,7 +468,7 @@ class Lingotek {
460
  'activate' === $what ? $this->_activate() : $this->_deactivate();
461
  }
462
  restore_current_blog();
463
- } // single blog.
464
  else {
465
  'activate' === $what ? $this->_activate() : $this->_deactivate();
466
  }
@@ -484,7 +492,8 @@ class Lingotek {
484
  global $polylang;
485
 
486
  if ( isset( $polylang ) ) {
487
- $polylang->model->clean_languages_cache(); // to add lingotek_locale property.
 
488
  }
489
 
490
  // default profiles.
@@ -495,6 +504,12 @@ class Lingotek {
495
  // for the end point for the Lingoteck callback in rewrite rules.
496
  // don't use flush_rewrite_rules at network activation. See #32471.
497
  delete_option( 'rewrite_rules' );
 
 
 
 
 
 
498
  }
499
 
500
  /**
@@ -506,7 +521,7 @@ class Lingotek {
506
  */
507
  public static function get_profiles() {
508
  $default_profiles = self::get_default_profiles();
509
- $profiles = get_option( 'lingotek_profiles' );
510
  if ( is_array( $profiles ) ) {
511
  $profiles = array_merge( $default_profiles, $profiles );
512
  } else {
@@ -515,9 +530,10 @@ class Lingotek {
515
 
516
  // localize canned profile names.
517
  foreach ( $profiles as $k => $v ) {
518
- if ( in_array( $k,array( 'automatic', 'manual', 'disabled' ), true ) ) {
519
  $profile_name = $profiles[ $k ]['name'];
520
- $profiles[ $k ]['name'] = __( $profile_name,'lingotek-translation' );// localize canned profile names.
 
521
  }
522
  }
523
 
@@ -572,7 +588,7 @@ class Lingotek {
572
  $class = self::convert_class_to_file( $class );
573
  foreach ( array( LINGOTEK_WORKFLOWS, LINGOTEK_INC, LINGOTEK_ADMIN_INC ) as $path ) {
574
  if ( file_exists( $file = "$path/$class.php" ) ) {
575
- require_once( $file );
576
  break;
577
  }
578
  }
@@ -620,24 +636,25 @@ class Lingotek {
620
  foreach ( $classes as $class ) {
621
  $method = "Lingotek_$class";
622
 
623
- add_filter( 'pll_' . strtolower( $class ) , array( &$this, $method ));
624
  }
625
 
626
  // add actions to posts, media and terms list.
627
  // no need to load this if there is no language yet.
628
  if ( $GLOBALS['polylang']->model->get_languages_list() ) {
629
- $this->post_actions = new Lingotek_Post_Actions();
630
- $this->term_actions = new Lingotek_Term_Actions();
631
  $this->string_actions = new Lingotek_String_actions();
632
- new Lingotek_Workflow_Factory(); // autoloads class.
 
633
  }
634
 
635
  $this->utilities = new Lingotek_Utilities();
636
- } // callback.
637
  elseif ( ! PLL_ADMIN && ! PLL_AJAX_ON_FRONT ) {
638
  $GLOBALS['wp']->add_query_var( 'lingotek' );
639
 
640
- $this->model = new Lingotek_Model();
641
  $this->callback = new Lingotek_Callback( $this->model );
642
  }
643
  }
@@ -673,10 +690,8 @@ class Lingotek {
673
 
674
  if ( ! defined( 'POLYLANG_VERSION' ) ) {
675
  add_action( 'all_admin_notices', array( &$this, 'pll_inactive_notice' ) );
676
-
677
  } elseif ( version_compare( POLYLANG_VERSION, LINGOTEK_MIN_PLL_VERSION, '<' ) ) {
678
  add_action( 'all_admin_notices', array( &$this, 'pll_old_notice' ) );
679
-
680
  } elseif ( isset( $GLOBALS['polylang'] ) && ! count( $GLOBALS['polylang']->model->get_languages_list() ) ) {
681
  self::create_first_language();
682
  }
@@ -691,20 +706,22 @@ class Lingotek {
691
  */
692
  public function pll_inactive_notice() {
693
  $action = 'install-plugin';
694
- $slug = 'polylang';
695
- $url = wp_nonce_url(
696
- add_query_arg(
697
- array(
698
- 'action' => $action,
699
- 'plugin' => $slug,
700
- ),
701
- admin_url( 'update.php' )
702
- ),
703
- $action . '_' . $slug
704
  );
705
  printf(
706
  '<div class="error" style="height:55px"><p style="font-size:1.5em">%s<a href="%s">%s</a></p></div>',
707
- esc_html( __( 'Lingotek Translation requires Polylang to work. ', 'lingotek-translation' ) ), esc_url( $url ), esc_html( __( 'Install Polylang', 'lingotek-translation' ) )
 
 
708
  );
709
  }
710
 
@@ -721,7 +738,7 @@ class Lingotek {
721
  '<div class="error"><p>%s</p></div>',
722
  sprintf(
723
  esc_html( __( 'Lingotek Translation requires Polylang %s to work. Please upgrade Polylang.', 'lingotek-translation' ) ),
724
- wp_kses( '<strong>' . LINGOTEK_MIN_PLL_VERSION . '</strong>' , $allowed_html )
725
  )
726
  );
727
  }
@@ -731,13 +748,12 @@ class Lingotek {
731
  *
732
  * @since 0.2
733
  */
734
- static protected function create_first_language() {
735
  global $polylang;
736
 
737
  $language;
738
- if (file_exists( PLL_ADMIN_INC . '/languages.php' ) )
739
- {
740
- include( PLL_ADMIN_INC . '/languages.php' );
741
  $locale = get_locale();
742
 
743
  // attempts to set the default language from the current locale.
@@ -747,21 +763,23 @@ class Lingotek {
747
  }
748
  }
749
  }
750
-
751
 
752
  // defaults to en_US.
753
  if ( empty( $language ) ) {
754
  $language = array( 'en', 'en_US', 'English' );
755
  }
756
 
757
- $pll_model = new PLL_Admin_Model( $polylang->options ); // need admin model.
758
- $pll_model->add_language(array(
759
- 'slug' => $language[0],
760
- 'locale' => $language[1],
761
- 'name' => $language[2],
762
- 'rtl' => isset( $language[3] ) ? 1 : 0,
763
- 'term_group' => 0,
764
- ));
 
 
 
765
  }
766
 
767
  /**
@@ -776,8 +794,10 @@ class Lingotek {
776
  public function pre_set_languages_list( $languages ) {
777
  foreach ( $languages as $key => $language ) {
778
  if ( is_object( $language ) ) {
779
- $languages[ $key ]->lingotek_locale = self::map_to_lingotek_locale( $language->locale ); // backward compatibility with Polylang < 1.7.3.
780
- } else { $languages[ $key ]['lingotek_locale'] = self::map_to_lingotek_locale( $language['locale'] );
 
 
781
  }
782
  }
783
 
@@ -800,16 +820,15 @@ class Lingotek {
800
  }
801
 
802
  /**
803
- * Converts the class name to the appropriate file name for class loading.
804
- *
805
- * @param string $class the class name.
806
  */
807
  public static function convert_class_to_file( $class ) {
808
  return str_replace( '_', '-', strtolower( substr( $class, 9 ) ) );
809
  }
810
 
811
  /**
812
- * Maps a WordPres locale to a Lingotek locale
813
  *
814
  * @since 0.3
815
  *
@@ -837,10 +856,10 @@ class Lingotek {
837
  }
838
 
839
  /**
840
- * Writes data to a log.
841
  *
842
- * @param multiple $data the data to be written.
843
- * @param string $label the label to identify the data.
844
  */
845
  public static function log( $data, $label = null ) {
846
  if ( self::$logging ) {
@@ -872,28 +891,27 @@ class Lingotek {
872
  ),
873
  array(
874
  'label' => __( 'Activate Account', 'lingotek-translation' ),
875
- 'link' => admin_url( 'admin.php?page=' . $this->plugin_slug . '_settings&connect=new' ),
876
  ),
877
  );
878
 
879
  $args = array(
880
- 'pointer' => 'lingotek-translation',
881
- 'id' => 'toplevel_page_lingotek-translation',
882
  'position' => array(
883
- 'edge' => 'bottom',
884
  'align' => 'left',
885
  ),
886
- 'width' => 380,
887
- 'title' => __( 'Congratulations!', 'lingotek-translation' ),
888
- 'content' => $content,
889
- 'buttons' => $buttons,
890
  );
891
 
892
  new Lingotek_Pointer( $args );
893
  }
894
 
895
- public function lingotek_professional_translation_pointer()
896
- {
897
  $content = __( 'Lingotek Professional Translation is now available!', 'lingotek-translation' );
898
 
899
  $buttons = array(
@@ -902,21 +920,21 @@ class Lingotek {
902
  ),
903
  array(
904
  'label' => __( 'Learn More', 'lingotek-translation' ),
905
- 'link' => admin_url( 'admin.php?page=lingotek-translation_tutorial&sm=content&tutorial=ltk-prof#ltk-prof-trans-header' ),
906
  ),
907
  );
908
 
909
  $args = array(
910
- 'pointer' => 'lingotek-professional-translation',
911
- 'id' => 'toplevel_page_lingotek-translation',
912
  'position' => array(
913
- 'edge' => 'bottom',
914
  'align' => 'left',
915
  ),
916
- 'width' => 380,
917
- 'title' => __( 'New Feature', 'lingotek-translation' ),
918
- 'content' => $content,
919
- 'buttons' => $buttons,
920
  );
921
 
922
  new Lingotek_Pointer( $args );
@@ -925,33 +943,32 @@ class Lingotek {
925
  public static function get_default_profiles() {
926
  $default_profiles = array();
927
 
928
- if (/**get_option('lingotek_automatic_enabled')*/ true) {
929
  $default_profiles['automatic'] = array(
930
- 'profile' => 'automatic',
931
- 'name' => __( 'Automatic', 'lingotek-translation' ),
932
- 'upload' => 'automatic',
933
- 'download' => 'automatic',
934
- );
935
  }
936
 
937
  $default_profiles['manual'] = array(
938
- 'profile' => 'manual',
939
- 'name' => __( 'Manual', 'lingotek-translation' ),
940
- 'upload' => 'manual',
941
- 'download' => 'manual',
942
- );
943
-
944
  $default_profiles['disabled'] = array(
945
- 'profile' => 'disabled',
946
- 'name' => __( 'Disabled', 'lingotek-translation' ),
947
- );
948
 
949
  return $default_profiles;
950
  }
951
- public static function mylog($message = '')
952
- {
953
- file_put_contents('php://stdout', "$message", FILE_APPEND);
954
- }
955
  }
956
 
957
  $GLOBALS['wp_lingotek'] = Lingotek::get_instance();
2
  /**
3
  Plugin name: Lingotek Translation
4
  Plugin URI: http://lingotek.com/wordpress#utm_source=wpadmin&utm_medium=plugin&utm_campaign=wplingotektranslationplugin
5
+ Version: 1.4.14
6
  Author: Lingotek and Frédéric Demarle
7
  Author uri: http://lingotek.com
8
  Description: Lingotek offers convenient cloud-based localization and translation.
16
  exit();
17
  }
18
 
19
+ // Plugin version (should match above meta).
20
+ define( 'LINGOTEK_VERSION', '1.4.14' );
21
  define( 'LINGOTEK_MIN_PLL_VERSION', '1.8' );
22
+ // Plugin name as known by WordPress.
23
+ define( 'LINGOTEK_BASENAME', plugin_basename( __FILE__ ) );
24
+ // plugin slug (should match above meta: Text Domain).
25
+ define( 'LINGOTEK_PLUGIN_SLUG', 'lingotek-translation' );
26
+ // our directory.
27
+ define( 'LINGOTEK_DIR', dirname( __FILE__ ) );
28
  define( 'LINGOTEK_INC', LINGOTEK_DIR . '/include' );
29
+ define( 'LINGOTEK_ADMIN_INC', LINGOTEK_DIR . '/admin' );
30
+ define( 'LINGOTEK_WORKFLOWS', LINGOTEK_ADMIN_INC . '/workflows' );
31
  define( 'LINGOTEK_URL', plugins_url( '', __FILE__ ) );
32
  define( 'BRIDGE_URL', 'https://marketplace.lingotek.com' );
33
 
34
  class Lingotek {
35
  /**
36
+ * Lingotek model.
37
  *
38
+ * @var object
39
  */
40
  public $model;
41
 
42
  /**
43
+ * Callback method
44
  *
45
+ * @var method
46
  */
47
  public $callback;
48
 
49
  /**
50
+ * Array to map Lingotek locales to WP locales.
51
+ * map as 'WP locale' => 'Lingotek locale'.
52
  *
53
  * TODO: update this list!!!!
54
+ *
55
+ * @var array
56
  */
57
  public static $lingotek_locales = array(
58
+ 'af' => 'af-ZA',
59
+ 'ak' => 'ak-GH',
60
+ 'am' => 'am-ET',
61
+ 'ar' => 'ar',
62
+ 'ar_AE' => 'ar-AE',
63
+ 'ar_AF' => 'ar-AF',
64
+ 'ar_BH' => 'ar-BH',
65
+ 'ar_DZ' => 'ar-DZ',
66
+ 'ar_EG' => 'ar-EG',
67
+ 'ar_IQ' => 'ar-IQ',
68
+ 'ar_JO' => 'ar-JO',
69
+ 'ar_LY' => 'ar-LY',
70
+ 'ar_MA' => 'ar-MA',
71
+ 'ar_MR' => 'ar-MR',
72
+ 'ar_OM' => 'ar-OM',
73
+ 'ar_SA' => 'ar-SA',
74
+ 'ar_SD' => 'ar-SD',
75
+ 'ar_SY' => 'ar-SY',
76
+ 'ar_TD' => 'ar-TD',
77
+ 'ar_TN' => 'ar-TN',
78
+ 'ar_UZ' => 'ar-UZ',
79
+ 'ar_YE' => 'ar-YE',
80
+ 'as' => 'as-IN',
81
+ 'az' => 'az-AZ',
82
+ 'ba' => 'ba-RU',
83
+ 'bel' => 'be-BY',
84
+ 'bg_BG' => 'bg-BG',
85
+ 'bn_BD' => 'bn-BD',
86
+ 'bo' => 'bo-CN',
87
+ 'bs_BA' => 'bs-BA',
88
+ 'ca' => 'ca-ES',
89
+ 'ca_ES' => 'ca-ES',
90
+ 'co' => 'co-FR',
91
+ 'cs_CZ' => 'cs-CZ',
92
+ 'cy' => 'cy-GB',
93
+ 'cy_GB' => 'cy-GB',
94
+ 'de_AT' => 'de-AT',
95
+ 'da_DK' => 'da-DK',
96
+ 'de_CH' => 'de-CH',
97
+ 'de_DE' => 'de-DE',
98
+ 'dv' => 'dv-MV',
99
+ 'el' => 'el-GR',
100
+ 'el_GR' => 'el-GR',
101
+ 'en_AU' => 'en-AU',
102
+ 'en_CA' => 'en-CA',
103
+ 'en_GB' => 'en-GB',
104
+ 'en_US' => 'en-US',
105
+ 'en_IE' => 'en-IE',
106
+ 'en_IN' => 'en-IN',
107
+ 'en_ZA' => 'en-ZA',
108
+ 'eo' => 'eo-FR',
109
+ 'es_419' => 'es-419',
110
+ 'es_AR' => 'es-AR',
111
+ 'es_BO' => 'es-BO',
112
+ 'es_CL' => 'es-CL',
113
+ 'es_CO' => 'es-CO',
114
+ 'es_ES' => 'es-ES',
115
+ 'es_MX' => 'es-MX',
116
+ 'es_PE' => 'es-PE',
117
+ 'es_PR' => 'es-PR',
118
+ 'es_VE' => 'es-VE',
119
+ 'es_HN' => 'es-HN',
120
+ 'es_CR' => 'es-CR',
121
+ 'es_CU' => 'es-CU',
122
+ 'es_DO' => 'es-DO',
123
+ 'es_EC' => 'es-EC',
124
+ 'es_GT' => 'es-GT',
125
+ 'es_NI' => 'es-NI',
126
+ 'es_PA' => 'es-PA',
127
+ 'es_PY' => 'es-PY',
128
+ 'es_SV' => 'es-SV',
129
+ 'es_UY' => 'es-UY',
130
+ 'es_US' => 'es-US',
131
+ 'et' => 'et-EE',
132
+ 'et_EE' => 'et-EE',
133
+ 'eu' => 'eu-ES',
134
+ 'fa_IR' => 'fa-IR',
135
+ 'fi' => 'fi-FI',
136
+ 'fi_FI' => 'fi-FI',
137
+ 'fr_FR' => 'fr-FR',
138
+ 'fr_BE' => 'fr-BE',
139
+ 'fr_CA' => 'fr-CA',
140
+ 'fr_CH' => 'fr-CH',
141
+ 'fr_US' => 'fr-US',
142
+ 'ga' => 'ga-IE',
143
+ 'gd' => 'gd-GB',
144
+ 'gl_ES' => 'gl-ES',
145
+ 'gn' => 'gn-BO',
146
  'haw_US' => 'haw-US',
147
+ 'he_IL' => 'he-IL',
148
+ 'hi_IN' => 'hi-IN',
149
+ 'hr' => 'hr-HR',
150
+ 'ht_HT' => 'ht-HT',
151
+ 'hu_HU' => 'hu-HU',
152
+ 'hy' => 'hy-AM',
153
+ 'id_ID' => 'id-ID',
154
+ 'is_IS' => 'is-IS',
155
+ 'it_IT' => 'it-IT',
156
+ 'it_CH' => 'it-CH',
157
+ 'ja' => 'ja-JP',
158
+ 'ja_JP' => 'ja-JP',
159
+ 'jv_ID' => 'jv-ID',
160
+ 'ka_GE' => 'ka-GE',
161
+ 'kin' => 'kin-RW',
162
+ 'kk' => 'kk-KZ',
163
+ 'kn' => 'kn-IN',
164
+ 'ko_KR' => 'ko-KR',
165
+ 'ky_KY' => 'ky-KG',
166
+ 'lb_LU' => 'lb-LU',
167
+ 'lo' => 'lo-LA',
168
+ 'lt_LT' => 'lt-LT',
169
+ 'lv' => 'lv-LV',
170
+ 'lv_LV' => 'lv-LV',
171
+ 'mg_MG' => 'mg-MG',
172
+ 'mk_MK' => 'mk-MK',
173
+ 'ml_IN' => 'ml-IN',
174
+ 'mn' => 'mn-MN',
175
+ 'mr' => 'mr-IN',
176
+ 'ms_MY' => 'ms-MY',
177
+ 'mt_MT' => 'mt-MT',
178
+ 'my_MM' => 'my-MM',
179
+ 'ne_NP' => 'ne-NP',
180
+ 'nl_BE' => 'nl-BE',
181
+ 'nl_NL' => 'nl-NL',
182
+ 'nn_NO' => 'nn-NO',
183
+ 'no_NO' => 'no-NO',
184
+ 'pa_IN' => 'pa-IN',
185
+ 'pl_PL' => 'pl-PL',
186
+ 'ps' => 'ps-AF',
187
+ 'pt_BR' => 'pt-BR',
188
+ 'pt_PT' => 'pt-PT',
189
+ 'ro_RO' => 'ro-RO',
190
+ 'ru_RU' => 'ru-RU',
191
+ 'sa_IN' => 'sa-IN',
192
+ 'sd_PK' => 'sd-PK',
193
+ 'si_LK' => 'si-LK',
194
+ 'sk_SK' => 'sk-SK',
195
+ 'sl_SI' => 'sl-SI',
196
+ 'so_SO' => 'so-SO',
197
+ 'sq' => 'sq-SQ',
198
+ 'sr_RS' => 'sr-CS',
199
+ 'su_ID' => 'su-ID',
200
+ 'sv_SE' => 'sv-SE',
201
+ 'sw' => 'sw-TZ',
202
+ 'sw_TZ' => 'sw-TZ',
203
+ 'ta_IN' => 'ta-IN',
204
+ 'te' => 'te-IN',
205
+ 'tg' => 'tg-TJ',
206
+ 'th' => 'th-TH',
207
+ 'th_TH' => 'th-TH',
208
+ 'tir' => 'ti-ER',
209
+ 'tl' => 'tl-PH',
210
+ 'tr_TR' => 'tr-TR',
211
+ 'ug_CN' => 'ug-CN',
212
+ 'uk' => 'uk-UA',
213
+ 'uk_UA' => 'uk-UA',
214
+ 'ur' => 'ur-PK',
215
+ 'ur_PK' => 'ur-PK',
216
+ 'uz_UZ' => 'uz-UZ',
217
+ 'vi' => 'vi-VN',
218
+ 'vi_VN' => 'vi-VN',
219
+ 'zh_CN' => 'zh-CN',
220
+ 'zh_HK' => 'zh-HK',
221
+ 'zh_TW' => 'zh-TW',
222
+ 'zh_SG' => 'zh-SG',
223
  );
224
 
225
 
226
  /**
227
+ * Verifies that a lingotek-locale (ie. es-ES) is an allowed
228
  * TMS locale.
229
  *
230
  * @param string $lingotek_locale
231
  * @return boolean
232
  */
233
+ public static function is_allowed_tms_locale( $lingotek_locale ) {
234
+ return isset( self::$lingotek_locales[ $lingotek_locale ] ) || in_array( $lingotek_locale, self::$lingotek_locales );
 
235
  }
236
 
237
  /**
281
  // loads the admin side of Polylang for the dashboard.
282
  if ( defined( 'DOING_AJAX' ) && DOING_AJAX && isset( $action ) && 'lingotek_language' === $action ) {
283
  define( 'PLL_AJAX_ON_FRONT', false );
284
+
285
  add_filter( 'pll_model', array( &$this, 'PLL_Admin_Model' ) );
286
  }
287
 
288
+ // Autoload classes.
289
+ spl_autoload_register( array( &$this, 'autoload' ) );
290
 
291
  // init.
292
  add_filter( 'pll_model', array( &$this, 'pll_model' ) );
330
  // If any update happened, inform the user and update the version.
331
  if ( $updatesHaveRun ) {
332
  update_option( 'lingotek_plugin_version', LINGOTEK_VERSION, false );
333
+ add_action(
334
+ 'admin_notices',
335
+ function () {
336
+ echo '<div class="notice notice-success is-dismissible">
337
  <p>' . __( 'Upgrades for the lingotek translation module have completed.', 'lingotek-translation' ) . '</p>
338
  </div>';
339
+ }
340
+ );
341
+ }
342
+ }
343
+
344
+ /**
345
+ * Check if we need to run these updates.
346
+ *
347
+ * It will check that the installed version is newer than the db one, even if we
348
+ * had skipped any version, and ensures we don't run any update if we already did.
349
+ *
350
+ * @param $versionUpdates
351
+ * The version where these updates were introduced.
352
+ * @return bool
353
+ * true if needs to run, false otherwise
354
+ *
355
+ * @since 1.4.11
356
+ */
357
+ public function needs_to_run_updates( $versionUpdates ) {
358
+ $db_version = get_option( 'lingotek_plugin_version' );
359
+ return ( $db_version !== false &&
360
+ version_compare( LINGOTEK_VERSION, $versionUpdates, '>=' ) &&
361
+ version_compare( $versionUpdates, $db_version, '>' ) );
362
+ }
363
+
364
+ /**
365
+ * As we already have the metas in the lingotek_custom_fields options, we can
366
+ * remove them from the lingotek_content_type option.
367
+ *
368
+ * @since 1.4.11
369
+ */
370
+ public function update_1_4_11_for_removing_custom_fields_from_postTypes_settings() {
371
+ $settings = get_option( 'lingotek_content_type' );
372
+ foreach ( $settings as $postType => &$postTypeSettings ) {
373
+ unset( $postTypeSettings['fields']['metas'] );
374
+ }
375
+ update_option( 'lingotek_content_type', $settings, false );
376
+ }
377
+
378
+ /**
379
+ * Set the lingotek_custom_fields option as not autoloaded.
380
+ *
381
+ * @since 1.4.11
382
+ */
383
+ public function update_1_4_11_for_removing_custom_fields_autoload() {
384
+ $settings = get_option( 'lingotek_custom_fields' );
385
+ update_option( 'lingotek_custom_fields', 'fakeValueSoWeForceAutoloadToFalse', false );
386
+ update_option( 'lingotek_custom_fields', $settings, false );
387
+ }
388
+
389
+ /**
390
+ * Set the lingotek_community_resources option as not autoloaded.
391
+ *
392
+ * @since 1.4.11
393
+ */
394
+ public function update_1_4_11_for_removing_community_resources_autoload() {
395
+ $settings = get_option( 'lingotek_community_resources' );
396
+ update_option( 'lingotek_community_resources', 'fakeValueSoWeForceAutoloadToFalse', false );
397
+ update_option( 'lingotek_community_resources', $settings, false );
398
+ }
399
+
400
+ /**
401
+ * Set the lingotek_custom_fields option as not autoloaded.
402
+ *
403
+ * @since 1.4.13
404
+ */
405
+ public function update_1_4_13_for_disabling_autoload_for_all_wpoptions() {
406
+ $wpoptions = array(
407
+ 'lingotek_base_url',
408
+ 'lingotek_plugin_version',
409
+ 'lingotek_community',
410
+ 'lingotek_defaults',
411
+ 'lingotek_profiles',
412
+ 'lingotek_token',
413
+ );
414
+ foreach ( $wpoptions as $wpoption ) {
415
+ $settings = get_option( $wpoption );
416
+ if ( $wpoption !== false ) {
417
+ update_option( $wpoption, 'fakeValueSoWeForceAutoloadToFalse', false );
418
+ update_option( $wpoption, $settings, false );
419
+ }
420
  }
421
  }
422
 
423
+ /**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
424
  * Return the plugin slug.
425
  *
426
  * @since 0.1
442
 
443
  // If the single instance hasn't been set, set it now.
444
  if ( null === self::$instance ) {
445
+ self::$instance = new self();
446
  }
447
 
448
  return self::$instance;
468
  'activate' === $what ? $this->_activate() : $this->_deactivate();
469
  }
470
  restore_current_blog();
471
+ } //end if
472
  else {
473
  'activate' === $what ? $this->_activate() : $this->_deactivate();
474
  }
492
  global $polylang;
493
 
494
  if ( isset( $polylang ) ) {
495
+ // To add lingotek_locale property.
496
+ $polylang->model->clean_languages_cache();
497
  }
498
 
499
  // default profiles.
504
  // for the end point for the Lingoteck callback in rewrite rules.
505
  // don't use flush_rewrite_rules at network activation. See #32471.
506
  delete_option( 'rewrite_rules' );
507
+
508
+ // Update the option for the installed version if it's the first time is activated,
509
+ // so updates are not attempted to run when they shouldn't.
510
+ if ( ! get_option( 'lingotek_plugin_version', false ) ) {
511
+ update_option( 'lingotek_plugin_version', LINGOTEK_VERSION );
512
+ }
513
  }
514
 
515
  /**
521
  */
522
  public static function get_profiles() {
523
  $default_profiles = self::get_default_profiles();
524
+ $profiles = get_option( 'lingotek_profiles' );
525
  if ( is_array( $profiles ) ) {
526
  $profiles = array_merge( $default_profiles, $profiles );
527
  } else {
530
 
531
  // localize canned profile names.
532
  foreach ( $profiles as $k => $v ) {
533
+ if ( in_array( $k, array( 'automatic', 'manual', 'disabled' ), true ) ) {
534
  $profile_name = $profiles[ $k ]['name'];
535
+ // Localize canned profile names.
536
+ $profiles[ $k ]['name'] = __( $profile_name, 'lingotek-translation' );
537
  }
538
  }
539
 
588
  $class = self::convert_class_to_file( $class );
589
  foreach ( array( LINGOTEK_WORKFLOWS, LINGOTEK_INC, LINGOTEK_ADMIN_INC ) as $path ) {
590
  if ( file_exists( $file = "$path/$class.php" ) ) {
591
+ require_once $file;
592
  break;
593
  }
594
  }
636
  foreach ( $classes as $class ) {
637
  $method = "Lingotek_$class";
638
 
639
+ add_filter( 'pll_' . strtolower( $class ), array( &$this, $method ) );
640
  }
641
 
642
  // add actions to posts, media and terms list.
643
  // no need to load this if there is no language yet.
644
  if ( $GLOBALS['polylang']->model->get_languages_list() ) {
645
+ $this->post_actions = new Lingotek_Post_Actions();
646
+ $this->term_actions = new Lingotek_Term_Actions();
647
  $this->string_actions = new Lingotek_String_actions();
648
+ // Autoloads class.
649
+ new Lingotek_Workflow_Factory();
650
  }
651
 
652
  $this->utilities = new Lingotek_Utilities();
653
+ } //end if
654
  elseif ( ! PLL_ADMIN && ! PLL_AJAX_ON_FRONT ) {
655
  $GLOBALS['wp']->add_query_var( 'lingotek' );
656
 
657
+ $this->model = new Lingotek_Model();
658
  $this->callback = new Lingotek_Callback( $this->model );
659
  }
660
  }
690
 
691
  if ( ! defined( 'POLYLANG_VERSION' ) ) {
692
  add_action( 'all_admin_notices', array( &$this, 'pll_inactive_notice' ) );
 
693
  } elseif ( version_compare( POLYLANG_VERSION, LINGOTEK_MIN_PLL_VERSION, '<' ) ) {
694
  add_action( 'all_admin_notices', array( &$this, 'pll_old_notice' ) );
 
695
  } elseif ( isset( $GLOBALS['polylang'] ) && ! count( $GLOBALS['polylang']->model->get_languages_list() ) ) {
696
  self::create_first_language();
697
  }
706
  */
707
  public function pll_inactive_notice() {
708
  $action = 'install-plugin';
709
+ $slug = 'polylang';
710
+ $url = wp_nonce_url(
711
+ add_query_arg(
712
+ array(
713
+ 'action' => $action,
714
+ 'plugin' => $slug,
715
+ ),
716
+ admin_url( 'update.php' )
717
+ ),
718
+ $action . '_' . $slug
719
  );
720
  printf(
721
  '<div class="error" style="height:55px"><p style="font-size:1.5em">%s<a href="%s">%s</a></p></div>',
722
+ esc_html( __( 'Lingotek Translation requires Polylang to work. ', 'lingotek-translation' ) ),
723
+ esc_url( $url ),
724
+ esc_html( __( 'Install Polylang', 'lingotek-translation' ) )
725
  );
726
  }
727
 
738
  '<div class="error"><p>%s</p></div>',
739
  sprintf(
740
  esc_html( __( 'Lingotek Translation requires Polylang %s to work. Please upgrade Polylang.', 'lingotek-translation' ) ),
741
+ wp_kses( '<strong>' . LINGOTEK_MIN_PLL_VERSION . '</strong>', $allowed_html )
742
  )
743
  );
744
  }
748
  *
749
  * @since 0.2
750
  */
751
+ protected static function create_first_language() {
752
  global $polylang;
753
 
754
  $language;
755
+ if ( file_exists( PLL_ADMIN_INC . '/languages.php' ) ) {
756
+ include PLL_ADMIN_INC . '/languages.php';
 
757
  $locale = get_locale();
758
 
759
  // attempts to set the default language from the current locale.
763
  }
764
  }
765
  }
 
766
 
767
  // defaults to en_US.
768
  if ( empty( $language ) ) {
769
  $language = array( 'en', 'en_US', 'English' );
770
  }
771
 
772
+ // Need admin model.
773
+ $pll_model = new PLL_Admin_Model( $polylang->options );
774
+ $pll_model->add_language(
775
+ array(
776
+ 'slug' => $language[0],
777
+ 'locale' => $language[1],
778
+ 'name' => $language[2],
779
+ 'rtl' => isset( $language[3] ) ? 1 : 0,
780
+ 'term_group' => 0,
781
+ )
782
+ );
783
  }
784
 
785
  /**
794
  public function pre_set_languages_list( $languages ) {
795
  foreach ( $languages as $key => $language ) {
796
  if ( is_object( $language ) ) {
797
+ // Backward compatibility with Polylang < 1.7.3.
798
+ $languages[ $key ]->lingotek_locale = self::map_to_lingotek_locale( $language->locale );
799
+ } else {
800
+ $languages[ $key ]['lingotek_locale'] = self::map_to_lingotek_locale( $language['locale'] );
801
  }
802
  }
803
 
820
  }
821
 
822
  /**
823
+ * Converts the class name to the appropriate file name for class loading.
824
+ * @param string $class the class name.
 
825
  */
826
  public static function convert_class_to_file( $class ) {
827
  return str_replace( '_', '-', strtolower( substr( $class, 9 ) ) );
828
  }
829
 
830
  /**
831
+ * Maps a WordPress locale to a Lingotek locale
832
  *
833
  * @since 0.3
834
  *
856
  }
857
 
858
  /**
859
+ * Writes data to a log.
860
  *
861
+ * @param multiple $data the data to be written.
862
+ * @param string $label the label to identify the data.
863
  */
864
  public static function log( $data, $label = null ) {
865
  if ( self::$logging ) {
891
  ),
892
  array(
893
  'label' => __( 'Activate Account', 'lingotek-translation' ),
894
+ 'link' => admin_url( 'admin.php?page=' . $this->plugin_slug . '_settings&connect=new' ),
895
  ),
896
  );
897
 
898
  $args = array(
899
+ 'pointer' => 'lingotek-translation',
900
+ 'id' => 'toplevel_page_lingotek-translation',
901
  'position' => array(
902
+ 'edge' => 'bottom',
903
  'align' => 'left',
904
  ),
905
+ 'width' => 380,
906
+ 'title' => __( 'Congratulations!', 'lingotek-translation' ),
907
+ 'content' => $content,
908
+ 'buttons' => $buttons,
909
  );
910
 
911
  new Lingotek_Pointer( $args );
912
  }
913
 
914
+ public function lingotek_professional_translation_pointer() {
 
915
  $content = __( 'Lingotek Professional Translation is now available!', 'lingotek-translation' );
916
 
917
  $buttons = array(
920
  ),
921
  array(
922
  'label' => __( 'Learn More', 'lingotek-translation' ),
923
+ 'link' => admin_url( 'admin.php?page=lingotek-translation_tutorial&sm=content&tutorial=ltk-prof#ltk-prof-trans-header' ),
924
  ),
925
  );
926
 
927
  $args = array(
928
+ 'pointer' => 'lingotek-professional-translation',
929
+ 'id' => 'toplevel_page_lingotek-translation',
930
  'position' => array(
931
+ 'edge' => 'bottom',
932
  'align' => 'left',
933
  ),
934
+ 'width' => 380,
935
+ 'title' => __( 'New Feature', 'lingotek-translation' ),
936
+ 'content' => $content,
937
+ 'buttons' => $buttons,
938
  );
939
 
940
  new Lingotek_Pointer( $args );
943
  public static function get_default_profiles() {
944
  $default_profiles = array();
945
 
946
+ if ( /**get_option('lingotek_automatic_enabled')*/ true ) {
947
  $default_profiles['automatic'] = array(
948
+ 'profile' => 'automatic',
949
+ 'name' => __( 'Automatic', 'lingotek-translation' ),
950
+ 'upload' => 'automatic',
951
+ 'download' => 'automatic',
952
+ );
953
  }
954
 
955
  $default_profiles['manual'] = array(
956
+ 'profile' => 'manual',
957
+ 'name' => __( 'Manual', 'lingotek-translation' ),
958
+ 'upload' => 'manual',
959
+ 'download' => 'manual',
960
+ );
961
+
962
  $default_profiles['disabled'] = array(
963
+ 'profile' => 'disabled',
964
+ 'name' => __( 'Disabled', 'lingotek-translation' ),
965
+ );
966
 
967
  return $default_profiles;
968
  }
969
+ public static function mylog( $message = '' ) {
970
+ file_put_contents( 'php://stdout', "$message", FILE_APPEND );
971
+ }
 
972
  }
973
 
974
  $GLOBALS['wp_lingotek'] = Lingotek::get_instance();
phpcs.xml ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <ruleset name="WordPress Coding Standards based custom ruleset for your plugin">
3
+ <description>Generally-applicable sniffs for WordPress plugins.</description>
4
+
5
+ <!-- What to scan -->
6
+ <file>.</file>
7
+ <exclude-pattern>/vendor/</exclude-pattern>
8
+ <exclude-pattern>/node_modules/</exclude-pattern>
9
+
10
+ <!-- How to scan -->
11
+ <!-- Usage instructions: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Usage -->
12
+ <!-- Annotated ruleset: https://github.com/squizlabs/PHP_CodeSniffer/wiki/Annotated-ruleset.xml -->
13
+ <arg value="sp"/> <!-- Show sniff and progress -->
14
+ <arg name="basepath" value="./"/><!-- Strip the file paths down to the relevant bit -->
15
+ <arg name="colors"/>
16
+ <arg name="extensions" value="php"/>
17
+ <arg name="parallel" value="8"/><!-- Enables parallel processing when available for faster results. -->
18
+
19
+ <!-- Rules: Check PHP version compatibility -->
20
+ <!-- https://github.com/PHPCompatibility/PHPCompatibility#sniffing-your-code-for-compatibility-with-specific-php-versions -->
21
+ <config name="testVersion" value="5.6-"/>
22
+ <!-- https://github.com/PHPCompatibility/PHPCompatibilityWP -->
23
+ <rule ref="PHPCompatibilityWP"/>
24
+
25
+ <!-- Rules: WordPress Coding Standards -->
26
+ <!-- https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards -->
27
+ <!-- https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/wiki/Customizable-sniff-properties -->
28
+ <config name="minimum_supported_wp_version" value="4.6"/>
29
+ <rule ref="WordPress"/>
30
+ <rule ref="WordPress.NamingConventions.PrefixAllGlobals">
31
+ <properties>
32
+ <!-- Value: replace the function, class, and variable prefixes used. Separate multiple prefixes with a comma. -->
33
+ <property name="prefixes" type="array" value="lingotek"/>
34
+ </properties>
35
+ </rule>
36
+ <rule ref="WordPress.WP.I18n">
37
+ <properties>
38
+ <!-- Value: replace the text domain used. -->
39
+ <property name="text_domain" type="array" value="lingotek-translation"/>
40
+ </properties>
41
+ </rule>
42
+ <rule ref="WordPress.WhiteSpace.ControlStructureSpacing">
43
+ <properties>
44
+ <property name="blank_line_check" value="true"/>
45
+ </properties>
46
+ </rule>
47
+
48
+ <!-- ltk: Starting Lingotek customizations. We should include these rules, but let's go step by step. -->
49
+ <rule ref="Generic.Commenting">
50
+ <exclude name="Generic.Commenting.DocComment.ShortNotCapital"/>
51
+ </rule>
52
+ <rule ref="Squiz.Commenting">
53
+ <exclude name="Squiz.Commenting.FunctionComment.Missing" />
54
+ <exclude name="Squiz.Commenting.InlineComment" />
55
+ <exclude name="Squiz.Commenting.FunctionComment.MissingParamComment" />
56
+ <exclude name="Squiz.Commenting.FileComment.Missing"/>
57
+ <exclude name="Squiz.Commenting.FunctionComment.MissingParamTag"/>
58
+ </rule>
59
+ <rule ref="WordPress.Files.FileName">
60
+ <exclude name="WordPress.Files.FileName.InvalidClassFileName" />
61
+ </rule>
62
+ <rule ref="WordPress.NamingConventions.PrefixAllGlobals">
63
+ <exclude name="WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound" />
64
+ <exclude name="WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound" />
65
+ </rule>
66
+ <!-- ltk: These are dangerous to change, as involve method renaming.' -->
67
+ <rule ref="PSR2.Methods.MethodDeclaration">
68
+ <exclude name="PSR2.Methods.MethodDeclaration.Underscore"/>
69
+ </rule>
70
+ <rule ref="WordPress.NamingConventions.ValidFunctionName">
71
+ <exclude name="WordPress.NamingConventions.ValidFunctionName" />
72
+ </rule>
73
+ <rule ref="WordPress.PHP.DisallowShortTernary.Found">
74
+ <type>warning</type>
75
+ </rule>
76
+ <rule ref="WordPress.PHP.StrictComparisons.LooseComparison">
77
+ <type>warning</type>
78
+ </rule>
79
+ </ruleset>
phpunit.xml ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <phpunit
3
+ bootstrap="tests/bootstrap.php"
4
+ backupGlobals="false"
5
+ colors="true"
6
+ convertErrorsToExceptions="true"
7
+ convertNoticesToExceptions="true"
8
+ convertWarningsToExceptions="true"
9
+ >
10
+ <testsuites>
11
+ <testsuite name="integration">
12
+ <directory prefix="test-" suffix=".php">./tests/</directory>
13
+ </testsuite>
14
+ </testsuites>
15
+ </phpunit>
readme.txt CHANGED
@@ -3,8 +3,8 @@ Contributors: chouby, smithworx, erichie, robertdhanna, ipoulsen, elliothanna, l
3
  Donate link: http://lingotek.com/
4
  Tags: automation, bilingual, international, language, Lingotek, localization, multilanguage, multilingual, translate, translation
5
  Requires at least: 3.8
6
- Tested up to: 5.6
7
- Stable tag: 1.4.13
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -122,6 +122,9 @@ For more, visit the [Lingotek documentation site](https://lingotek.atlassian.net
122
  5. The Lingotek Translation plugin provides the ability to Copy, Translate, and Ignore each specific custom field. Our plugin supports Wordpress custom fields and advanced custom fields.
123
 
124
  == Changelog ==
 
 
 
125
  = 1.4.13 (2021-6-14) =
126
  * Updated code base to be compatible with PHP 8
127
  * Updated cancel action behavior to be more consistent.
3
  Donate link: http://lingotek.com/
4
  Tags: automation, bilingual, international, language, Lingotek, localization, multilanguage, multilingual, translate, translation
5
  Requires at least: 3.8
6
+ Tested up to: 5.7
7
+ Stable tag: 1.4.14
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
122
  5. The Lingotek Translation plugin provides the ability to Copy, Translate, and Ignore each specific custom field. Our plugin supports Wordpress custom fields and advanced custom fields.
123
 
124
  == Changelog ==
125
+ = 1.4.14 (2021-07-07) =
126
+ * Fixed WordPress: consume the download_interim_translation callback
127
+
128
  = 1.4.13 (2021-6-14) =
129
  * Updated code base to be compatible with PHP 8
130
  * Updated cancel action behavior to be more consistent.
tests/README.md ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Devs Quality Assurance
2
+
3
+ ## PHPUnit Setup
4
+
5
+ Note: my setup is based on roots/bedrock, not a basic WordPress, so instructions might not be 100% accurate.
6
+
7
+ Warning: This runs on the host, not on ddev.
8
+
9
+ _TODO_: Adapt this so it runs on ddev.
10
+
11
+ _TODO_: Edit the release process. We don't want the /tests or /bin folder at all in the releases.
12
+
13
+
14
+ ```
15
+ composer global require phpunit/phpunit:^7.3
16
+
17
+ bash bin/install-wp-tests.sh wordpress_test root 'mysql-pwd' localhost latest
18
+ ```
19
+
20
+ ## Running the tests
21
+
22
+ In a bedrocks setup is
23
+ ```
24
+ ../../../../vendor/bin/phpunit
25
+ ```
26
+
27
+ # PHPCS
28
+
29
+ ## Setup
30
+
31
+ ```
32
+ composer global require wp-coding-standards/wpcs
33
+ composer global require phpcompatibility/php-compatibility
34
+ composer global require phpcompatibility/phpcompatibility-paragonie
35
+ composer global require phpcompatibility/phpcompatibility-wp
36
+ phpcs --config-set installed_paths $HOME/.composer/vendor/wp-coding-standards/wpcs,$HOME/.composer/vendor/phpcompatibility/php-compatibility,$HOME/.composer/vendor/phpcompatibility/phpcompatibility-paragonie,$HOME/.composer/vendor/phpcompatibility/phpcompatibility-wp
37
+ ```
38
+
39
+ ## Running checks
40
+
41
+ Just run `phpcs` from the plugin folder.
42
+
43
+ ## Future work
44
+
45
+ Some rules from the _WP Standards_ have been disabled, as they involve renaming functions, files, etc that might
46
+ be dangerous.
tests/bootstrap.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PHPUnit bootstrap file.
4
+ *
5
+ * @package Lingotek_Translation
6
+ */
7
+
8
+ if ( PHP_MAJOR_VERSION >= 8 ) {
9
+ echo 'The scaffolded tests cannot currently be run on PHP 8.0+. See https://github.com/wp-cli/scaffold-command/issues/285' . PHP_EOL; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
10
+ exit( 1 );
11
+ }
12
+
13
+ $_tests_dir = getenv( 'WP_TESTS_DIR' );
14
+
15
+ if ( ! $_tests_dir ) {
16
+ $_tests_dir = rtrim( sys_get_temp_dir(), '/\\' ) . '/wordpress-tests-lib';
17
+ }
18
+
19
+ if ( ! file_exists( "{$_tests_dir}/includes/functions.php" ) ) {
20
+ echo "Could not find {$_tests_dir}/includes/functions.php, have you run bin/install-wp-tests.sh ?" . PHP_EOL; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
21
+ exit( 1 );
22
+ }
23
+
24
+ // Give access to tests_add_filter() function.
25
+ require_once "{$_tests_dir}/includes/functions.php";
26
+
27
+ /**
28
+ * Manually load the plugin being tested.
29
+ */
30
+ function _manually_load_plugin() {
31
+ require dirname( dirname( __FILE__ ) ) . '/lingotek.php';
32
+ }
33
+
34
+ tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' );
35
+
36
+ $GLOBALS['wp_tests_options'] = array(
37
+ 'active_plugins' => array( 'lingotek-translation' ),
38
+ );
39
+
40
+ // Start up the WP testing environment.
41
+ require "{$_tests_dir}/includes/bootstrap.php";
42
+
tests/test-lingotek-installation.php ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class LingotekInstallationTest
4
+ *
5
+ * @package Lingotek_Translation
6
+ */
7
+
8
+ /**
9
+ * Sample test case.
10
+ */
11
+ class LingotekInstallationTest extends WP_UnitTestCase {
12
+
13
+ /**
14
+ * Tests the initial options are set on activation.
15
+ *
16
+ * @test
17
+ * @dataProvider getInitialOptions
18
+ *
19
+ * @param string $option The option name.
20
+ * @param mixed $value The expected value.
21
+ */
22
+ public function InitialOptionsAreSet( $option, $value ) {
23
+ $this->ltk = new Lingotek();
24
+ $this->ltk->activate();
25
+
26
+ $this->assertSame( $value, get_option( $option ) );
27
+ }
28
+
29
+ /**
30
+ * Tests the initial profiles are created on activation.
31
+ *
32
+ * @test
33
+ */
34
+ public function InitialProfilesAreCreated() {
35
+ $this->ltk = new Lingotek();
36
+ $this->ltk->activate();
37
+
38
+ $profiles = get_option( 'lingotek_profiles', false );
39
+
40
+ $this->assertEquals( 3, count( $profiles ) );
41
+ $this->assertTrue( isset( $profiles['automatic'] ) );
42
+ $this->assertTrue( isset( $profiles['manual'] ) );
43
+ $this->assertTrue( isset( $profiles['disabled'] ) );
44
+ }
45
+
46
+ /**
47
+ * Data provider for initial options values.
48
+ *
49
+ * @see ::InitialOptionsAreSet
50
+ */
51
+ public function getInitialOptions() {
52
+ yield 'lingotek_plugin_version' => array( 'lingotek_plugin_version', LINGOTEK_VERSION );
53
+ yield 'lingotek_profiles' => array(
54
+ 'lingotek_profiles',
55
+ array(
56
+ 'automatic' => array(
57
+ 'profile' => 'automatic',
58
+ 'name' => 'Automatic',
59
+ 'upload' => 'automatic',
60
+ 'download' => 'automatic',
61
+ ),
62
+ 'manual' => array(
63
+ 'profile' => 'manual',
64
+ 'name' => 'Manual',
65
+ 'upload' => 'manual',
66
+ 'download' => 'manual',
67
+ ),
68
+ 'disabled' => array(
69
+ 'profile' => 'disabled',
70
+ 'name' => 'Disabled',
71
+ ),
72
+ ),
73
+ );
74
+ }
75
+
76
+ /**
77
+ * Helper function for outputting data while running tests (debug purposes).
78
+ *
79
+ * @param mixed $data The data to be logged.
80
+ */
81
+ public function log( $data ) {
82
+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_var_export,WordPress.WP.AlternativeFunctions.file_system_read_fwrite
83
+ fwrite( STDERR, var_export( $data, true ) );
84
+ }
85
+
86
+ }
uninstall.php CHANGED
@@ -1,8 +1,9 @@
1
  <?php
2
 
3
  //if uninstall not called from WordPress exit
4
- if (!defined('WP_UNINSTALL_PLUGIN'))
5
- exit();
 
6
 
7
  class Lingotek_Uninstall {
8
 
@@ -15,15 +16,15 @@ class Lingotek_Uninstall {
15
  global $wpdb;
16
 
17
  // check if it is a multisite uninstall - if so, run the uninstall function for each blog id
18
- if (is_multisite()) {
19
- foreach ($wpdb->get_col("SELECT blog_id FROM $wpdb->blogs") as $blog_id) {
20
- switch_to_blog($blog_id);
21
  $this->uninstall();
22
  }
23
  restore_current_blog();
24
- }
25
- else
26
  $this->uninstall();
 
27
  }
28
 
29
  /*
@@ -34,15 +35,15 @@ class Lingotek_Uninstall {
34
  * @since 0.1
35
  */
36
  function uninstall() {
37
- delete_option('lingotek_prefs');
38
- delete_option('lingotek_content_type');
39
- delete_option('lingotek_community');
40
- delete_option('lingotek_defaults');
41
- delete_option('lingotek_profiles');
42
- delete_option('lingotek_token');
43
- delete_option('lingotek_community_resources');
44
- delete_option('lingotek_custom_fields');
45
- delete_option('lingotek_log_errors');
46
  }
47
  }
48
 
1
  <?php
2
 
3
  //if uninstall not called from WordPress exit
4
+ if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
5
+ exit();
6
+ }
7
 
8
  class Lingotek_Uninstall {
9
 
16
  global $wpdb;
17
 
18
  // check if it is a multisite uninstall - if so, run the uninstall function for each blog id
19
+ if ( is_multisite() ) {
20
+ foreach ( $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs" ) as $blog_id ) {
21
+ switch_to_blog( $blog_id );
22
  $this->uninstall();
23
  }
24
  restore_current_blog();
25
+ } else {
 
26
  $this->uninstall();
27
+ }
28
  }
29
 
30
  /*
35
  * @since 0.1
36
  */
37
  function uninstall() {
38
+ delete_option( 'lingotek_prefs' );
39
+ delete_option( 'lingotek_content_type' );
40
+ delete_option( 'lingotek_community' );
41
+ delete_option( 'lingotek_defaults' );
42
+ delete_option( 'lingotek_profiles' );
43
+ delete_option( 'lingotek_token' );
44
+ delete_option( 'lingotek_community_resources' );
45
+ delete_option( 'lingotek_custom_fields' );
46
+ delete_option( 'lingotek_log_errors' );
47
  }
48
  }
49