Lingotek Translation - Version 1.2.7

Version Description

(2017-4-14) =

  • Added Lingotek bulk actions to custom content types
  • Fixed incorrect number display on the Translation Dashboard when content was disabled for translation
  • Fixed a bug that created empty content if trying to download translations before they were finished
  • Fixed the String Groups page
  • Code refactoring to meet WordPress coding standards
Download this release

Release Info

Developer erichie
Plugin Icon 128x128 Lingotek Translation
Version 1.2.7
Comparing to
See all releases

Code changes from version 1.2.6 to 1.2.7

admin/actions.php CHANGED
@@ -1,108 +1,141 @@
1
  <?php
2
 
3
- /*
4
  * Base class to add row and bulk actions to posts, media and terms list
5
  * Bulk actions management is inspired by http://www.foxrunsoftware.net/articles/wordpress/add-custom-bulk-action/
6
  *
7
  * @since 0.2
8
  */
9
  abstract class Lingotek_Actions {
10
- public $pllm, $lgtm; // Polylang and Lingotek models
11
- public $type; // *must* be defined in child class: 'post' or 'term'
12
- public static $actions, $icons, $confirm_message;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
- /*
15
  * Constructor
16
  *
17
  * @since 0.2
18
  */
19
- public function __construct($type) {
20
- // confirm message
21
- self::$confirm_message = sprintf(' onclick = "return confirm(\'%s\');"', __('You are about to overwrite existing translations. Are you sure?', 'lingotek-translation'));
22
 
23
- // row actions
24
  self::$actions = array(
25
  'upload' => array(
26
- 'action' => __('Upload to Lingotek', 'lingotek-translation'),
27
- 'progress' => __('Uploading...', 'lingotek-translation'),
28
- 'description' => __('Upload this item to Lingotek TMS', 'lingotek-translation' ),
29
  ),
30
 
31
  'request' => array(
32
- 'action' => __('Request translations', 'lingotek-translation'),
33
- 'progress' => __('Requesting translations...', 'lingotek-translation'),
34
- 'description' => __('Request translations of this item to Lingotek TMS', 'lingotek-translation' ),
35
  ),
36
 
37
  'status' => array(
38
- 'action' => __('Update translations status', 'lingotek-translation'),
39
- 'progress' => __('Updating translations status...', 'lingotek-translation'),
40
- 'description' => __('Update translations status of this item in Lingotek TMS', 'lingotek-translation' ),
41
  ),
42
 
43
  'download' => array(
44
- 'action' => __('Download translations', 'lingotek-translation'),
45
- 'progress' => __('Downloading translations...', 'lingotek-translation'),
46
- 'description' => __('Download translations of this item from Lingotek TMS', 'lingotek-translation' ),
47
  ),
48
 
49
  'delete' => array(
50
- 'action' => __('Disassociate translations', 'lingotek-translation'),
51
- 'progress' => __('Disassociating translations...', 'lingotek-translation'),
52
- 'description' => __('Disassociate the translations of this item from Lingotek TMS', 'lingotek-translation' ),
53
  ),
54
  );
55
 
56
  // action icons
57
  self::$icons = array(
58
  'upload' => array(
59
- 'title' => __('Upload Now', 'lingotek-translation'),
60
- 'icon' => 'upload'
61
  ),
62
 
63
  'importing' => array(
64
- 'title' => __('Importing source', 'lingotek-translation'),
65
- 'icon' => 'clock'
66
  ),
67
 
68
  'uploaded' => array(
69
- 'title' => __('Source uploaded', 'lingotek-translation'),
70
- 'icon' => 'yes'
71
  ),
72
 
73
  'request' => array(
74
- 'title' => __('Request a translation', 'lingotek-translation'),
75
- 'icon' => 'plus'
76
  ),
77
 
78
  'pending' => array(
79
- 'title' => __('In Progress', 'lingotek-translation'),
80
- 'icon' => 'clock'
81
  ),
82
 
83
  'ready' => array(
84
- 'title' => __('Ready to download', 'lingotek-translation'),
85
- 'icon' => 'download'
86
  ),
87
 
88
  'current' => array(
89
- 'title' => __('Current', 'lingotek-translation'),
90
- 'icon' => 'edit'
91
  ),
92
 
93
  'not-current' => array(
94
- 'title' => __('The target translation is no longer current as the source content has been updated', 'lingotek-translation'),
95
- 'icon' => 'edit'
96
  ),
97
 
98
  'error' => array(
99
- 'title' => __('There was an error contacting Lingotek', 'lingotek-translation'),
100
- 'icon' => 'warning'
101
  ),
102
 
103
  'copy' => array(
104
- 'title' => __('Copy source language', 'lingotek-translation'),
105
- 'icon' => 'welcome-add-page'
106
  ),
107
  );
108
 
@@ -110,14 +143,15 @@ abstract class Lingotek_Actions {
110
  $this->pllm = $GLOBALS['polylang']->model;
111
  $this->lgtm = $GLOBALS['wp_lingotek']->model;
112
 
113
- add_action('admin_enqueue_scripts', array(&$this, 'admin_enqueue_scripts'));
114
 
115
- foreach (array_keys(self::$actions) as $action)
116
- add_action('wp_ajax_lingotek_progress_' . $this->type . '_'. $action , array(&$this, 'ajax_' . $action));
 
117
  }
118
 
119
- /*
120
- * generates a workbench link
121
  *
122
  * @since 0.1
123
  *
@@ -125,13 +159,13 @@ abstract class Lingotek_Actions {
125
  * @param string $locale Lingotek locale
126
  * @return string workbench link
127
  */
128
- public static function workbench_link($document_id, $locale) {
129
  $client_id = Lingotek_API::CLIENT_ID;
130
- $token_details = get_option('lingotek_token');
131
  $user = wp_get_current_user();
132
- $base_url = get_option('lingotek_base_url');
133
 
134
- $acting_login_id = $user->user_email; //user_nicename;
135
 
136
  return self::generate_workbench_link(
137
  $document_id,
@@ -144,41 +178,41 @@ abstract class Lingotek_Actions {
144
  );
145
  }
146
 
147
- /*
148
- * generates a workbench link
149
  * function provided by Matt Smith from Lingotek
150
  *
151
  * @since 0.1
152
  *
153
- * @param string $document_id
154
- * @param string $locale_code
155
- * @param string $client_id
156
- * @param string $access_token
157
- * @param string $login_id
158
- * @param string $acting_login_id
159
- * @param string $base_url
160
  * @param int|null $expiration
161
  * @return string workbench link
162
  */
163
- public static function generate_workbench_link($document_id, $locale_code, $client_id, $access_token, $login_id, $acting_login_id = "anonymous", $base_url = "https://myaccount.lingotek.com", $expiration = NULL) {
164
  $expiration_default = time() + (60 * 30); // 30-minute default, otherwise use $expiration as passed in
165
- $expiration = is_null($expiration) ? $expiration_default : $expiration;
166
  $data = array(
167
  'document_id' => $document_id,
168
  'locale_code' => $locale_code,
169
  'client_id' => $client_id,
170
  'login_id' => $login_id,
171
  'acting_login_id' => $acting_login_id,
172
- 'expiration' => $expiration
173
  );
174
- $query_data = utf8_encode(http_build_query($data));
175
- $hmac = urlencode(base64_encode(hash_hmac('sha1', $query_data, $access_token, TRUE)));
176
- $workbench_url = $base_url . '/lingopoint/portal/wb.action?' . $query_data . "&hmac=" . $hmac;
177
  return $workbench_url;
178
  }
179
 
180
- /*
181
- * outputs an action icon
182
  *
183
  * @since 0.2
184
  *
@@ -186,275 +220,271 @@ abstract class Lingotek_Actions {
186
  * @param string $link
187
  * @param string $additional parameters to add (js, target)
188
  */
189
- public static function display_icon($name, $link, $additional = '') {
190
  return sprintf('<a class="lingotek-color dashicons dashicons-%s" title="%s" href="%s"%s></a>',
191
- self::$icons[$name]['icon'], self::$icons[$name]['title'], esc_url($link), $additional);
192
  }
193
 
194
- /*
195
- * outputs an API error icon
196
  *
197
  * @since 1.2
198
  *
199
  * @param string $name
200
  * @param string $additional parameters to add (js, target)
201
  */
202
- public static function display_error_icon($name, $api_error, $additional = '') {
203
  return sprintf('<span class="lingotek-error dashicons dashicons-%s" title="%s"></span>',
204
- self::$icons[$name]['icon'], self::$icons[$name]['title'] . "\n" . $api_error, $additional);
205
  }
206
 
207
- /*
208
- * outputs an upload icon
209
  *
210
  * @since 0.2
211
  *
212
  * @param int|string $object_id
213
- * @param bool $warning
214
  */
215
- public function upload_icon($object_id, $confirm = false) {
216
- $args = array($this->type => $object_id, 'action' => 'lingotek-upload', 'noheader' => true);
217
- $link = wp_nonce_url(defined('DOING_AJAX') && DOING_AJAX ? add_query_arg($args, wp_get_referer()) : add_query_arg($args), 'lingotek-upload');
218
- return self::display_icon('upload', $link, $confirm ? self::$confirm_message : '');
219
  }
220
 
221
- /*
222
- * outputs a copy icon
223
- *
224
  *
225
  * @param int|string $object_id
226
- * @param string $target
227
- * @param bool $warning
228
  */
229
- public function copy_icon($object_id, $target, $confirm = false) {
230
- $args = array($this->type => $object_id, 'target' => $target, 'action' => 'lingotek-copy', 'noheader' => true);
231
- $link = wp_nonce_url(defined('DOING_AJAX') && DOING_AJAX ? add_query_arg($args, wp_get_referer()) : add_query_arg($args), 'lingotek-copy');
232
- return self::display_icon('copy', $link, $confirm ? self::$confirm_message : '');
233
  }
234
 
235
- /*
236
- * outputs an importing icon
237
  *
238
  * @since 0.2
239
  *
240
  * @param object $document
241
  */
242
- public static function importing_icon($document) {
243
- $args = array('document_id' => $document->document_id, 'action' => 'lingotek-status', 'noheader' => true);
244
- $link = wp_nonce_url(defined('DOING_AJAX') && DOING_AJAX ? add_query_arg($args, wp_get_referer()) : add_query_arg($args), 'lingotek-status');
245
- return self::display_icon('importing', $link);
246
  }
247
 
248
- /*
249
- * outputs icons for translations
250
  *
251
  * @since 0.2
252
  *
253
  * @param object $document
254
  * @param object $language
255
  */
256
- public static function translation_icon($document, $language) {
257
- if (isset($document->translations[$language->locale])) {
258
- if ('ready' == $document->translations[$language->locale]) {
259
- $link = wp_nonce_url(add_query_arg(array('document_id' => $document->document_id, 'locale' => $language->locale, 'action' => 'lingotek-download', 'noheader' => true)), 'lingotek-download');
260
- return self::display_icon($document->translations[$language->locale], $link);
261
- }
262
- else if ('not-current' == $document->translations[$language->locale]) {
263
  return '<div class="lingotek-color dashicons dashicons-no"></div>';
 
 
 
264
  }
265
- else {
266
- $link = self::workbench_link($document->document_id, $language->lingotek_locale);
267
- return self::display_icon($document->translations[$language->locale], $link, ' target="_blank"');
268
- }
269
-
270
- }
271
- else {
272
- $link = wp_nonce_url(add_query_arg(array('document_id' => $document->document_id, 'locale' => $language->locale, 'action' => 'lingotek-request', 'noheader' => true)), 'lingotek-request');
273
- return self::display_icon('request', $link);
274
  }
275
  }
276
 
277
- /*
278
- * creates an html action link
279
  *
280
  * @since 0.2
281
  *
282
  * @param array $args parameters to add to the link
283
- * @param bool $warning whether to display an alert or not, optional, defaults to false
284
  * @return string
285
  */
286
- protected function get_action_link($args, $warning = false) {
287
  $action = $args['action'];
288
  $args['action'] = 'lingotek-' . $action;
289
  $args['noheader'] = true;
290
 
291
  return sprintf(
292
  '<a class="lingotek-color" title="%s" href="%s"%s>%s</a>',
293
- self::$actions[$action]['description'],
294
- wp_nonce_url(defined('DOING_AJAX') && DOING_AJAX ? add_query_arg($args, wp_get_referer()) : add_query_arg($args), 'lingotek-' .$action),
295
- empty($warning) ? '' : self::$confirm_message,
296
- self::$actions[$action]['action']
297
  );
298
  }
299
 
300
- /*
301
- * adds a row action link
302
  *
303
  * @since 0.2
304
  *
305
- * @param array $actions list of action links
306
  * @param $id object id
307
  * @return array
308
  */
309
- protected function _row_actions($actions, $id) {
310
  // first check that a language is associated to this object
311
- if (!$this->get_language($id))
312
  return $actions;
 
313
 
314
- $document = $this->lgtm->get_group($this->type, $id);
315
- if ($this->type != 'string' && isset($document->desc_array['lingotek']['source'])) {
316
  $id = $document->desc_array['lingotek']['source'];
317
  }
318
 
319
- if ($this->lgtm->can_upload($this->type, $id) || (isset($document->source) && 'string' != $this->type && $this->lgtm->can_upload($this->type, $document->source))) {
320
- if ($document) {
321
  $desc_array = $document->desc_array;
322
- unset($desc_array['lingotek']);
323
- if (count($desc_array) >= 2) {
324
- $actions['lingotek-upload'] = $this->get_action_link(array($this->type => $id, 'action' => 'upload'), true);
 
 
325
  }
326
- else {
327
- $actions['lingotek-upload'] = $this->get_action_link(array($this->type => $id, 'action' => 'upload'));
328
- }
329
- }
330
- else {
331
- $actions['lingotek-upload'] = $this->get_action_link(array($this->type => $id, 'action' => 'upload'));
332
  }
333
- }
334
-
335
- elseif (isset($document->translations)) {
336
  // translations to download ?
337
- if ($document->has_translation_status('ready'))
338
- $actions['lingotek-download'] = $this->get_action_link(array('document_id' => $document->document_id, 'action' => 'download'));
 
339
 
340
  // need to request translations ?
341
- $language = $this->get_language($document->source);
342
- $all_locales = array_flip($this->pllm->get_languages_list(array('fields' => 'locale')));
343
- if (!empty($language)) // in case a language has been deleted
344
- unset($all_locales[$language->locale]);
345
- $untranslated = array_diff_key($all_locales, $document->translations);
 
346
 
347
  // remove disabled target language from untranslated languages list
348
- foreach ($untranslated as $k => $v) {
349
- if ($this->type == 'term') {
350
- if ($document->is_disabled_target($language, $this->pllm->get_language($k)))
351
- unset($untranslated[$k]);
352
- }
353
- else {
354
- if ($document->is_disabled_target($language, $this->pllm->get_language($k)))
355
- unset($untranslated[$k]);
 
356
  }
357
  }
358
 
359
- if ('current' == $document->status && !empty($untranslated))
360
- $actions['lingotek-request'] = $this->get_action_link(array('document_id' => $document->document_id, 'action' => 'request'));
 
361
 
362
  // offers to update translations status
363
- if ('importing' == $document->status || $document->has_translation_status('pending'))
364
- $actions['lingotek-status'] = $this->get_action_link(array('document_id' => $document->document_id, 'action' => 'status'));
365
- }
366
-
367
- elseif (empty($document->source)) {
368
- $actions['lingotek-upload'] = $this->get_action_link(array($this->type => $id, 'action' => 'upload'), true);
369
  }
370
 
371
  // offers to disassociate translations
372
- if (isset($document->source))
373
- $actions['lingotek-delete'] = $this->get_action_link(array('document_id' => $document->document_id, 'action' => 'delete'));
 
374
 
375
  return $actions;
376
  }
377
 
378
- /*
379
- * adds actions to bulk dropdown list table using a javascript hack
380
  * as the existing filter does not allow to *add* actions
381
  * also displays the progress dialog placeholder
382
  *
383
  * @since 0.2
384
  */
385
- protected function _add_bulk_actions() {
386
- $js = '';
387
-
388
- foreach (self::$actions as $action => $strings) {
389
- foreach (array('', '2') as $i)
390
- $js .= sprintf('jQuery("<option>").val("bulk-lingotek-%s").text("%s").appendTo("select[name=\'action%s\']");', $action, $strings['action'], $i);
391
 
392
- if (!empty($_GET['bulk-lingotek-' . $action]))
 
 
393
  $text = $strings['progress'];
 
394
  }
395
 
396
- echo '<script type="text/javascript">jQuery(document).ready(function() {' . $js . '});</script>';
 
 
397
 
398
- if (!empty($text))
399
- printf('<div id="lingotek-progressdialog" title="%s"><div id="lingotek-progressbar"></div></div>', $text);
400
  }
401
 
402
- /*
403
- * outputs javascript data for progress.js
404
  *
405
  * @since 0.1
406
  */
407
  public function admin_enqueue_scripts() {
408
- foreach (array_keys(self::$actions) as $action) {
409
- if (!empty($_GET['bulk-lingotek-' . $action])) {
410
  wp_localize_script('lingotek_progress', 'lingotek_data', array(
411
- 'action' => empty($_GET['page']) ? (empty($_GET['taxonomy']) ? 'post_' . $action : 'term_' . $action) : 'string_' . $action,
412
- 'taxonomy' => empty($_GET['taxonomy']) || !taxonomy_exists($_GET['taxonomy']) ? '' : $_GET['taxonomy'],
413
- 'sendback' => remove_query_arg( array('bulk-lingotek-' . $action, 'ids', 'lingotek_warning'), wp_get_referer() ),
414
- 'ids' => array_map('intval', explode(',', $_GET['ids'])),
415
- 'warning' => empty($_GET['lingotek_warning']) ? '' : __('You are about to overwrite existing translations. Are you sure?', 'lingotek-translation'),
416
- 'nonce' => wp_create_nonce('lingotek_progress')
417
  ));
418
  return;
419
  }
420
  }
421
  }
422
 
423
- /*
424
- * manages actions driven by dcoument_id
425
  *
426
  * @since 0.2
427
  *
428
  * @param string $action action name
429
  * @return bool true if the action was managed, false otherwise
430
  */
431
- protected function _manage_actions($action) {
432
- if (!empty($_GET['document_id']))
433
- $document = $this->lgtm->get_group_by_id($_GET['document_id']);
 
434
 
435
- switch($action) {
436
  case 'lingotek-status':
437
- check_admin_referer('lingotek-status');
438
  $document->source_status();
439
  $document->translations_status();
440
  break;
441
 
442
  case 'lingotek-request':
443
- check_admin_referer('lingotek-request');
444
- isset($_GET['locale']) ? $document->request_translation($_GET['locale']) : $document->request_translations();
445
  break;
446
 
447
  case 'lingotek-download':
448
- check_admin_referer('lingotek-download');
449
- isset($_GET['locale']) ? $document->create_translation($_GET['locale']) : $document->create_translations();
450
  break;
451
 
452
  case 'lingotek-delete':
453
- check_admin_referer('lingotek-delete');
454
  $document->disassociate();
455
- if (isset($_GET['lingotek_redirect']) && $_GET['lingotek_redirect'] == true) {
456
  $site_id = get_current_blog_id();
457
- wp_redirect(get_site_url($site_id, '/wp-admin/edit.php?post_type=page'));
458
  exit();
459
  }
460
  break;
@@ -466,83 +496,82 @@ abstract class Lingotek_Actions {
466
  return true;
467
  }
468
 
469
- /*
470
- * ajax response to download translations and showing progress
471
  *
472
  * @since 0.1
473
  */
474
  public function ajax_download() {
475
- check_ajax_referer('lingotek_progress', '_lingotek_nonce');
476
 
477
- if ($document = $this->lgtm->get_group($this->type, $_POST['id'])) {
478
- foreach ($document->translations as $locale => $status) {
479
- if ('pending' == $status || 'ready' == $status) {
480
- $document->create_translation($locale);
481
  }
482
  }
483
  }
484
  die();
485
  }
486
 
487
- /*
488
- * ajax response to request translations and showing progress
489
  *
490
  * @since 0.2
491
  */
492
  public function ajax_request() {
493
- check_ajax_referer('lingotek_progress', '_lingotek_nonce');
494
- if ($document = $this->lgtm->get_group($this->type, $_POST['id'])) {
495
  $document->request_translations();
496
  }
497
  die();
498
  }
499
 
500
- /*
501
- * ajax response to check translation status and showing progress
502
  *
503
  * @since 0.1
504
  */
505
  public function ajax_status() {
506
- check_ajax_referer('lingotek_progress', '_lingotek_nonce');
507
- if ($document = $this->lgtm->get_group($this->type, $_POST['id'])) {
508
  $document->source_status();
509
  $document->translations_status();
510
  }
511
  die();
512
  }
513
 
514
- /*
515
- * ajax response disassociate translations and showing progress
516
  *
517
  * @since 0.2
518
  */
519
  public function ajax_delete() {
520
- check_ajax_referer('lingotek_progress', '_lingotek_nonce');
521
- if ($document = $this->lgtm->get_group($this->type, $_POST['id'])) {
522
  $document->disassociate();
523
  }
524
  die();
525
  }
526
 
527
- /*
528
- * collects and returns all API errors
529
  *
530
  * @since 1.1
531
  *
532
  * @param string errors
533
  */
534
- public static function retrieve_api_error($errors) {
535
  $api_error = "\n";
536
 
537
- foreach($errors as $error => $error_message) {
538
- if (is_array($error_message)) {
539
- if (!empty($error_message)) {
540
- foreach ($error_message as $locale => $message) {
541
  $api_error = $api_error . $message . "\n";
542
  }
543
  }
544
- }
545
- else {
546
  $api_error = $api_error . $error_message . "\n";
547
  }
548
  }
1
  <?php
2
 
3
+ /**
4
  * Base class to add row and bulk actions to posts, media and terms list
5
  * Bulk actions management is inspired by http://www.foxrunsoftware.net/articles/wordpress/add-custom-bulk-action/
6
  *
7
  * @since 0.2
8
  */
9
  abstract class Lingotek_Actions {
10
+ /**
11
+ * Polylang model.
12
+ *
13
+ * @var obj
14
+ */
15
+ public $pllm;
16
+ /**
17
+ * Lingotek model.
18
+ *
19
+ * @var object
20
+ */
21
+ public $lgtm;
22
+ /**
23
+ * Must be defined in child class: 'post' or 'term'.
24
+ *
25
+ * @var string
26
+ */
27
+ public $type;
28
+ /**
29
+ * Actions
30
+ *
31
+ * @var array
32
+ */
33
+ public static $actions;
34
+ /**
35
+ * Icons
36
+ *
37
+ * @var list
38
+ */
39
+ public static $icons;
40
+ /**
41
+ * Confirm_message
42
+ *
43
+ * @var string
44
+ */
45
+ public static $confirm_message;
46
 
47
+ /**
48
  * Constructor
49
  *
50
  * @since 0.2
51
  */
52
+ public function __construct( $type ) {
53
+ // confirm message.
54
+ self::$confirm_message = sprintf( ' onclick = "return confirm(\'%s\');"', __( 'You are about to overwrite existing translations. Are you sure?', 'lingotek-translation' ) );
55
 
56
+ // row actions.
57
  self::$actions = array(
58
  'upload' => array(
59
+ 'action' => __( 'Upload to Lingotek', 'lingotek-translation' ),
60
+ 'progress' => __( 'Uploading...', 'lingotek-translation' ),
61
+ 'description' => __( 'Upload this item to Lingotek TMS', 'lingotek-translation' ),
62
  ),
63
 
64
  'request' => array(
65
+ 'action' => __( 'Request translations', 'lingotek-translation' ),
66
+ 'progress' => __( 'Requesting translations...', 'lingotek-translation' ),
67
+ 'description' => __( 'Request translations of this item to Lingotek TMS', 'lingotek-translation' ),
68
  ),
69
 
70
  'status' => array(
71
+ 'action' => __( 'Update translations status', 'lingotek-translation' ),
72
+ 'progress' => __( 'Updating translations status...', 'lingotek-translation' ),
73
+ 'description' => __( 'Update translations status of this item in Lingotek TMS', 'lingotek-translation' ),
74
  ),
75
 
76
  'download' => array(
77
+ 'action' => __( 'Download translations', 'lingotek-translation' ),
78
+ 'progress' => __( 'Downloading translations...', 'lingotek-translation' ),
79
+ 'description' => __( 'Download translations of this item from Lingotek TMS', 'lingotek-translation' ),
80
  ),
81
 
82
  'delete' => array(
83
+ 'action' => __( 'Disassociate translations', 'lingotek-translation' ),
84
+ 'progress' => __( 'Disassociating translations...', 'lingotek-translation' ),
85
+ 'description' => __( 'Disassociate the translations of this item from Lingotek TMS', 'lingotek-translation' ),
86
  ),
87
  );
88
 
89
  // action icons
90
  self::$icons = array(
91
  'upload' => array(
92
+ 'title' => __( 'Upload Now', 'lingotek-translation' ),
93
+ 'icon' => 'upload',
94
  ),
95
 
96
  'importing' => array(
97
+ 'title' => __( 'Importing source', 'lingotek-translation' ),
98
+ 'icon' => 'clock',
99
  ),
100
 
101
  'uploaded' => array(
102
+ 'title' => __( 'Source uploaded', 'lingotek-translation' ),
103
+ 'icon' => 'yes',
104
  ),
105
 
106
  'request' => array(
107
+ 'title' => __( 'Request a translation', 'lingotek-translation' ),
108
+ 'icon' => 'plus',
109
  ),
110
 
111
  'pending' => array(
112
+ 'title' => __( 'In Progress', 'lingotek-translation' ),
113
+ 'icon' => 'clock',
114
  ),
115
 
116
  'ready' => array(
117
+ 'title' => __( 'Ready to download', 'lingotek-translation' ),
118
+ 'icon' => 'download',
119
  ),
120
 
121
  'current' => array(
122
+ 'title' => __( 'Current', 'lingotek-translation' ),
123
+ 'icon' => 'edit',
124
  ),
125
 
126
  'not-current' => array(
127
+ 'title' => __( 'The target translation is no longer current as the source content has been updated', 'lingotek-translation' ),
128
+ 'icon' => 'edit',
129
  ),
130
 
131
  'error' => array(
132
+ 'title' => __( 'There was an error contacting Lingotek', 'lingotek-translation' ),
133
+ 'icon' => 'warning',
134
  ),
135
 
136
  'copy' => array(
137
+ 'title' => __( 'Copy source language', 'lingotek-translation' ),
138
+ 'icon' => 'welcome-add-page',
139
  ),
140
  );
141
 
143
  $this->pllm = $GLOBALS['polylang']->model;
144
  $this->lgtm = $GLOBALS['wp_lingotek']->model;
145
 
146
+ add_action( 'admin_enqueue_scripts', array( &$this, 'admin_enqueue_scripts' ) );
147
 
148
+ foreach ( array_keys( self::$actions ) as $action ) {
149
+ add_action( 'wp_ajax_lingotek_progress_' . $this->type . '_' . $action , array( &$this, 'ajax_' . $action ) );
150
+ }
151
  }
152
 
153
+ /**
154
+ * Generates a workbench link
155
  *
156
  * @since 0.1
157
  *
159
  * @param string $locale Lingotek locale
160
  * @return string workbench link
161
  */
162
+ public static function workbench_link( $document_id, $locale ) {
163
  $client_id = Lingotek_API::CLIENT_ID;
164
+ $token_details = get_option( 'lingotek_token' );
165
  $user = wp_get_current_user();
166
+ $base_url = get_option( 'lingotek_base_url' );
167
 
168
+ $acting_login_id = $user->user_email; // user_nicename;
169
 
170
  return self::generate_workbench_link(
171
  $document_id,
178
  );
179
  }
180
 
181
+ /**
182
+ * Generates a workbench link
183
  * function provided by Matt Smith from Lingotek
184
  *
185
  * @since 0.1
186
  *
187
+ * @param string $document_id
188
+ * @param string $locale_code
189
+ * @param string $client_id
190
+ * @param string $access_token
191
+ * @param string $login_id
192
+ * @param string $acting_login_id
193
+ * @param string $base_url
194
  * @param int|null $expiration
195
  * @return string workbench link
196
  */
197
+ public static function generate_workbench_link( $document_id, $locale_code, $client_id, $access_token, $login_id, $acting_login_id = 'anonymous', $base_url = 'https://myaccount.lingotek.com', $expiration = null ) {
198
  $expiration_default = time() + (60 * 30); // 30-minute default, otherwise use $expiration as passed in
199
+ $expiration = is_null( $expiration ) ? $expiration_default : $expiration;
200
  $data = array(
201
  'document_id' => $document_id,
202
  'locale_code' => $locale_code,
203
  'client_id' => $client_id,
204
  'login_id' => $login_id,
205
  'acting_login_id' => $acting_login_id,
206
+ 'expiration' => $expiration,
207
  );
208
+ $query_data = utf8_encode( http_build_query( $data ) );
209
+ $hmac = rawurlencode( base64_encode( hash_hmac( 'sha1', $query_data, $access_token, true ) ) );
210
+ $workbench_url = $base_url . '/lingopoint/portal/wb.action?' . $query_data . '&hmac=' . $hmac;
211
  return $workbench_url;
212
  }
213
 
214
+ /**
215
+ * Outputs an action icon
216
  *
217
  * @since 0.2
218
  *
220
  * @param string $link
221
  * @param string $additional parameters to add (js, target)
222
  */
223
+ public static function display_icon( $name, $link, $additional = '' ) {
224
  return sprintf('<a class="lingotek-color dashicons dashicons-%s" title="%s" href="%s"%s></a>',
225
+ self::$icons[ $name ]['icon'], self::$icons[ $name ]['title'], esc_url( $link ), $additional);
226
  }
227
 
228
+ /**
229
+ * Outputs an API error icon
230
  *
231
  * @since 1.2
232
  *
233
  * @param string $name
234
  * @param string $additional parameters to add (js, target)
235
  */
236
+ public static function display_error_icon( $name, $api_error, $additional = '' ) {
237
  return sprintf('<span class="lingotek-error dashicons dashicons-%s" title="%s"></span>',
238
+ self::$icons[ $name ]['icon'], self::$icons[ $name ]['title'] . "\n" . $api_error, $additional);
239
  }
240
 
241
+ /**
242
+ * Outputs an upload icon
243
  *
244
  * @since 0.2
245
  *
246
  * @param int|string $object_id
247
+ * @param bool $warning
248
  */
249
+ public function upload_icon( $object_id, $confirm = false ) {
250
+ $args = array( $this->type => $object_id, 'action' => 'lingotek-upload', 'noheader' => true );
251
+ $link = wp_nonce_url( defined( 'DOING_AJAX' ) && DOING_AJAX ? add_query_arg( $args, wp_get_referer() ) : add_query_arg( $args ), 'lingotek-upload' );
252
+ return self::display_icon( 'upload', $link, $confirm ? self::$confirm_message : '' );
253
  }
254
 
255
+ /**
256
+ * Outputs a copy icon
 
257
  *
258
  * @param int|string $object_id
259
+ * @param string $target
260
+ * @param bool $warning
261
  */
262
+ public function copy_icon( $object_id, $target, $confirm = false ) {
263
+ $args = array( $this->type => $object_id, 'target' => $target, 'action' => 'lingotek-copy', 'noheader' => true );
264
+ $link = wp_nonce_url( defined( 'DOING_AJAX' ) && DOING_AJAX ? add_query_arg( $args, wp_get_referer() ) : add_query_arg( $args ), 'lingotek-copy' );
265
+ return self::display_icon( 'copy', $link, $confirm ? self::$confirm_message : '' );
266
  }
267
 
268
+ /**
269
+ * Outputs an importing icon
270
  *
271
  * @since 0.2
272
  *
273
  * @param object $document
274
  */
275
+ public static function importing_icon( $document ) {
276
+ $args = array( 'document_id' => $document->document_id, 'action' => 'lingotek-status', 'noheader' => true );
277
+ $link = wp_nonce_url( defined( 'DOING_AJAX' ) && DOING_AJAX ? add_query_arg( $args, wp_get_referer() ) : add_query_arg( $args ), 'lingotek-status' );
278
+ return self::display_icon( 'importing', $link );
279
  }
280
 
281
+ /**
282
+ * Outputs icons for translations
283
  *
284
  * @since 0.2
285
  *
286
  * @param object $document
287
  * @param object $language
288
  */
289
+ public static function translation_icon( $document, $language ) {
290
+ if ( isset( $document->translations[ $language->locale ] ) ) {
291
+ if ( 'ready' === $document->translations[ $language->locale ] ) {
292
+ $link = wp_nonce_url( add_query_arg( array( 'document_id' => $document->document_id, 'locale' => $language->locale, 'action' => 'lingotek-download', 'noheader' => true ) ), 'lingotek-download' );
293
+ return self::display_icon( $document->translations[ $language->locale ], $link );
294
+ } elseif ( 'not-current' === $document->translations[ $language->locale ] ) {
 
295
  return '<div class="lingotek-color dashicons dashicons-no"></div>';
296
+ } else {
297
+ $link = self::workbench_link( $document->document_id, $language->lingotek_locale );
298
+ return self::display_icon( $document->translations[ $language->locale ], $link, ' target="_blank"' );
299
  }
300
+ } else {
301
+ $link = wp_nonce_url( add_query_arg( array( 'document_id' => $document->document_id, 'locale' => $language->locale, 'action' => 'lingotek-request', 'noheader' => true ) ), 'lingotek-request' );
302
+ return self::display_icon( 'request', $link );
 
 
 
 
 
 
303
  }
304
  }
305
 
306
+ /**
307
+ * Creates an html action link
308
  *
309
  * @since 0.2
310
  *
311
  * @param array $args parameters to add to the link
312
+ * @param bool $warning whether to display an alert or not, optional, defaults to false
313
  * @return string
314
  */
315
+ protected function get_action_link( $args, $warning = false ) {
316
  $action = $args['action'];
317
  $args['action'] = 'lingotek-' . $action;
318
  $args['noheader'] = true;
319
 
320
  return sprintf(
321
  '<a class="lingotek-color" title="%s" href="%s"%s>%s</a>',
322
+ self::$actions[ $action ]['description'],
323
+ wp_nonce_url( defined( 'DOING_AJAX' ) && DOING_AJAX ? add_query_arg( $args, wp_get_referer() ) : add_query_arg( $args ), 'lingotek-' . $action ),
324
+ empty( $warning ) ? '' : self::$confirm_message,
325
+ self::$actions[ $action ]['action']
326
  );
327
  }
328
 
329
+ /**
330
+ * Adds a row action link
331
  *
332
  * @since 0.2
333
  *
334
+ * @param array $actions list of action links
335
  * @param $id object id
336
  * @return array
337
  */
338
+ protected function _row_actions( $actions, $id ) {
339
  // first check that a language is associated to this object
340
+ if ( ! $this->get_language( $id ) ) {
341
  return $actions;
342
+ }
343
 
344
+ $document = $this->lgtm->get_group( $this->type, $id );
345
+ if ( $this->type !== 'string' && isset( $document->desc_array['lingotek']['source'] ) ) {
346
  $id = $document->desc_array['lingotek']['source'];
347
  }
348
 
349
+ if ( $this->lgtm->can_upload( $this->type, $id ) || (isset( $document->source ) && 'string' !== $this->type && $this->lgtm->can_upload( $this->type, $document->source )) ) {
350
+ if ( $document ) {
351
  $desc_array = $document->desc_array;
352
+ unset( $desc_array['lingotek'] );
353
+ if ( count( $desc_array ) >= 2 ) {
354
+ $actions['lingotek-upload'] = $this->get_action_link( array( $this->type => $id, 'action' => 'upload' ), true );
355
+ } else {
356
+ $actions['lingotek-upload'] = $this->get_action_link( array( $this->type => $id, 'action' => 'upload' ) );
357
  }
358
+ } else {
359
+ $actions['lingotek-upload'] = $this->get_action_link( array( $this->type => $id, 'action' => 'upload' ) );
 
 
 
 
360
  }
361
+ } elseif ( isset( $document->translations ) ) {
 
 
362
  // translations to download ?
363
+ if ( $document->has_translation_status( 'ready' ) ) {
364
+ $actions['lingotek-download'] = $this->get_action_link( array( 'document_id' => $document->document_id, 'action' => 'download' ) );
365
+ }
366
 
367
  // need to request translations ?
368
+ $language = $this->get_language( $document->source );
369
+ $all_locales = array_flip( $this->pllm->get_languages_list( array( 'fields' => 'locale' ) ) );
370
+ if ( ! empty( $language ) ) { // in case a language has been deleted
371
+ unset( $all_locales[ $language->locale ] );
372
+ }
373
+ $untranslated = array_diff_key( $all_locales, $document->translations );
374
 
375
  // remove disabled target language from untranslated languages list
376
+ foreach ( $untranslated as $k => $v ) {
377
+ if ( $this->type === 'term' ) {
378
+ if ( $document->is_disabled_target( $language, $this->pllm->get_language( $k ) ) ) {
379
+ unset( $untranslated[ $k ] );
380
+ }
381
+ } else {
382
+ if ( $document->is_disabled_target( $language, $this->pllm->get_language( $k ) ) ) {
383
+ unset( $untranslated[ $k ] );
384
+ }
385
  }
386
  }
387
 
388
+ if ( 'current' === $document->status && ! empty( $untranslated ) ) {
389
+ $actions['lingotek-request'] = $this->get_action_link( array( 'document_id' => $document->document_id, 'action' => 'request' ) );
390
+ }
391
 
392
  // offers to update translations status
393
+ if ( 'importing' === $document->status || $document->has_translation_status( 'pending' ) ) {
394
+ $actions['lingotek-status'] = $this->get_action_link( array( 'document_id' => $document->document_id, 'action' => 'status' ) );
395
+ }
396
+ } elseif ( empty( $document->source ) ) {
397
+ $actions['lingotek-upload'] = $this->get_action_link( array( $this->type => $id, 'action' => 'upload' ), true );
 
398
  }
399
 
400
  // offers to disassociate translations
401
+ if ( isset( $document->source ) ) {
402
+ $actions['lingotek-delete'] = $this->get_action_link( array( 'document_id' => $document->document_id, 'action' => 'delete' ) );
403
+ }
404
 
405
  return $actions;
406
  }
407
 
408
+ /**
409
+ * Adds actions to bulk dropdown list table using a javascript hack
410
  * as the existing filter does not allow to *add* actions
411
  * also displays the progress dialog placeholder
412
  *
413
  * @since 0.2
414
  */
415
+ protected function _add_bulk_actions( $bulk_actions ) {
 
 
 
 
 
416
 
417
+ foreach ( self::$actions as $action => $strings ) {
418
+ $bulk_actions[ 'bulk-lingotek-' . $action ] = __( $strings['action'], $action );
419
+ if ( null !== filter_input( INPUT_GET, 'bulk-lingotek-' . $action ) ) {
420
  $text = $strings['progress'];
421
+ }
422
  }
423
 
424
+ if ( ! empty( $text ) ) {
425
+ printf( '<div id="lingotek-progressdialog" style="display:none" title="%s"><div id="lingotek-progressbar"></div></div>', esc_html( $text ) );
426
+ }
427
 
428
+ return $bulk_actions;
 
429
  }
430
 
431
+ /**
432
+ * Outputs javascript data for progress.js
433
  *
434
  * @since 0.1
435
  */
436
  public function admin_enqueue_scripts() {
437
+ foreach ( array_keys( self::$actions ) as $action ) {
438
+ if ( null !== filter_input( INPUT_GET, 'bulk-lingotek-' . $action ) ) {
439
  wp_localize_script('lingotek_progress', 'lingotek_data', array(
440
+ 'action' => null === filter_input( INPUT_GET, 'page' ) ? (null === filter_input( INPUT_GET, 'taxonomy' ) ? 'post_' . $action : 'term_' . $action) : 'string_' . $action,
441
+ 'taxonomy' => null === filter_input( INPUT_GET, 'taxonomy' ) || ! taxonomy_exists( wp_unslash( filter_input( INPUT_GET, 'taxonomy' ) ) ) ? '' : filter_input( INPUT_GET, 'taxonomy' ),
442
+ 'sendback' => remove_query_arg( array( 'bulk-lingotek-' . $action, 'ids', 'lingotek_warning' ), wp_get_referer() ),
443
+ 'ids' => array_map( 'intval', explode( ',', filter_input( INPUT_GET, 'ids' ) ) ),
444
+ 'warning' => null === filter_input( INPUT_GET, 'lingotek_warning' ) ? '' : __( 'You are about to overwrite existing translations. Are you sure?', 'lingotek-translation' ),
445
+ 'nonce' => wp_create_nonce( 'lingotek_progress' ),
446
  ));
447
  return;
448
  }
449
  }
450
  }
451
 
452
+ /**
453
+ * Manages actions driven by dcoument_id
454
  *
455
  * @since 0.2
456
  *
457
  * @param string $action action name
458
  * @return bool true if the action was managed, false otherwise
459
  */
460
+ protected function _manage_actions( $action ) {
461
+ if ( null !== filter_input( INPUT_GET, 'document_id' ) ) {
462
+ $document = $this->lgtm->get_group_by_id( filter_input( INPUT_GET, 'document_id' ) );
463
+ }
464
 
465
+ switch ( $action ) {
466
  case 'lingotek-status':
467
+ check_admin_referer( 'lingotek-status' );
468
  $document->source_status();
469
  $document->translations_status();
470
  break;
471
 
472
  case 'lingotek-request':
473
+ check_admin_referer( 'lingotek-request' );
474
+ null !== filter_input( INPUT_GET, 'locale' ) ? $document->request_translation( filter_input( INPUT_GET, 'locale' ) ) : $document->request_translations();
475
  break;
476
 
477
  case 'lingotek-download':
478
+ check_admin_referer( 'lingotek-download' );
479
+ null !== filter_input( INPUT_GET, 'locale' ) ? $document->create_translation( filter_input( INPUT_GET, 'locale' ) ) : $document->create_translations();
480
  break;
481
 
482
  case 'lingotek-delete':
483
+ check_admin_referer( 'lingotek-delete' );
484
  $document->disassociate();
485
+ if ( null !== filter_input( INPUT_GET, 'lingotek_redirect' ) && filter_input( INPUT_GET, 'lingotek_redirect' ) === true ) {
486
  $site_id = get_current_blog_id();
487
+ wp_safe_redirect( get_site_url( $site_id, '/wp-admin/edit.php?post_type=page' ) );
488
  exit();
489
  }
490
  break;
496
  return true;
497
  }
498
 
499
+ /**
500
+ * Ajax response to download translations and showing progress
501
  *
502
  * @since 0.1
503
  */
504
  public function ajax_download() {
505
+ check_ajax_referer( 'lingotek_progress', '_lingotek_nonce' );
506
 
507
+ if ( $document = $this->lgtm->get_group( $this->type, filter_input( INPUT_POST, 'id' ) ) ) {
508
+ foreach ( $document->translations as $locale => $status ) {
509
+ if ( 'pending' === $status || 'ready' === $status ) {
510
+ $document->create_translation( $locale );
511
  }
512
  }
513
  }
514
  die();
515
  }
516
 
517
+ /**
518
+ * Ajax response to request translations and showing progress
519
  *
520
  * @since 0.2
521
  */
522
  public function ajax_request() {
523
+ check_ajax_referer( 'lingotek_progress', '_lingotek_nonce' );
524
+ if ( $document = $this->lgtm->get_group( $this->type, filter_input( INPUT_POST, 'id' ) ) ) {
525
  $document->request_translations();
526
  }
527
  die();
528
  }
529
 
530
+ /**
531
+ * Ajax response to check translation status and showing progress
532
  *
533
  * @since 0.1
534
  */
535
  public function ajax_status() {
536
+ check_ajax_referer( 'lingotek_progress', '_lingotek_nonce' );
537
+ if ( $document = $this->lgtm->get_group( $this->type, filter_input( INPUT_POST, 'id' ) ) ) {
538
  $document->source_status();
539
  $document->translations_status();
540
  }
541
  die();
542
  }
543
 
544
+ /**
545
+ * Ajax response disassociate translations and showing progress
546
  *
547
  * @since 0.2
548
  */
549
  public function ajax_delete() {
550
+ check_ajax_referer( 'lingotek_progress', '_lingotek_nonce' );
551
+ if ( $document = $this->lgtm->get_group( $this->type, filter_input( INPUT_POST, 'id' ) ) ) {
552
  $document->disassociate();
553
  }
554
  die();
555
  }
556
 
557
+ /**
558
+ * Collects and returns all API errors
559
  *
560
  * @since 1.1
561
  *
562
  * @param string errors
563
  */
564
+ public static function retrieve_api_error( $errors ) {
565
  $api_error = "\n";
566
 
567
+ foreach ( $errors as $error => $error_message ) {
568
+ if ( is_array( $error_message ) ) {
569
+ if ( ! empty( $error_message ) ) {
570
+ foreach ( $error_message as $locale => $message ) {
571
  $api_error = $api_error . $message . "\n";
572
  }
573
  }
574
+ } else {
 
575
  $api_error = $api_error . $error_message . "\n";
576
  }
577
  }
admin/admin.php CHANGED
@@ -1,415 +1,453 @@
1
  <?php
2
-
 
 
3
  class Lingotek_Admin {
4
- private $ajax_dashboard_language_endpoint = "lingotek_language";
5
- /*
6
- * setups filters and action needed on all admin pages and on plugins page
 
 
 
 
 
7
  *
8
  * @since 0.1
9
  */
10
  public function __construct() {
11
  $plugin = Lingotek::get_instance();
12
  $this->plugin_slug = $plugin->get_plugin_slug();
13
- $this->dashboard = new Lingotek_Dashboard($plugin);
14
 
15
  $this->pllm = $GLOBALS['polylang']->model;
16
 
17
- add_action('admin_enqueue_scripts', array(&$this, 'admin_enqueue_scripts'));
18
 
19
- // adds a 'settings' link in the plugins table
20
- add_filter('plugin_action_links_' . LINGOTEK_BASENAME, array(&$this, 'plugin_action_links'));
21
 
22
- // adds the link to the languages panel in the wordpress admin menu
23
- add_action('admin_menu', array(&$this, 'add_menus'));
24
 
25
- add_action('load-translation_page_lingotek-translation_manage', array(&$this, 'load_manage_page'));
26
- add_filter('set-screen-option', array($this, 'set_screen_option'), 10, 3);
27
 
28
- add_action('wp_ajax_'.$this->ajax_dashboard_language_endpoint, array(&$this->dashboard, 'ajax_language_dashboard'));
29
- add_action('wp_ajax_get_current_status', array($this,'ajax_get_current_status'));
30
- //Network admin menu
31
- add_action('network_admin_menu', array($this, 'add_network_admin_menu'));
32
  }
33
- public function ajax_get_current_status(){
34
- $lgtm = &$GLOBALS['wp_lingotek']->model;
35
- $pllm = $GLOBALS['polylang']->model;
36
- $languages = pll_languages_list(array('fields' => 'locale'));
37
- $object_ids = $_POST['check_ids'];
38
- if($object_ids === null){
39
- return;
40
- }
41
- $terms = isset($_POST['terms_translations']);
42
-
43
- //The main array consists of
44
- //ids and nonces. Each id has a source language, languages with statuses, and a workbench link
45
- $content_metadata = array();
46
- foreach($object_ids as $object_id) {
47
- $id = $object_id;
48
- $type = $terms ? 'term' : 'post';
49
- if (isset($_POST['taxonomy'])) {
50
- $taxonomy = $_POST['taxonomy'];
51
- if (strpos($_POST['taxonomy'], '&')) {
52
- $taxonomy = strstr($_POST['taxonomy'], '&', true);
53
- }
54
- }
55
- else {
56
- $taxonomy = get_post_type($id);
57
- }
58
- $content_metadata[$id] = array(
59
- 'existing_trans' => false,
60
- 'source' => false,
61
- 'doc_id' => null,
62
- 'source_id' => null,
63
- 'source_status' => null,
64
- );
65
-
66
- $document = $lgtm->get_group($type, $object_id);
67
- if($document && !isset($document->source) && count($document->desc_array) >= 3) {
68
- $content_metadata[$id]['existing_trans'] = true;
69
  }
70
- if ($document && isset($document->source) && isset($document->document_id) && isset($document->status) && isset($document->translations)) {
71
- if($document->source !== (int) $object_id){
72
- $document = $lgtm->get_group($type, $document->source);
73
- }
74
- $source_id = $document->source !== null ? $document->source : $object_id;
75
- $source_language = $terms ? pll_get_term_language($document->source, 'locale')
76
- : pll_get_post_language($document->source, 'locale');
77
- $existing_translations = $type = 'term' ? PLL()->model->term->get_translations($source_id) : PLL()->model->post->get_translations($source_id);
78
-
79
- if(count($existing_translations) > 1){
80
- $content_metadata[$id]['existing_trans'] = true;
81
- }
82
- $content_metadata[$id]['source'] = $source_language;
83
- $content_metadata[$id]['doc_id'] = $document->document_id;
84
- $content_metadata[$id]['source_id'] = $document->source;
85
- $content_metadata[$id]['source_status'] = $document->status;
86
- $target_status = $document->status == 'edited' || $document->status == null ? 'edited' : 'current';
87
- $content_metadata[$id][$source_language]['status'] = $document->source == $object_id ? $document->status : $target_status;
88
-
89
- if(is_array($document->translations)){
90
- foreach($document->translations as $locale => $translation_status) {
91
- $content_metadata[$id][$locale]['status'] = $translation_status;
92
- $workbench_link = Lingotek_Actions::workbench_link($document->document_id, $locale);
93
- $content_metadata[$id][$locale]['workbench_link'] = $workbench_link;
94
- }
95
- }
96
-
97
- //fills in missing languages, makes life easier for the updater
98
- foreach ($languages as $language) {
99
- foreach ($content_metadata as $group => $status) {
100
- $language_obj = $pllm->get_language($source_language);
101
- $target_lang_obj = $pllm->get_language($language);
102
- $profile = Lingotek_Model::get_profile($taxonomy, $language_obj, $group);
103
- if ($profile['profile'] != 'disabled' && $status['source'] != false) {
104
- if (!isset($status[$language])) {
105
- $content_metadata[$group][$language]['status'] = "none";
106
- 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))) {
107
- $content_metadata[$group][$language]['status'] = 'disabled';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  }
109
  }
110
  }
111
  }
112
  }
 
 
 
 
 
 
 
 
 
113
  }
114
 
115
- $language = $type == 'post' ? pll_get_post_language($id) : pll_get_term_language($id);
116
- $language = $pllm->get_language($language);
117
- if ($language) {
118
- $profile = Lingotek_Model::get_profile($taxonomy, $language, $id);
119
- if ($profile['profile'] == 'disabled' && $content_metadata[$id]['source'] == false) {
120
- $content_metadata[$id]['source'] = 'disabled';
121
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  }
123
- }
124
-
125
- //get the nonces associated with the different actions
126
- $content_metadata['request_nonce'] = $this->lingotek_get_matching_nonce('lingotek-request');
127
- $content_metadata['download_nonce'] = $this->lingotek_get_matching_nonce('lingotek-download');
128
- $content_metadata['upload_nonce'] = $this->lingotek_get_matching_nonce('lingotek-upload');
129
- $content_metadata['status_nonce'] = $this->lingotek_get_matching_nonce('lingotek-status');
130
-
131
- wp_send_json($content_metadata);
132
- }
133
-
134
- public function lingotek_get_matching_nonce($action){
135
- $upload_link = wp_nonce_url(add_query_arg(array(
136
- 'action' => $action)),
137
- $action);
138
- $nonce_begin = strpos($upload_link, 'wpnonce=') + 8;
139
- $nonce = substr($upload_link,$nonce_begin);
140
- return $nonce;
141
- }
142
-
143
- public function lingotek_get_placeholders($items){
144
- foreach($items as $item){
145
- $placeholders .= '%s,';
146
- }
147
- $placeholders = rtrim($placeholders, ',');
148
- return $placeholders;
149
- }
150
-
151
- public function get_dashboard_endpoint(){
152
- return site_url("wp-admin/admin-ajax.php?action=".$this->ajax_dashboard_language_endpoint);
153
  }
154
 
155
- /*
156
- * setup js scripts & css styles (only on the relevant pages)
157
  *
158
  * @since 0.1
159
  */
160
  public function admin_enqueue_scripts() {
161
  $screen = get_current_screen();
162
 
163
- // FIXME no minified file for now
164
  $suffix = '';
165
- // $suffix = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min';
166
-
167
- // for each script:
168
- // 0 => the pages on which to load the script
169
- // 1 => the scripts it needs to work
170
- // 2 => 1 if loaded in footer
171
- // FIXME: check if I can load more scripts in footer
172
  $scripts = array(
173
- '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),
174
- 'updater' => array(array('edit', 'upload', 'edit-tags'), array('jquery-ui-progressbar', 'jquery-ui-dialog', 'wp-ajax-response'), 1),
175
  );
176
 
177
  $styles = array(
178
- 'admin' => array(array('edit', 'upload', 'edit-tags', 'translation_page_lingotek-translation_manage', 'translation_page_lingotek-translation_settings'), array('wp-jquery-ui-dialog')),
179
  );
180
 
181
- foreach ($scripts as $script => $v)
182
- if (in_array($screen->base, $v[0]))
183
- wp_enqueue_script('lingotek_'.$script, LINGOTEK_URL .'/js/'.$script.$suffix.'.js', $v[1], LINGOTEK_VERSION, $v[2]);
 
 
184
 
185
- foreach ($styles as $style => $v)
186
- if (in_array($screen->base, $v[0]))
187
- wp_enqueue_style('lingotek_'.$style, LINGOTEK_URL .'/css/'.$style.$suffix.'.css', $v[1], LINGOTEK_VERSION);
 
 
188
  }
189
 
190
- /*
191
- * adds a 'settings' link in the plugins table
192
  *
193
  * @since 0.1
194
  *
195
- * @param array $links list of links associated to the plugin
196
  * @return array modified list of links
197
  */
198
- public function plugin_action_links($links) {
199
- array_unshift($links, '<a href="admin.php?page=lingotek-translation">' . __('Settings', 'lingotek-translation') . '</a>');
200
  return $links;
201
  }
202
 
203
- /*
204
- * adds the links to the Lingotek panels in the wordpress admin menu
205
  *
206
  * @since 0.0.1
207
  */
208
  public function add_menus() {
209
  add_menu_page(
210
- $title = __('Translation', 'lingotek-translation'),
211
  $title,
212
  'manage_options',
213
  $this->plugin_slug,
214
- array($this, 'display_dashboard_page'), 'dashicons-translation'
215
  );
216
 
217
-
218
- add_submenu_page($this->plugin_slug, __('Translation Dashboard', 'lingotek-translation'), __('Dashboard', 'lingotek-translation'), 'manage_options', $this->plugin_slug, array($this, 'display_dashboard_page'));
219
- add_submenu_page($this->plugin_slug, __('Translation Management', 'lingotek-translation'), __('Manage', 'lingotek-translation'), 'manage_options', $this->plugin_slug . '_manage', array($this, 'display_manage_page'));
220
- add_submenu_page($this->plugin_slug, __('Translation Settings', 'lingotek-translation'), __('Settings', 'lingotek-translation'), 'manage_options', $this->plugin_slug . '_settings', array($this, 'display_settings_page'));
221
- add_submenu_page($this->plugin_slug, __('Lingotek Tutorial', 'lingotek-translation'), __('Tutorial', 'lingotek-translation'), 'manage_options', $this->plugin_slug . '_tutorial', array($this, 'display_tutorial_page'));
222
 
223
  $selected_options = Lingotek_Model::get_prefs();
224
- if (isset($selected_options['import_enabled']) && $selected_options['import_enabled']['enabled'] == '1'){
225
- add_submenu_page($this->plugin_slug, __('Lingotek Import', 'lingotek-translation'), __('Import', 'lingotek-translation'), 'manage_options', $this->plugin_slug . '_import', array($this, 'display_import_page')); }
226
- }
227
- /*
228
- * displays the settings page
229
  *
230
  * @since 0.0.1
231
  */
232
  public function display_settings_page() {
233
 
234
- // disconnect Lingotek account
235
- if (array_key_exists('delete_access_token', $_GET) && $_GET['delete_access_token']) {
236
- delete_option('lingotek_token');
237
- delete_option('lingotek_community');
238
- delete_option('lingotek_defaults');
239
  }
240
 
241
- // connect Lingotek account
242
- if (array_key_exists('access_token', $_GET)) {
243
- // set and get token details
244
  $client = new Lingotek_API();
245
- $token_details = $client->get_token_details($_GET['access_token']);
246
- if ($token_details && strlen($token_details->login_id)) {
247
- update_option('lingotek_token', array('access_token' => $_GET['access_token'], 'login_id' => $token_details->login_id));
248
- add_settings_error( 'lingotek_token', 'account-connection', __('Your Lingotek account has been successfully connected.', 'lingotek-translation'), 'updated' );
249
- }
250
- else {
251
- add_settings_error('lingotek_token', 'account-connection', __('Your Lingotek account was not connected. The Access Token received was invalid.', 'lingotek-translation'), 'error');
252
  }
253
  }
254
 
255
- // set page key primarily used for form submissions
256
- $page_key = $this->plugin_slug.'_settings';
257
- if(isset($_GET['sm'])){
258
- $page_key .= '&sm='.sanitize_text_field($_GET['sm']);
259
  }
260
 
261
- // set community
262
- if (!empty($_POST) && key_exists('lingotek_community', $_POST) && strlen($_POST['lingotek_community'])) {
263
- check_admin_referer($page_key, '_wpnonce_' . $page_key);
264
- update_option('lingotek_community', $_POST['lingotek_community']);
265
- add_settings_error('lingotek_community', 'update', __('Your community has been successfully saved.', 'lingotek-translation'), 'updated');
266
- $this->set_community_resources($_POST['lingotek_community']);
267
  }
268
- $community_id = get_option('lingotek_community');
269
- if (!$community_id) {
270
- add_settings_error('lingotek_community', 'error', __('Select and save the community that you would like to use.', 'lingotek-translation'), 'error');
271
  }
272
 
273
  $token_details = self::has_token_details();
274
- $redirect_url = admin_url('admin.php?page=' . $this->plugin_slug . '_settings&sm=account');
275
 
276
- if($token_details){
277
  $access_token = $token_details['access_token'];
278
  $login_id = $token_details['login_id'];
279
- $base_url = get_option('lingotek_base_url');
280
- include(LINGOTEK_ADMIN_INC . '/settings.php');
281
- }
282
- else {
283
- $connect_url = "";
284
- // connect cloak redirect
285
- if(isset($_GET['connect'])){
286
- // set sandbox or production (after button clicked)
287
- if(strcasecmp($_GET['connect'],'sandbox')==0) {
288
- update_option('lingotek_base_url', Lingotek_API::SANDBOX_URL);
289
- }
290
- else {
291
- update_option('lingotek_base_url', Lingotek_API::PRODUCTION_URL);
292
  }
293
  $client = new Lingotek_API();
294
- echo '<div class="wrap"><p class="description">'.__("Redirecting to Lingotek to connect your account...",'lingotek-translation').'</p></div>';
295
 
296
- $connect_url = (strcasecmp($_GET['connect'],'new')==0) ? $client->get_new_url($redirect_url) : $client->get_connect_url($redirect_url);
297
  }
298
- $connect_account_cloak_url_new = admin_url('admin.php?page=' . $this->plugin_slug . '_settings&connect=new');
299
- $connect_account_cloak_url_test = admin_url('admin.php?page=' . $this->plugin_slug . '_settings&connect=sandbox');
300
- $connect_account_cloak_url_prod = admin_url('admin.php?page=' . $this->plugin_slug . '_settings&connect=production');
301
- include(LINGOTEK_ADMIN_INC . '/settings/connect-account.php');
302
  }
303
  }
304
 
305
- /*
306
- * get possible settings for defaults or translation profiles
307
  *
308
  * @since 0.2
309
  *
 
310
  * @return array
311
  */
312
- public function get_profiles_settings($defaults = false) {
313
- $resources = get_option('lingotek_community_resources');
 
 
 
 
 
 
 
 
 
314
  $options = array(
315
- 'manual' => __('Manual', 'lingotek-translation'),
316
- 'automatic' => __('Automatic', 'lingotek-translation')
317
  );
318
 
319
  return array(
320
  'upload' => array(
321
- 'label' => __('Upload content', 'lingotek-translation'),
322
  'options' => $options,
323
- 'description' => __('How should new and modified content be uploaded to Lingotek?', 'lingotek-translation')
324
  ),
325
  'download' => array(
326
- 'label' => __('Download translations', 'lingotek-translation'),
327
  'options' => $options,
328
- 'description' => __('How should completed translations be downloaded to WordPress?', 'lingotek-translation')
329
  ),
330
  'project_id' => array(
331
- 'label' => $defaults ? __('Default Project', 'lingotek-translation') : __('Project', 'lingotek-translation'),
332
  'options' => $resources['projects'],
333
- 'description' => __('Changes will affect new entities only', 'lingotek-translation')
334
  ),
335
  'workflow_id' => array(
336
- 'label' => $defaults ? __('Default Workflow', 'lingotek-translation') : __('Workflow', 'lingotek-translation'),
337
  'options' => $resources['workflows'],
338
- 'description' => __('Changes will affect new entities only', 'lingotek-translation')
339
  ),
340
  'primary_filter_id' => array(
341
- 'label' => $defaults ? __('Primary Filter', 'lingotek-translation') : __('Primary Filter', 'lingotek-translation'),
342
  'options' => $resources['filters'],
343
- 'description' => __('Changes will affect new entities only', 'lingotek-translation')
344
  ),
345
  'secondary_filter_id' => array(
346
- 'label' => $defaults ? __('Secondary Filter', 'lingotek-translation') : __('Secondary Filter', 'lingotek-translation'),
347
  'options' => $resources['filters'],
348
- 'description' => __('Changes will affect new entities only', 'lingotek-translation')
349
  ),
350
  );
351
  }
352
 
353
- /*
354
- * get usage for all profiles
355
  *
356
  * @since 0.2
357
  *
358
- * @param arry $profiles
359
  * @return array profiles with added usage column
360
  */
361
- public function get_profiles_usage($profiles) {
362
- $content_types = get_option('lingotek_content_type');
363
-
364
- // initialize usage column
365
- foreach ($profiles as $key => $profile)
366
- $profiles[$key]['usage'] = 0;
367
-
368
- // fill usage column
369
- foreach (array_merge($this->pllm->get_translated_post_types(), $this->pllm->get_translated_taxonomies(), array('string')) as $type) {
370
- if (isset($content_types[$type]['profile']))
371
- $profiles[$content_types[$type]['profile']]['usage'] += 1;
372
- elseif ('post' == $type)
 
373
  $profiles['automatic']['usage'] += 1;
374
- else
375
- $profiles['manual']['usage'] += 1;
376
 
377
- if (isset($content_types[$type]['sources'])) {
378
- foreach ($content_types[$type]['sources'] as $profile)
379
- $profiles[$profile]['usage'] +=1;
 
380
  }
381
  }
382
  return $profiles;
383
  }
384
 
385
- /*
386
- * store community options and set any missing defaults to the first available option
387
  *
388
  * @since 0.1.0
 
 
 
389
  */
390
- public function set_community_resources($community_id, $update_first_project_callback = FALSE) {
391
  $client = new Lingotek_API();
392
  $refresh_success = array(
393
- 'projects' => FALSE,
394
- 'workflows' => FALSE,
395
  );
396
 
397
- $api_data = $client->get_projects($community_id);
398
  $projects = array();
399
- if ($api_data !== FALSE) {
400
- foreach ($api_data->entities as $project) {
401
- $projects[$project->properties->id] = $project->properties->title;
402
- }
403
- if ($api_data->properties->total == 1) {
404
- if (!$project->properties->callback_url) {
405
- $client->update_callback_url($project->properties->id);
406
- }
407
- }
408
- natcasesort($projects); //order by title (case-insensitive)
409
- $refresh_success['projects'] = TRUE;
410
- }
411
-
412
- $api_data = $client->get_workflows($community_id);
413
  $default_workflows = array(
414
  'c675bd20-0688-11e2-892e-0800200c9a66' => 'Machine Translation',
415
  'ddf6e3c0-0688-11e2-892e-0800200c9a66' => 'Machine Translation + Post-Edit',
@@ -417,39 +455,42 @@ class Lingotek_Admin {
417
  '2b5498e0-f3c7-4c49-9afa-cca4b3345af7' => 'Translation + 1 review',
418
  '814172a6-3744-4da7-b932-5857c1c20976' => 'Translation + 2 reviews',
419
  '2210b148-0c44-4ae2-91d0-ca2ee47c069e' => 'Translation + 3 reviews',
420
- '7993b4d7-4ada-46d0-93d5-858db46c4c7d' => 'Translation Only'
421
  );
422
  $workflows = array();
423
- if ($api_data) {
424
- foreach ($api_data->entities as $workflow) {
425
- $workflows[$workflow->properties->id] = $workflow->properties->title;
426
  }
427
- $diff = array_diff_key($workflows, $default_workflows);
428
- if (empty($diff)) {
429
- $workflows = array('c675bd20-0688-11e2-892e-0800200c9a66' => 'Machine Translation');
 
 
 
430
  }
431
- natcasesort($workflows); //order by title (case-insensitive)
432
- $refresh_success['workflows'] = TRUE;
433
  }
434
 
435
  $api_data = $client->get_filters();
436
  $filters = array();
437
- if ($api_data && $api_data->properties->total > 0) {
438
- foreach ($api_data->entities as $filter) {
439
- if (!$filter->properties->is_public) {
440
- $filters[$filter->properties->id] = $filter->properties->title;
441
  }
442
- if ($filter->properties->title == 'okf_json@with-html-subfilter.fprm' || $filter->properties->title == 'okf_html@wordpress.fprm') {
443
- $filters[$filter->properties->id] = $filter->properties->title;
444
  }
445
  }
446
- $primary_filter_id = array_search('okf_json@with-html-subfilter.fprm', $filters);
447
- $secondary_filter_id = array_search('okf_html@wordpress.fprm', $filters);
448
- $defaults = get_option('lingotek_defaults');
449
- if($defaults == NULL) {
450
  $defaults['primary_filter_id'] = $primary_filter_id;
451
  $defaults['secondary_filter_id'] = $secondary_filter_id;
452
- update_option('lingotek_defaults', $defaults);
453
  }
454
  }
455
 
@@ -459,188 +500,188 @@ class Lingotek_Admin {
459
  'filters' => $filters,
460
  );
461
 
462
- if ($refresh_success['projects'] == TRUE || $refresh_success['workflows'] == TRUE) {
463
- update_option('lingotek_community_resources', $resources);
464
  $this->ensure_valid_defaults();
465
  }
466
  return $refresh_success;
467
  }
468
 
 
 
 
469
  public function ensure_valid_defaults() {
470
- $resources = get_option('lingotek_community_resources');
471
- $defaults = get_option('lingotek_defaults');
472
  $valid_default = array();
473
- foreach ($resources as $resource_key => $options) {
474
- $key = substr($resource_key,0,strlen($resource_key)-1)."_id";
475
- $valid_default[$key] = 0;
476
- if(!is_array($defaults)) {
477
  continue;
478
  }
479
- foreach ($options as $option_key => $option_val) {
480
- if(!array_key_exists($key, $defaults)){
481
  continue;
482
  }
483
- if ($option_key === $defaults[$key]) {
484
- $valid_default[$key] = 1;
485
  break;
486
  }
487
  }
488
  }
489
- foreach ($valid_default as $key => $valid) {
490
- $resource_key = substr($key,0,strpos($key,'_'))."s";
491
- if ($valid) {
492
  continue;
493
- }
494
- else {
495
- $defaults[$key] = current(array_keys($resources[$resource_key]));
496
  }
497
  }
498
- $num_valid_defaults = array_sum($valid_default);
499
 
500
- if($num_valid_defaults < count($valid_default)){
501
- 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' );
502
  }
503
- unset($defaults['filter_id']);
504
- update_option('lingotek_defaults', $defaults);
505
  }
506
 
507
- /*
508
- * displays the admin manage page
509
  *
510
  * @since 0.1.0
511
  */
512
  public function display_manage_page() {
513
- if (self::has_token_details()) {
514
- include(LINGOTEK_ADMIN_INC . '/view-manage.php');
515
- }
516
- else {
517
  $this->display_settings_page();
518
  }
519
  }
520
 
521
- /*
522
- * add screen option on translations->manage page
523
  *
524
  * @since 0.2
525
  */
526
  public function load_manage_page() {
527
  add_screen_option('per_page', array(
528
- 'label' => __('Strings groups', 'lingotek-translation'),
529
  'default' => 10,
530
- 'option' => 'lingotek_strings_per_page'
531
  ));
532
  }
533
 
534
- /*
535
- * save screen option from translations->manage page
536
  *
537
  * @since 0.2
 
 
 
 
538
  */
539
- public function set_screen_option($status, $option, $value) {
540
- if ('lingotek_strings_per_page' == $option) {
541
  return $value;
542
- }
543
  return $status;
544
  }
545
 
546
- /*
547
- * displays the admin manage page
548
  *
549
  * @since 0.1.0
550
  */
551
  public function display_dashboard_page() {
552
  $token_details = self::has_token_details();
553
- if ($token_details) {
554
- $community_id = get_option('lingotek_community');
555
- $defaults = get_option('lingotek_defaults');
556
  $user = wp_get_current_user();
557
 
558
- // The data that will be passed to the Lingotek GMC dashboard
559
  $cms_data = array(
560
- // lingotek
561
- "community_id"=> $community_id,
562
- "external_id"=> $token_details['login_id'],
563
- //"vault_id"=> $defaults['vault_id'],
564
- "workflow_id"=> $defaults['workflow_id'],
565
- "project_id"=> $defaults['project_id'],
566
- "first_name"=> $user->display_name,
567
- "last_name"=> '',
568
- "email"=> get_bloginfo('admin_email'),
569
- // cms
570
- "cms_site_id"=> site_url(),
571
- "cms_site_key"=> site_url(),
572
- "cms_site_name"=> get_bloginfo('name'),
573
- "cms_type"=> "Wordpress",
574
- "cms_version"=> get_bloginfo('version'),
575
- "cms_tag"=> LINGOTEK_PLUGIN_SLUG,
576
- "locale"=> pll_current_language('lingotek_locale'),
577
- "module_version"=> LINGOTEK_VERSION,
578
- "endpoint_url" => $this->get_dashboard_endpoint()
579
  );
580
- include(LINGOTEK_ADMIN_INC . '/view-dashboard.php');
581
- }
582
- else {
583
  $this->display_settings_page();
584
  }
585
  }
586
 
587
- /*
588
- * returns the access token when present, otherwise returns FALSE
589
  *
590
  * @since 0.1.0
591
  */
592
  public static function has_token_details() {
593
- $token_details = get_option('lingotek_token');
594
- $has_token = FALSE;
595
- if ($token_details !== FALSE && key_exists('access_token', $token_details) && key_exists('login_id', $token_details) && strlen($token_details['access_token']) && strlen($token_details['login_id'])) {
596
- $has_token = TRUE;
597
  return $token_details;
598
  }
599
  return $has_token;
600
  }
601
 
 
 
 
602
  public function display_network_settings_page() {
603
- if (is_multisite() && self::has_token_details()) {
604
- include(LINGOTEK_ADMIN_INC . '/view-network.php');
605
- }
606
- else {
607
  $this->display_settings_page();
608
  }
609
  }
610
 
611
- /*
612
- * adds a Lingotek settings option in the network admin page
613
  *
614
  * @since 0.1.0
615
  */
616
  public function add_network_admin_menu() {
617
- add_submenu_page('settings.php', __('Lingotek Settings', 'lingotek-translation'), __('Lingotek Settings', 'lingotek-translation'), 'manage_network_options', $this->plugin_slug . '_network', array($this, 'display_network_settings_page'), 'dashicons-translation');
618
  }
619
 
 
 
 
620
  public function display_tutorial_page() {
621
- if (self::has_token_details()) {
622
- include(LINGOTEK_ADMIN_INC . '/view-tutorial.php');
623
- }
624
- else {
625
  $this->display_settings_page();
626
  }
627
  }
628
 
 
 
 
629
  public function display_import_page() {
630
- if (self::has_token_details()) {
631
- // $client = new Lingotek_API();
632
- // $docs = $client->get_documents(array('limit'=>5000));
633
- // //$community_id = get_option('lingotek_community');
634
- // $communities = $client->get_communities();
635
- // var_dump($communities->entities);
636
- // die();
637
- // $projects = $client->get_projects($community_id)->entities;
638
- // var_dump($projects);
639
- // die();
640
  settings_errors();
641
- include(LINGOTEK_ADMIN_INC) . '/import.php';
642
- }
643
- else {
644
  $this->display_settings_page();
645
  }
646
  }
1
  <?php
2
+ /**
3
+ * Lingotek Admin Class
4
+ */
5
  class Lingotek_Admin {
6
+ /**
7
+ * Ajax dashboard language endpoint.
8
+ *
9
+ * @var string
10
+ */
11
+ private $ajax_dashboard_language_endpoint = 'lingotek_language';
12
+ /**
13
+ * Setups filters and action needed on all admin pages and on plugins page
14
  *
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
 
24
+ add_action( 'admin_enqueue_scripts', array( &$this, 'admin_enqueue_scripts' ) );
25
 
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
  }
40
+
41
+ /**
42
+ * Gets current status.
43
+ */
44
+ public function ajax_get_current_status() {
45
+ $lgtm = &$GLOBALS['wp_lingotek']->model;
46
+ $pllm = $GLOBALS['polylang']->model;
47
+ $languages = pll_languages_list( array( 'fields' => 'locale' ) );
48
+ $object_ids = filter_input( INPUT_POST, 'check_ids' );
49
+ if ( null === $object_ids ) {
50
+ return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  }
52
+ $terms = ! empty( filter_input( INPUT_POST, 'terms_translations' ) );
53
+
54
+ // The main array consists of ids and nonces. Each id has a source language, languages with statuses, and a workbench link.
55
+ $content_metadata = array();
56
+ foreach ( $object_ids as $object_id ) {
57
+ $id = $object_id;
58
+ $type = $terms ? 'term' : 'post';
59
+ if ( ! empty( filter_input( INPUT_POST, 'taxonomy' ) ) ) {
60
+ $taxonomy = filter_input( INPUT_POST, 'taxonomy' );
61
+ if ( strpos( filter_input( INPUT_POST, 'taxonomy' ), '&' ) ) {
62
+ $taxonomy = strstr( filter_input( INPUT_POST, 'taxonomy' ), '&', true );
63
+ }
64
+ } else {
65
+ $taxonomy = get_post_type( $id );
66
+ }
67
+ $content_metadata[ $id ] = array(
68
+ 'existing_trans' => false,
69
+ 'source' => false,
70
+ 'doc_id' => null,
71
+ 'source_id' => null,
72
+ 'source_status' => null,
73
+ );
74
+
75
+ $document = $lgtm->get_group( $type, $object_id );
76
+ if ( $document && ! isset( $document->source ) && count( $document->desc_array ) >= 3 ) {
77
+ $content_metadata[ $id ]['existing_trans'] = true;
78
+ }
79
+ if ( $document && isset( $document->source ) && isset( $document->document_id ) && isset( $document->status ) && isset( $document->translations ) ) {
80
+ if ( $document->source !== (int) $object_id ) {
81
+ $document = $lgtm->get_group( $type, $document->source );
82
+ }
83
+ $source_id = null !== $document->source ? $document->source : $object_id;
84
+ $source_language = $terms ? pll_get_term_language( $document->source, 'locale' )
85
+ : pll_get_post_language( $document->source, 'locale' );
86
+ $existing_translations = $type = 'term' ? PLL()->model->term->get_translations( $source_id ) : PLL()->model->post->get_translations( $source_id );
87
+
88
+ if ( count( $existing_translations ) > 1 ) {
89
+ $content_metadata[ $id ]['existing_trans'] = true;
90
+ }
91
+ $content_metadata[ $id ]['source'] = $source_language;
92
+ $content_metadata[ $id ]['doc_id'] = $document->document_id;
93
+ $content_metadata[ $id ]['source_id'] = $document->source;
94
+ $content_metadata[ $id ]['source_status'] = $document->status;
95
+ $target_status = 'edited' === $document->status || null === $document->status ? 'edited' : 'current';
96
+ $content_metadata[ $id ][ $source_language ]['status'] = $document->source === $object_id ? $document->status : $target_status;
97
+
98
+ if ( is_array( $document->translations ) ) {
99
+ foreach ( $document->translations as $locale => $translation_status ) {
100
+ $content_metadata[ $id ][ $locale ]['status'] = $translation_status;
101
+ $workbench_link = Lingotek_Actions::workbench_link( $document->document_id, $locale );
102
+ $content_metadata[ $id ][ $locale ]['workbench_link'] = $workbench_link;
103
+ }
104
+ }
105
+
106
+ // fills in missing languages, makes life easier for the updater.
107
+ foreach ( $languages as $language ) {
108
+ foreach ( $content_metadata as $group => $status ) {
109
+ $language_obj = $pllm->get_language( $source_language );
110
+ $target_lang_obj = $pllm->get_language( $language );
111
+ $profile = Lingotek_Model::get_profile( $taxonomy, $language_obj, $group );
112
+ if ( 'disabled' !== $profile['profile'] && false !== $status['source'] ) {
113
+ if ( ! isset( $status[ $language ] ) ) {
114
+ $content_metadata[ $group ][ $language ]['status'] = 'none';
115
+ 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 )) ) {
116
+ $content_metadata[ $group ][ $language ]['status'] = 'disabled';
117
+ }
118
  }
119
  }
120
  }
121
  }
122
  }
123
+
124
+ $language = 'post' === $type ? pll_get_post_language( $id ) : pll_get_term_language( $id );
125
+ $language = $pllm->get_language( $language );
126
+ if ( $language ) {
127
+ $profile = Lingotek_Model::get_profile( $taxonomy, $language, $id );
128
+ if ( 'disabled' === $profile['profile'] && false === $content_metadata[ $id ]['source'] ) {
129
+ $content_metadata[ $id ]['source'] = 'disabled';
130
+ }
131
+ }
132
  }
133
 
134
+ // get the nonces associated with the different actions.
135
+ $content_metadata['request_nonce'] = $this->lingotek_get_matching_nonce( 'lingotek-request' );
136
+ $content_metadata['download_nonce'] = $this->lingotek_get_matching_nonce( 'lingotek-download' );
137
+ $content_metadata['upload_nonce'] = $this->lingotek_get_matching_nonce( 'lingotek-upload' );
138
+ $content_metadata['status_nonce'] = $this->lingotek_get_matching_nonce( 'lingotek-status' );
139
+
140
+ wp_send_json( $content_metadata );
141
+ }
142
+
143
+ /**
144
+ * Gets the matching nonce.
145
+ *
146
+ * @param string $action action.
147
+ * @return string nonce.
148
+ */
149
+ public function lingotek_get_matching_nonce( $action ) {
150
+ $upload_link = wp_nonce_url( add_query_arg( array( 'action' => $action ) ), $action );
151
+ $nonce_begin = strpos( $upload_link, 'wpnonce=' ) + 8;
152
+ $nonce = substr( $upload_link,$nonce_begin );
153
+ return $nonce;
154
+ }
155
+
156
+ /**
157
+ * Gets placeholder string.
158
+ *
159
+ * @param array $items list of items.
160
+ * @return string string of placeholders.
161
+ */
162
+ public function lingotek_get_placeholders( $items ) {
163
+ foreach ( $items as $item ) {
164
+ $placeholders .= '%s,';
165
  }
166
+ $placeholders = rtrim( $placeholders, ',' );
167
+ return $placeholders;
168
+ }
169
+
170
+ /**
171
+ * Gets dashboard endpoint.
172
+ *
173
+ * @return url endpoint.
174
+ */
175
+ public function get_dashboard_endpoint() {
176
+ return site_url( 'wp-admin/admin-ajax.php?action=' . $this->ajax_dashboard_language_endpoint );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  }
178
 
179
+ /**
180
+ * Setup js scripts & css styles (only on the relevant pages)
181
  *
182
  * @since 0.1
183
  */
184
  public function admin_enqueue_scripts() {
185
  $screen = get_current_screen();
186
 
187
+ // FIXME no minified file for now.
188
  $suffix = '';
189
+ // $suffix = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min';.
190
+ // for each script:.
191
+ // 0 => the pages on which to load the script.
192
+ // 1 => the scripts it needs to work.
193
+ // 2 => 1 if loaded in footer.
194
+ // FIXME: check if I can load more scripts in footer.
 
195
  $scripts = array(
196
+ '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 ),
197
+ 'updater' => array( array( 'edit', 'upload', 'edit-tags' ), array( 'jquery-ui-progressbar', 'jquery-ui-dialog', 'wp-ajax-response' ), 1 ),
198
  );
199
 
200
  $styles = array(
201
+ 'admin' => array( array( 'edit', 'upload', 'edit-tags', 'translation_page_lingotek-translation_manage', 'translation_page_lingotek-translation_settings' ), array( 'wp-jquery-ui-dialog' ) ),
202
  );
203
 
204
+ foreach ( $scripts as $script => $v ) {
205
+ if ( in_array( $screen->base, $v[0], true ) ) {
206
+ wp_enqueue_script( 'lingotek_' . $script, LINGOTEK_URL . '/js/' . $script . $suffix . '.js', $v[1], LINGOTEK_VERSION, $v[2] );
207
+ }
208
+ }
209
 
210
+ foreach ( $styles as $style => $v ) {
211
+ if ( in_array( $screen->base, $v[0], true ) ) {
212
+ wp_enqueue_style( 'lingotek_' . $style, LINGOTEK_URL . '/css/' . $style . $suffix . '.css', $v[1], LINGOTEK_VERSION );
213
+ }
214
+ }
215
  }
216
 
217
+ /**
218
+ * Adds a 'settings' link in the plugins table
219
  *
220
  * @since 0.1
221
  *
222
+ * @param array $links list of links associated to the plugin.
223
  * @return array modified list of links
224
  */
225
+ public function plugin_action_links( $links ) {
226
+ array_unshift( $links, '<a href="admin.php?page=lingotek-translation">' . __( 'Settings', 'lingotek-translation' ) . '</a>' );
227
  return $links;
228
  }
229
 
230
+ /**
231
+ * Adds the links to the Lingotek panels in the wordpress admin menu
232
  *
233
  * @since 0.0.1
234
  */
235
  public function add_menus() {
236
  add_menu_page(
237
+ $title = __( 'Translation', 'lingotek-translation' ),
238
  $title,
239
  'manage_options',
240
  $this->plugin_slug,
241
+ array( $this, 'display_dashboard_page' ), 'dashicons-translation'
242
  );
243
 
244
+ add_submenu_page( $this->plugin_slug, __( 'Translation Dashboard', 'lingotek-translation' ), __( 'Dashboard', 'lingotek-translation' ), 'manage_options', $this->plugin_slug, array( $this, 'display_dashboard_page' ) );
245
+ add_submenu_page( $this->plugin_slug, __( 'Translation Management', 'lingotek-translation' ), __( 'Manage', 'lingotek-translation' ), 'manage_options', $this->plugin_slug . '_manage', array( $this, 'display_manage_page' ) );
246
+ add_submenu_page( $this->plugin_slug, __( 'Translation Settings', 'lingotek-translation' ), __( 'Settings', 'lingotek-translation' ), 'manage_options', $this->plugin_slug . '_settings', array( $this, 'display_settings_page' ) );
247
+ add_submenu_page( $this->plugin_slug, __( 'Lingotek Tutorial', 'lingotek-translation' ), __( 'Tutorial', 'lingotek-translation' ), 'manage_options', $this->plugin_slug . '_tutorial', array( $this, 'display_tutorial_page' ) );
 
248
 
249
  $selected_options = Lingotek_Model::get_prefs();
250
+ if ( isset( $selected_options['import_enabled'] ) && '1' === $selected_options['import_enabled']['enabled'] ) {
251
+ add_submenu_page( $this->plugin_slug, __( 'Lingotek Import', 'lingotek-translation' ), __( 'Import', 'lingotek-translation' ), 'manage_options', $this->plugin_slug . '_import', array( $this, 'display_import_page' ) ); }
252
+ }
253
+ /**
254
+ * Displays the settings page
255
  *
256
  * @since 0.0.1
257
  */
258
  public function display_settings_page() {
259
 
260
+ // disconnect Lingotek account.
261
+ if ( ! empty( filter_input( INPUT_GET, 'delete_access_token' ) ) ) {
262
+ delete_option( 'lingotek_token' );
263
+ delete_option( 'lingotek_community' );
264
+ delete_option( 'lingotek_defaults' );
265
  }
266
 
267
+ // connect Lingotek account.
268
+ if ( ! empty( filter_input( INPUT_GET, 'access_token' ) ) ) {
269
+ // set and get token details.
270
  $client = new Lingotek_API();
271
+ $token_details = $client->get_token_details( filter_input( INPUT_GET, 'access_token' ) );
272
+ if ( $token_details && strlen( $token_details->login_id ) ) {
273
+ update_option( 'lingotek_token', array( 'access_token' => filter_input( INPUT_GET, 'access_token' ), 'login_id' => $token_details->login_id ) );
274
+ add_settings_error( 'lingotek_token', 'account-connection', __( 'Your Lingotek account has been successfully connected.', 'lingotek-translation' ), 'updated' );
275
+ } else {
276
+ add_settings_error( 'lingotek_token', 'account-connection', __( 'Your Lingotek account was not connected. The Access Token received was invalid.', 'lingotek-translation' ), 'error' );
 
277
  }
278
  }
279
 
280
+ // set page key primarily used for form submissions.
281
+ $page_key = $this->plugin_slug . '_settings';
282
+ if ( ! empty( filter_input( INPUT_GET, 'sm' ) ) ) {
283
+ $page_key .= '&sm=' . sanitize_text_field( filter_input( INPUT_GET, 'sm' ) );
284
  }
285
 
286
+ // set community.
287
+ if ( ! empty( filter_input( INPUT_POST, 'lingotek_community' ) ) && strlen( filter_input( INPUT_POST, 'lingotek_community' ) ) ) {
288
+ check_admin_referer( $page_key, '_wpnonce_' . $page_key );
289
+ update_option( 'lingotek_community', filter_input( INPUT_POST, 'lingotek_community' ) );
290
+ add_settings_error( 'lingotek_community', 'update', __( 'Your community has been successfully saved.', 'lingotek-translation' ), 'updated' );
291
+ $this->set_community_resources( filter_input( INPUT_POST, 'lingotek_community' ) );
292
  }
293
+ $community_id = get_option( 'lingotek_community' );
294
+ if ( ! $community_id ) {
295
+ add_settings_error( 'lingotek_community', 'error', __( 'Select and save the community that you would like to use.', 'lingotek-translation' ), 'error' );
296
  }
297
 
298
  $token_details = self::has_token_details();
299
+ $redirect_url = admin_url( 'admin.php?page=' . $this->plugin_slug . '_settings&sm=account' );
300
 
301
+ if ( $token_details ) {
302
  $access_token = $token_details['access_token'];
303
  $login_id = $token_details['login_id'];
304
+ $base_url = get_option( 'lingotek_base_url' );
305
+ include( LINGOTEK_ADMIN_INC . '/settings.php' );
306
+ } else {
307
+ $connect_url = '';
308
+ // connect cloak redirect.
309
+ if ( ! empty( filter_input( INPUT_GET, 'connect' ) ) ) {
310
+ // set sandbox or production (after button clicked).
311
+ if ( 0 === strcasecmp( filter_input( INPUT_GET, 'connect' ),'sandbox' ) ) {
312
+ update_option( 'lingotek_base_url', Lingotek_API::SANDBOX_URL );
313
+ } else {
314
+ update_option( 'lingotek_base_url', Lingotek_API::PRODUCTION_URL );
 
 
315
  }
316
  $client = new Lingotek_API();
317
+ echo '<div class="wrap"><p class="description">' . esc_html( __( 'Redirecting to Lingotek to connect your account...','lingotek-translation' ) ) . '</p></div>';
318
 
319
+ $connect_url = (0 === strcasecmp( filter_input( INPUT_GET, 'connect' ),'new' )) ? $client->get_new_url( $redirect_url ) : $client->get_connect_url( $redirect_url );
320
  }
321
+ $connect_account_cloak_url_new = admin_url( 'admin.php?page=' . $this->plugin_slug . '_settings&connect=new' );
322
+ $connect_account_cloak_url_test = admin_url( 'admin.php?page=' . $this->plugin_slug . '_settings&connect=sandbox' );
323
+ $connect_account_cloak_url_prod = admin_url( 'admin.php?page=' . $this->plugin_slug . '_settings&connect=production' );
324
+ include( LINGOTEK_ADMIN_INC . '/settings/connect-account.php' );
325
  }
326
  }
327
 
328
+ /**
329
+ * Get possible settings for defaults or translation profiles
330
  *
331
  * @since 0.2
332
  *
333
+ * @param bool $defaults defaults flag.
334
  * @return array
335
  */
336
+ public function get_profiles_settings( $defaults = false ) {
337
+
338
+ /**
339
+ * All specialized modals are echo'd to the page.
340
+ * a .js file is loaded that attaches listeners to each of the specialized workflows
341
+ * and launches a modal when one of them is selected in the default list.
342
+ */
343
+ Lingotek_Workflow_Factory::echo_info_modals();
344
+ wp_enqueue_script( 'lingotek_workflow_defaults', LINGOTEK_URL . '/js/workflow/workflow-defaults.js' );
345
+
346
+ $resources = get_option( 'lingotek_community_resources' );
347
  $options = array(
348
+ 'manual' => __( 'Manual', 'lingotek-translation' ),
349
+ 'automatic' => __( 'Automatic', 'lingotek-translation' ),
350
  );
351
 
352
  return array(
353
  'upload' => array(
354
+ 'label' => __( 'Upload content', 'lingotek-translation' ),
355
  'options' => $options,
356
+ 'description' => __( 'How should new and modified content be uploaded to Lingotek?', 'lingotek-translation' ),
357
  ),
358
  'download' => array(
359
+ 'label' => __( 'Download translations', 'lingotek-translation' ),
360
  'options' => $options,
361
+ 'description' => __( 'How should completed translations be downloaded to WordPress?', 'lingotek-translation' ),
362
  ),
363
  'project_id' => array(
364
+ 'label' => $defaults ? __( 'Default Project', 'lingotek-translation' ) : __( 'Project', 'lingotek-translation' ),
365
  'options' => $resources['projects'],
366
+ 'description' => __( 'Changes will affect new entities only', 'lingotek-translation' ),
367
  ),
368
  'workflow_id' => array(
369
+ 'label' => $defaults ? __( 'Default Workflow', 'lingotek-translation' ) : __( 'Workflow', 'lingotek-translation' ),
370
  'options' => $resources['workflows'],
371
+ 'description' => __( 'Changes will affect new entities only', 'lingotek-translation' ),
372
  ),
373
  'primary_filter_id' => array(
374
+ 'label' => $defaults ? __( 'Primary Filter', 'lingotek-translation' ) : __( 'Primary Filter', 'lingotek-translation' ),
375
  'options' => $resources['filters'],
376
+ 'description' => __( 'Changes will affect new entities only', 'lingotek-translation' ),
377
  ),
378
  'secondary_filter_id' => array(
379
+ 'label' => $defaults ? __( 'Secondary Filter', 'lingotek-translation' ) : __( 'Secondary Filter', 'lingotek-translation' ),
380
  'options' => $resources['filters'],
381
+ 'description' => __( 'Changes will affect new entities only', 'lingotek-translation' ),
382
  ),
383
  );
384
  }
385
 
386
+ /**
387
+ * Get usage for all profiles
388
  *
389
  * @since 0.2
390
  *
391
+ * @param arry $profiles profiles.
392
  * @return array profiles with added usage column
393
  */
394
+ public function get_profiles_usage( $profiles ) {
395
+ $content_types = get_option( 'lingotek_content_type' );
396
+
397
+ // initialize usage column.
398
+ foreach ( $profiles as $key => $profile ) {
399
+ $profiles[ $key ]['usage'] = 0;
400
+ }
401
+
402
+ // fill usage column.
403
+ foreach ( array_merge( $this->pllm->get_translated_post_types(), $this->pllm->get_translated_taxonomies(), array( 'string' ) ) as $type ) {
404
+ if ( isset( $content_types[ $type ]['profile'] ) ) {
405
+ $profiles[ $content_types[ $type ]['profile'] ]['usage'] += 1;
406
+ } elseif ( 'post' === $type ) {
407
  $profiles['automatic']['usage'] += 1;
408
+ } else { $profiles['manual']['usage'] += 1;
409
+ }
410
 
411
+ if ( isset( $content_types[ $type ]['sources'] ) ) {
412
+ foreach ( $content_types[ $type ]['sources'] as $profile ) {
413
+ $profiles[ $profile ]['usage'] += 1;
414
+ }
415
  }
416
  }
417
  return $profiles;
418
  }
419
 
420
+ /**
421
+ * Store community options and set any missing defaults to the first available option
422
  *
423
  * @since 0.1.0
424
+ *
425
+ * @param string $community_id communit id.
426
+ * @param bool $update_first_project_callback boolean flag.
427
  */
428
+ public function set_community_resources( $community_id, $update_first_project_callback = false ) {
429
  $client = new Lingotek_API();
430
  $refresh_success = array(
431
+ 'projects' => false,
432
+ 'workflows' => false,
433
  );
434
 
435
+ $api_data = $client->get_projects( $community_id );
436
  $projects = array();
437
+ if ( false !== $api_data ) {
438
+ foreach ( $api_data->entities as $project ) {
439
+ $projects[ $project->properties->id ] = $project->properties->title;
440
+ }
441
+ if ( 1 === $api_data->properties->total ) {
442
+ if ( ! $project->properties->callback_url ) {
443
+ $client->update_callback_url( $project->properties->id );
444
+ }
445
+ }
446
+ natcasesort( $projects ); // order by title (case-insensitive).
447
+ $refresh_success['projects'] = true;
448
+ }
449
+
450
+ $api_data = $client->get_workflows( $community_id );
451
  $default_workflows = array(
452
  'c675bd20-0688-11e2-892e-0800200c9a66' => 'Machine Translation',
453
  'ddf6e3c0-0688-11e2-892e-0800200c9a66' => 'Machine Translation + Post-Edit',
455
  '2b5498e0-f3c7-4c49-9afa-cca4b3345af7' => 'Translation + 1 review',
456
  '814172a6-3744-4da7-b932-5857c1c20976' => 'Translation + 2 reviews',
457
  '2210b148-0c44-4ae2-91d0-ca2ee47c069e' => 'Translation + 3 reviews',
458
+ '7993b4d7-4ada-46d0-93d5-858db46c4c7d' => 'Translation Only',
459
  );
460
  $workflows = array();
461
+ if ( $api_data ) {
462
+ foreach ( $api_data->entities as $workflow ) {
463
+ $workflows[ $workflow->properties->id ] = $workflow->properties->title;
464
  }
465
+ $diff = array_diff_key( $workflows, $default_workflows );
466
+ if ( empty( $diff ) ) {
467
+ $workflows = [
468
+ 'c675bd20-0688-11e2-892e-0800200c9a66' => 'Machine Translation',
469
+ // 'professional-translation' => 'Professional Translation',
470
+ ];
471
  }
472
+ natcasesort( $workflows ); // order by title (case-insensitive).
473
+ $refresh_success['workflows'] = true;
474
  }
475
 
476
  $api_data = $client->get_filters();
477
  $filters = array();
478
+ if ( $api_data && $api_data->properties->total > 0 ) {
479
+ foreach ( $api_data->entities as $filter ) {
480
+ if ( ! $filter->properties->is_public ) {
481
+ $filters[ $filter->properties->id ] = $filter->properties->title;
482
  }
483
+ if ( 'okf_json@with-html-subfilter.fprm' === $filter->properties->title || 'okf_html@wordpress.fprm' === $filter->properties->title ) {
484
+ $filters[ $filter->properties->id ] = $filter->properties->title;
485
  }
486
  }
487
+ $primary_filter_id = array_search( 'okf_json@with-html-subfilter.fprm', $filters, true );
488
+ $secondary_filter_id = array_search( 'okf_html@wordpress.fprm', $filters, true );
489
+ $defaults = get_option( 'lingotek_defaults' );
490
+ if ( null === $defaults ) {
491
  $defaults['primary_filter_id'] = $primary_filter_id;
492
  $defaults['secondary_filter_id'] = $secondary_filter_id;
493
+ update_option( 'lingotek_defaults', $defaults );
494
  }
495
  }
496
 
500
  'filters' => $filters,
501
  );
502
 
503
+ if ( true === $refresh_success['projects'] || true === $refresh_success['workflows'] ) {
504
+ update_option( 'lingotek_community_resources', $resources );
505
  $this->ensure_valid_defaults();
506
  }
507
  return $refresh_success;
508
  }
509
 
510
+ /**
511
+ * Ensures valid defaults.
512
+ */
513
  public function ensure_valid_defaults() {
514
+ $resources = get_option( 'lingotek_community_resources' );
515
+ $defaults = get_option( 'lingotek_defaults' );
516
  $valid_default = array();
517
+ foreach ( $resources as $resource_key => $options ) {
518
+ $key = substr( $resource_key,0,strlen( $resource_key ) -1 ) . '_id';
519
+ $valid_default[ $key ] = 0;
520
+ if ( ! is_array( $defaults ) ) {
521
  continue;
522
  }
523
+ foreach ( $options as $option_key => $option_val ) {
524
+ if ( ! array_key_exists( $key, $defaults ) ) {
525
  continue;
526
  }
527
+ if ( $option_key === $defaults[ $key ] ) {
528
+ $valid_default[ $key ] = 1;
529
  break;
530
  }
531
  }
532
  }
533
+ foreach ( $valid_default as $key => $valid ) {
534
+ $resource_key = substr( $key,0,strpos( $key,'_' ) ) . 's';
535
+ if ( $valid ) {
536
  continue;
537
+ } else {
538
+ $defaults[ $key ] = current( array_keys( $resources[ $resource_key ] ) );
 
539
  }
540
  }
541
+ $num_valid_defaults = array_sum( $valid_default );
542
 
543
+ if ( $num_valid_defaults < count( $valid_default ) ) {
544
+ 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' );
545
  }
546
+ unset( $defaults['filter_id'] );
547
+ update_option( 'lingotek_defaults', $defaults );
548
  }
549
 
550
+ /**
551
+ * Displays the admin manage page
552
  *
553
  * @since 0.1.0
554
  */
555
  public function display_manage_page() {
556
+ if ( self::has_token_details() ) {
557
+ include( LINGOTEK_ADMIN_INC . '/view-manage.php' );
558
+ } else {
 
559
  $this->display_settings_page();
560
  }
561
  }
562
 
563
+ /**
564
+ * Add screen option on translations->manage page
565
  *
566
  * @since 0.2
567
  */
568
  public function load_manage_page() {
569
  add_screen_option('per_page', array(
570
+ 'label' => __( 'Strings groups', 'lingotek-translation' ),
571
  'default' => 10,
572
+ 'option' => 'lingotek_strings_per_page',
573
  ));
574
  }
575
 
576
+ /**
577
+ * Save screen option from translations->manage page
578
  *
579
  * @since 0.2
580
+ *
581
+ * @param item $status status.
582
+ * @param string $option option.
583
+ * @param item $value value.
584
  */
585
+ public function set_screen_option( $status, $option, $value ) {
586
+ if ( 'lingotek_strings_per_page' === $option ) {
587
  return $value;
588
+ }
589
  return $status;
590
  }
591
 
592
+ /**
593
+ * Displays the admin manage page
594
  *
595
  * @since 0.1.0
596
  */
597
  public function display_dashboard_page() {
598
  $token_details = self::has_token_details();
599
+ if ( $token_details ) {
600
+ $community_id = get_option( 'lingotek_community' );
601
+ $defaults = get_option( 'lingotek_defaults' );
602
  $user = wp_get_current_user();
603
 
604
+ // The data that will be passed to the Lingotek GMC dashboard.
605
  $cms_data = array(
606
+ // lingotek.
607
+ 'community_id' => $community_id,
608
+ 'external_id' => $token_details['login_id'],
609
+ 'workflow_id' => $defaults['workflow_id'],
610
+ 'project_id' => $defaults['project_id'],
611
+ 'first_name' => $user->display_name,
612
+ 'last_name' => '',
613
+ 'email' => get_bloginfo( 'admin_email' ),
614
+ // cms.
615
+ 'cms_site_id' => site_url(),
616
+ 'cms_site_key' => site_url(),
617
+ 'cms_site_name' => get_bloginfo( 'name' ),
618
+ 'cms_type' => 'Wordpress',
619
+ 'cms_version' => get_bloginfo( 'version' ),
620
+ 'cms_tag' => LINGOTEK_PLUGIN_SLUG,
621
+ 'locale' => pll_current_language( 'lingotek_locale' ),
622
+ 'module_version' => LINGOTEK_VERSION,
623
+ 'endpoint_url' => $this->get_dashboard_endpoint(),
 
624
  );
625
+ include( LINGOTEK_ADMIN_INC . '/view-dashboard.php' );
626
+ } else {
 
627
  $this->display_settings_page();
628
  }
629
  }
630
 
631
+ /**
632
+ * Returns the access token when present, otherwise returns FALSE
633
  *
634
  * @since 0.1.0
635
  */
636
  public static function has_token_details() {
637
+ $token_details = get_option( 'lingotek_token' );
638
+ $has_token = false;
639
+ 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'] ) ) {
640
+ $has_token = true;
641
  return $token_details;
642
  }
643
  return $has_token;
644
  }
645
 
646
+ /**
647
+ * Displays network settings page.
648
+ */
649
  public function display_network_settings_page() {
650
+ if ( is_multisite() && self::has_token_details() ) {
651
+ include( LINGOTEK_ADMIN_INC . '/view-network.php' );
652
+ } else {
 
653
  $this->display_settings_page();
654
  }
655
  }
656
 
657
+ /**
658
+ * Adds a Lingotek settings option in the network admin page
659
  *
660
  * @since 0.1.0
661
  */
662
  public function add_network_admin_menu() {
663
+ add_submenu_page( 'settings.php', __( 'Lingotek Settings', 'lingotek-translation' ), __( 'Lingotek Settings', 'lingotek-translation' ), 'manage_network_options', $this->plugin_slug . '_network', array( $this, 'display_network_settings_page' ), 'dashicons-translation' );
664
  }
665
 
666
+ /**
667
+ * Displays tutorial page.
668
+ */
669
  public function display_tutorial_page() {
670
+ if ( self::has_token_details() ) {
671
+ include( LINGOTEK_ADMIN_INC . '/view-tutorial.php' );
672
+ } else {
 
673
  $this->display_settings_page();
674
  }
675
  }
676
 
677
+ /**
678
+ * Displays import page.
679
+ */
680
  public function display_import_page() {
681
+ if ( self::has_token_details() ) {
 
 
 
 
 
 
 
 
 
682
  settings_errors();
683
+ include( LINGOTEK_ADMIN_INC ) . '/import.php';
684
+ } else {
 
685
  $this->display_settings_page();
686
  }
687
  }
admin/content-table.php CHANGED
@@ -1,48 +1,61 @@
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
  class Lingotek_Content_Table extends WP_List_Table {
8
- protected $profiles, $content_types;
 
 
 
 
 
 
 
 
 
 
 
9
 
10
- /*
11
- * constructor
12
  *
 
13
  * @since 0.2
14
  */
15
- function __construct($content_types) {
16
  parent::__construct(array(
17
- 'plural' => 'lingotek-content', // do not translate (used for css class)
18
- 'ajax' => false
19
  ));
20
 
21
  $this->profiles = Lingotek::get_profiles();
22
  $this->content_types = $content_types;
23
  }
24
 
25
- /*
26
- * displays the item information in a column (default case)
27
  *
28
  * @since 0.2
29
  *
30
- * @param array $item
31
- * @param string $column_name
32
- * @return string
33
  */
34
- function column_name($item) {
35
  global $polylang;
36
 
37
- printf('<span class="content-type-name">%s</span>', esc_html($item['name']));
38
 
39
- // the source language for strings is always the default language
40
- if ('string' != $item['type']) {
41
  printf('<a id="id[%s]" class="dashicons dashicons-arrow-right" onclick="%s" href="#"></a>',
42
- esc_attr($item['type']),
43
  "
44
- d1 = document.getElementById('sources-name[{$item['type']}]');
45
- d2 = document.getElementById('sources-profile[{$item['type']}]');
46
  c = 'dashicons dashicons-arrow-';
47
  if (c+'right' == this.className) {
48
  this.className = c+'down';
@@ -56,42 +69,41 @@ class Lingotek_Content_Table extends WP_List_Table {
56
  "
57
  );
58
 
59
- printf('<ul class="sources-name" id="sources-name[%s]" style="display:none;">', $item['type']);
60
- foreach ($polylang->model->get_languages_list() as $language) {
61
- printf('<li>%s</li>', sprintf(__('%s source', 'lingotek-translation'), esc_html($language->name)));
62
  }
63
  echo '</ul>';
64
  }
65
  }
66
 
67
- /*
68
- * displays the item profile dropdown list
69
  *
70
  * @since 0.2
71
  *
72
- * @param array $item
73
- * @return string
74
  */
75
- function column_profile($item) {
76
  global $polylang;
77
 
78
- printf('<select class="content-type-profile" name="%1$s" id="%1$s">', $item['type'] . '[profile]');
79
- foreach ($this->profiles as $key => $profile) {
80
- $selected = (isset($item['profile']) && $key == $item['profile']) ? 'selected="selected"' : '';
81
- echo "\n\t<option value='" . esc_attr($key) . "' $selected>" . esc_html($profile['name']) . '</option>';
82
  }
83
  echo '</select>';
84
 
85
- $options = array_merge(array('default' => array('name' => __('Use content type default', 'lingotek-translation'))), $this->profiles);
86
 
87
- // the source language for strings is always the default language
88
- if ('string' != $item['type']) {
89
- printf('<ul class="sources-profile" id="sources-profile[%s]" style="display:none;">', $item['type']);
90
- foreach ($polylang->model->get_languages_list() as $language) {
91
- printf('<li><select name="%1$s" id="%1$s">', $item['type'] . '[sources][' . $language->slug . ']' );
92
- foreach ($options as $key => $profile) {
93
- $selected = (isset($item['sources'][$language->slug]) && $key == $item['sources'][$language->slug]) ? 'selected="selected"' : '';
94
- echo "\n\t<option value='" . esc_attr($key) . "' $selected>" . esc_html($profile['name']) . '</option>';
95
  }
96
  echo '</select></li>';
97
  }
@@ -99,53 +111,51 @@ class Lingotek_Content_Table extends WP_List_Table {
99
  }
100
  }
101
 
102
- /*
103
- * displays checkboxes in fields columns
104
  * can handle fields with one or two keys
105
  *
106
  * @since 0.2
107
  *
108
- * @param array $labels
109
- * @param array $values
110
- * @param string $parent
111
  */
112
- protected function display_fields($labels, $values, $name) {
113
- foreach ($labels as $key => $str) {
114
- if (is_array($str)) {
115
- if ($key === 'metas') {
116
  continue;
117
  }
118
- $this->display_fields($str, isset($values[$key]) ? $values[$key] : array(), $name . "[$key]");
119
- }
120
- else {
121
  printf(
122
  '<li><label><input name="%s" type="checkbox" value="1" %s /> %s</label></li>',
123
- esc_attr($name . "[$key]"),
124
- empty($values[$key]) ? 'checked="checked"' : '',
125
- esc_html($str)
126
  );
127
  }
128
  }
129
  }
130
 
131
- /*
132
- * displays the item fields checkboxes
133
  *
134
  * @since 0.2
135
  *
136
- * @param array $item
137
- * @return string
138
  */
139
- function column_fields($item) {
140
- if (!empty($item['fields'])) {
141
  echo '<ul class="content-type-fields">';
142
- $this->display_fields($item['fields']['label'], isset($item['fields']['value']) ? $item['fields']['value'] : array() , $item['type'] . '[fields]');
143
  echo '</ul>';
144
  }
145
  }
146
 
147
- /*
148
- * gets the list of columns
149
  *
150
  * @since 0.2
151
  *
@@ -153,14 +163,14 @@ class Lingotek_Content_Table extends WP_List_Table {
153
  */
154
  function get_columns() {
155
  return array(
156
- 'name' => __('Content Type', 'lingotek-translation'),
157
- 'profile' => __('Profile', 'lingotek-translation'),
158
- 'fields' => __('Fields', 'lingotek-translation'),
159
  );
160
  }
161
 
162
- /*
163
- * gets the list of sortable columns
164
  *
165
  * @since 0.2
166
  *
@@ -168,36 +178,44 @@ class Lingotek_Content_Table extends WP_List_Table {
168
  */
169
  function get_sortable_columns() {
170
  return array(
171
- 'name' => array('name', false),
172
  );
173
  }
174
 
175
- /*
176
- * prepares the list of items ofr displaying
177
  *
178
  * @since 0.2
179
  *
180
- * @param array $data
181
  */
182
- function prepare_items($data = array()) {
183
- $per_page = $this->get_items_per_page('lingotek_content_per_page');
184
- $this->_column_headers = array($this->get_columns(), array(), $this->get_sortable_columns());
185
-
186
- function usort_reorder($a, $b){
187
- $result = strcmp($a[$_REQUEST['orderby']], $b[$_REQUEST['orderby']]); // determine sort order
188
- return (empty($_REQUEST['order']) || $_REQUEST['order'] == 'asc') ? $result : -$result; // send final sort direction to usort
 
 
 
 
 
 
 
189
  };
190
 
191
- if (!empty($_REQUEST['orderby'])) // no sort by default
192
- usort($data, 'usort_reorder');
 
193
 
194
- $total_items = count($data);
195
- $this->items = array_slice($data, ($this->get_pagenum() - 1) * $per_page, $per_page);
196
 
197
  $this->set_pagination_args(array(
198
  'total_items' => $total_items,
199
  'per_page' => $per_page,
200
- 'total_pages' => ceil($total_items/$per_page)
201
  ));
202
  }
203
  }
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
+ * Lingotek Content Table class.
9
+ */
10
  class Lingotek_Content_Table extends WP_List_Table {
11
+ /**
12
+ * Profiles.
13
+ *
14
+ * @var array
15
+ */
16
+ protected $profiles;
17
+ /**
18
+ * Content types.
19
+ *
20
+ * @var array
21
+ */
22
+ protected $content_types;
23
 
24
+ /**
25
+ * Constructor
26
  *
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
 
40
+ /**
41
+ * Displays the item information in a column (default case)
42
  *
43
  * @since 0.2
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'] ) . "]');
58
+ d2 = document.getElementById('sources-profile[" . esc_html( $item['type'] ) . "]');
59
  c = 'dashicons dashicons-arrow-';
60
  if (c+'right' == this.className) {
61
  this.className = c+'down';
69
  "
70
  );
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
+ /**
81
+ * Displays the item profile dropdown list
82
  *
83
  * @since 0.2
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>';
96
 
97
+ $options = array_merge( array( 'default' => array( 'name' => __( 'Use content type default', 'lingotek-translation' ) ) ), $this->profiles );
98
 
99
+ // the source language for strings is always the default language.
100
+ if ( 'string' !== $item['type'] ) {
101
+ printf( '<ul class="sources-profile" id="sources-profile[%s]" style="display:none;">', esc_html( $item['type'] ) );
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>';
109
  }
111
  }
112
  }
113
 
114
+ /**
115
+ * Displays checkboxes in fields columns
116
  * can handle fields with one or two keys
117
  *
118
  * @since 0.2
119
  *
120
+ * @param array $labels labels.
121
+ * @param array $values values.
122
+ * @param string $name name.
123
  */
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]" );
131
+ } else {
 
132
  printf(
133
  '<li><label><input name="%s" type="checkbox" value="1" %s /> %s</label></li>',
134
+ esc_attr( $name . "[$key]" ),
135
+ empty( $values[ $key ] ) ? 'checked="checked"' : '',
136
+ esc_html( $str )
137
  );
138
  }
139
  }
140
  }
141
 
142
+ /**
143
+ * Displays the item fields checkboxes
144
  *
145
  * @since 0.2
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
  }
156
 
157
+ /**
158
+ * Gets the list of columns
159
  *
160
  * @since 0.2
161
  *
163
  */
164
  function get_columns() {
165
  return array(
166
+ 'name' => __( 'Content Type', 'lingotek-translation' ),
167
+ 'profile' => __( 'Profile', 'lingotek-translation' ),
168
+ 'fields' => __( 'Fields', 'lingotek-translation' ),
169
  );
170
  }
171
 
172
+ /**
173
+ * Gets the list of sortable columns
174
  *
175
  * @since 0.2
176
  *
178
  */
179
  function get_sortable_columns() {
180
  return array(
181
+ 'name' => array( 'name', false ),
182
  );
183
  }
184
 
185
+ /**
186
+ * Prepares the list of items ofr displaying
187
  *
188
  * @since 0.2
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
+ /**
197
+ * Custom sorting comparator.
198
+ *
199
+ * @param array $a array of strings.
200
+ * @param array $b array of strings.
201
+ * @return int sort direction.
202
+ */
203
+ function usort_reorder( $a, $b ) {
204
+ $result = strcmp( $a[ filter_input( INPUT_GET, 'orderby' ) ], $b[ filter_input( INPUT_GET, 'orderby' ) ] ); // determine sort order.
205
+ return (empty( filter_input( INPUT_GET, 'order' ) ) || filter_input( INPUT_GET, 'order' ) === 'asc') ? $result : -$result; // send final sort direction to usort.
206
  };
207
 
208
+ if ( ! empty( filter_input( INPUT_GET, 'orderby' ) ) ) { // no sort by default.
209
+ usort( $data, 'usort_reorder' );
210
+ }
211
 
212
+ $total_items = count( $data );
213
+ $this->items = array_slice( $data, ($this->get_pagenum() - 1) * $per_page, $per_page );
214
 
215
  $this->set_pagination_args(array(
216
  'total_items' => $total_items,
217
  'per_page' => $per_page,
218
+ 'total_pages' => ceil( $total_items / $per_page ),
219
  ));
220
  }
221
  }
admin/custom-fields-table.php CHANGED
@@ -1,115 +1,134 @@
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
  class Lingotek_Custom_Fields_Table extends WP_List_Table {
8
- protected $profiles, $content_types;
 
 
 
 
 
 
 
 
 
 
 
9
 
10
- /*
11
- * constructor
12
- *
13
- * @since 0.2
14
- */
15
- function __construct() {
16
- parent::__construct(array(
17
- 'plural' => 'lingotek-custom-fields', // do not translate (used for css class)
18
- 'ajax' => false
19
- ));
20
- }
21
 
22
- /*
23
- * displays the item's meta_key
24
- *
25
- * @since 0.2
26
- *
27
- * @param array $item
28
- * @return string
29
- */
30
- function column_meta_key($item) {
31
- return isset($item['meta_key']) ? esc_html($item['meta_key']) : '';
32
- }
33
 
34
- /*
35
- * displays the item setting
36
- *
37
- * @since 0.2
38
- *
39
- * @param array $item
40
- * @param string $column_name
41
- * @return string
42
- */
43
- function column_setting($item) {
44
- $settings = array('translate', 'copy', 'ignore');
45
- $custom_field_choices = get_option('lingotek_custom_fields', array());
46
 
47
- printf('<select class="custom-field-setting" name="%1$s" id="%1$s">', 'settings' . '[' . $item['meta_key'] . ']');
48
-
49
- // select the option from the lingotek_custom_fields option
50
- foreach ($settings as $setting) {
51
- if ($setting === $custom_field_choices[$item['meta_key']]) {
52
- $selected = 'selected="selected"';
53
- }
54
- else {
55
- $selected = '';
56
- }
57
- echo "\n\t<option value='" . esc_attr($setting) . "' $selected>" . esc_attr(ucwords($setting)) . '</option>';
58
- }
59
- echo '</select>';
60
- }
61
 
62
- /*
63
- * gets the list of columns
64
- *
65
- * @since 0.2
66
- *
67
- * @return array the list of column titles
68
- */
69
- function get_columns() {
70
- return array(
71
- 'meta_key' => __('Custom Field Key', 'lingotek-translation'),
72
- 'setting' => __('Action', 'lingotek-translation'),
73
- );
74
- }
75
 
76
- /*
77
- * gets the list of sortable columns
78
- *
79
- * @since 0.2
80
- *
81
- * @return array
82
- */
83
- function get_sortable_columns() {
84
- return array(
85
- 'meta_key' => array('meta_key', false),
86
- );
87
- }
 
88
 
89
- /*
90
- * prepares the list of items for displaying
91
- *
92
- * @since 0.2
93
- *
94
- * @param array $data
95
- */
96
- function prepare_items($data = array()) {
97
- $this->_column_headers = array($this->get_columns(), array(), $this->get_sortable_columns());
 
 
 
98
 
99
- function usort_reorder($a, $b){
100
- $result = strcmp($a[$_REQUEST['orderby']], $b[$_REQUEST['orderby']]); // determine sort order
101
- return (empty($_REQUEST['order']) || $_REQUEST['order'] == 'asc') ? $result : -$result; // send final sort direction to usort
102
- };
 
 
 
 
 
103
 
104
- if (!empty($_REQUEST['orderby'])) // no sort by default
105
- usort($data, 'usort_reorder');
 
 
 
 
 
 
 
 
 
106
 
107
- $total_items = count($data);
108
- $this->items = $data;
 
109
 
110
- $this->set_pagination_args(array(
111
- 'total_items' => $total_items,
112
- 'per_page' => count($data),
113
- ));
114
- }
115
- }
 
 
 
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
+ * Lingotek Custom Fields Table class.
9
+ */
10
  class Lingotek_Custom_Fields_Table extends WP_List_Table {
11
+ /**
12
+ * List of profiles.
13
+ *
14
+ * @var array
15
+ */
16
+ protected $profiles;
17
+ /**
18
+ * List of content types.
19
+ *
20
+ * @var array
21
+ */
22
+ protected $content_types;
23
 
24
+ /**
25
+ * Constructor
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
+ /**
37
+ * Displays the item's meta_key
38
+ *
39
+ * @since 0.2
40
+ *
41
+ * @param array $item item.
42
+ * @return string
43
+ */
44
+ function column_meta_key( $item ) {
45
+ return isset( $item['meta_key'] ) ? esc_html( $item['meta_key'] ) : '';
46
+ }
47
 
48
+ /**
49
+ * Displays the item setting
50
+ *
51
+ * @since 0.2
52
+ *
53
+ * @param array $item item.
54
+ */
55
+ function column_setting( $item ) {
56
+ $settings = array( 'translate', 'copy', 'ignore' );
57
+ $custom_field_choices = get_option( 'lingotek_custom_fields', array() );
 
 
58
 
59
+ printf( '<select class="custom-field-setting" name="%1$s" id="%1$s">', 'settings[' . esc_html( $item['meta_key'] ) . ']' );
 
 
 
 
 
 
 
 
 
 
 
 
 
60
 
61
+ // select the option from the lingotek_custom_fields option.
62
+ foreach ( $settings as $setting ) {
63
+ if ( $setting === $custom_field_choices[ $item['meta_key'] ] ) {
64
+ $selected = 'selected="selected"';
65
+ } else {
66
+ $selected = '';
67
+ }
68
+ echo "\n\t<option value='" . esc_attr( $setting ) . "' " . esc_html( $selected ) . '>' . esc_attr( ucwords( $setting ) ) . '</option>';
69
+ }
70
+ echo '</select>';
71
+ }
 
 
72
 
73
+ /**
74
+ * Gets the list of columns
75
+ *
76
+ * @since 0.2
77
+ *
78
+ * @return array the list of column titles
79
+ */
80
+ function get_columns() {
81
+ return array(
82
+ 'meta_key' => __( 'Custom Field Key', 'lingotek-translation' ),
83
+ 'setting' => __( 'Action', 'lingotek-translation' ),
84
+ );
85
+ }
86
 
87
+ /**
88
+ * Gets the list of sortable columns
89
+ *
90
+ * @since 0.2
91
+ *
92
+ * @return array
93
+ */
94
+ function get_sortable_columns() {
95
+ return array(
96
+ 'meta_key' => array( 'meta_key', false ),
97
+ );
98
+ }
99
 
100
+ /**
101
+ * Prepares the list of items for displaying
102
+ *
103
+ * @since 0.2
104
+ *
105
+ * @param array $data data.
106
+ */
107
+ function prepare_items( $data = array() ) {
108
+ $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() );
109
 
110
+ /**
111
+ * Custom sorting comparator.
112
+ *
113
+ * @param array $a array of strings.
114
+ * @param array $b array of strings.
115
+ * @return int sort direction.
116
+ */
117
+ function usort_reorder( $a, $b ) {
118
+ $result = strcmp( $a[ filter_input( INPUT_GET, 'orderby' ) ], $b[ filter_input( INPUT_GET, 'orderby' ) ] ); // determine sort order.
119
+ return (empty( filter_input( INPUT_GET, 'order' ) ) || 'asc' === filter_input( INPUT_GET, 'order' ) ) ? $result : -$result; // send final sort direction to usort.
120
+ };
121
 
122
+ if ( ! empty( filter_input( INPUT_GET, 'orderby' ) ) ) { // no sort by default.
123
+ usort( $data, 'usort_reorder' );
124
+ }
125
 
126
+ $total_items = count( $data );
127
+ $this->items = $data;
128
+
129
+ $this->set_pagination_args(array(
130
+ 'total_items' => $total_items,
131
+ 'per_page' => count( $data ),
132
+ ));
133
+ }
134
+ }
admin/filters-columns.php CHANGED
@@ -1,241 +1,277 @@
1
  <?php
2
 
3
- /*
4
  * Modifies Polylang filters
5
  *
6
  * @since 0.1
7
  */
8
  class Lingotek_Filters_Columns extends PLL_Admin_Filters_Columns {
9
- public $lgtm; // Lingotek model
 
 
 
 
 
10
 
11
- /*
12
- * cosntructor
13
  *
14
  * @since 0.1
15
  *
16
- * @param object $polylang Polylang object
17
  */
18
- public function __construct(&$polylang) {
19
- parent::__construct($polylang);
20
 
21
  $this->lgtm = &$GLOBALS['wp_lingotek']->model;
22
 
23
- // FIXME remove quick edit and bulk edit for now waiting for a solution to remove it only for uploaded documents
24
- remove_filter('quick_edit_custom_box', array(&$this, 'quick_edit_custom_box'), 10, 2);
25
- remove_filter('bulk_edit_custom_box', array(&$this, 'quick_edit_custom_box'), 10, 2);
26
  }
27
 
28
- /*
29
- * adds languages and translations columns in posts, pages, media, categories and tags tables
30
  * overrides Polylang method to display all languages including the filtered one
31
  * as well as displaying a tooltip with the language name and locale when there is no flag
32
  *
33
  * @since 0.2
34
  *
35
- * @param array $columns list of table columns
36
- * @param string $before the column before which we want to add our languages
37
  * @return array modified list of columns
38
  */
39
- protected function add_column($columns, $before) {
40
- $n = array_search($before, array_keys($columns));
41
- if ($n) {
42
- $end = array_slice($columns, $n);
43
- $columns = array_slice($columns, 0, $n);
44
  }
45
 
46
- foreach ($this->model->get_languages_list() as $language) {
47
- $columns['language_'.$language->locale] = $language->flag ? $language->flag :
48
  sprintf('<a href="" title="%s">%s</a>',
49
- esc_html("$language->name ($language->locale)"),
50
- esc_html($language->slug)
51
  );
52
  }
53
 
54
- return isset($end) ? array_merge($columns, $end) : $columns;
55
  }
56
 
57
- /*
58
- * fills the language and translations columns in the posts and taxonomies lists tables
59
  * take care that when doing ajax inline edit, the post or term may not be updated in database yet
60
  *
61
  * @since 0.2
62
  *
63
- * @param string $type 'post' or 'term'
64
- * @param string $column column name
65
- * @param int $object_id id of the current object in row
 
66
  */
67
- protected function _column($type, $column, $object_id, $custom_data = NULL) {
68
- $action = 'post' == $type ? 'inline-save' : 'inline-save-tax';
69
- $inline = defined('DOING_AJAX') && $_REQUEST['action'] == $action && isset($_POST['inline_lang_choice']);
70
  $lang = $inline ?
71
- $this->model->get_language($_POST['inline_lang_choice']) :
72
- $type == 'post' ? PLL()->model->post->get_language($object_id) : PLL()->model->term->get_language($object_id);
73
 
74
- if (false === strpos($column, 'language_') || !$lang) {
75
- if ($custom_data) {
76
  return $custom_data;
77
- }
78
- else {
79
  return '';
80
  }
81
  }
82
 
83
- $language = $this->model->get_language(substr($column, 9));
84
 
85
- // FIXME should I suppress quick edit?
86
- // yes for uploaded posts, but I will need js as the field is built for all posts
87
- // /!\ also take care not add this field two times when translations are managed by Polylang
88
- // hidden field containing the post language for quick edit (used to filter categories since Polylang 1.7)
89
- if ($column == $this->get_first_language_column() /*&& !$this->model->get_translation_id('post', $post_id)*/) {
90
- printf('<div class="hidden" id="lang_%d">%s</div>', esc_attr($object_id), esc_html($lang->slug));
91
  }
92
 
93
- $id = ($inline && $lang->slug != $this->model->get_language($_POST['old_lang'])->slug) ?
94
- ($language->slug == $lang->slug ? $object_id : 0) :
95
- $type == 'post' ? PLL()->model->post->get($object_id, $language) : PLL()->model->term->get($object_id, $language);
96
 
97
- $document = $this->lgtm->get_group($type, $object_id);
98
- if (isset($document->source)) {
99
- $source_language = $type == 'post' ? PLL()->model->post->get_language($document->source) : PLL()->model->term->get_language($document->source);
100
- $source_profile = Lingotek_Model::get_profile($this->content_type, $source_language, $document->source);
101
- }
102
- else {
103
  $source_language = $lang;
104
  }
105
 
106
- // FIXME not very clean
107
- $actions = 'post' == $type ? $GLOBALS['wp_lingotek']->post_actions : $GLOBALS['wp_lingotek']->term_actions;
108
-
109
- $profile = Lingotek_Model::get_profile($this->content_type, $language, $object_id);
110
- $disabled = 'disabled' == $profile['profile'];
111
 
112
- // post ready for upload
113
- if ($this->lgtm->can_upload($type, $object_id) && $object_id == $id) {
114
- return $disabled ? ('post' == $type ? parent::post_column($column, $object_id) : parent::term_column('', $column, $object_id))
115
- : ($document && (count($document->desc_array) >= 3) ? $actions->upload_icon($object_id, true) : $actions->upload_icon($object_id));
116
- }
117
 
118
- // if language is set to copy and profile is manual
119
- elseif (($type == 'post') && ((isset($source_profile['targets'][$language->slug]) && $source_profile['targets'][$language->slug] == 'copy') || (isset($profile['targets'][$language->slug]) && $profile['targets'][$language->slug] == 'copy') && isset($document->source))) {
120
- if (isset($document->desc_array[$language->slug])) {
121
- return 'post' == $type ? parent::post_column($column, $object_id) : parent::term_column('', $column, $object_id);
122
- }
123
- else {
124
- if ($document) {
125
- return $actions->copy_icon($document->source, $language->slug);
126
- }
127
- else {
128
- return $actions->copy_icon($object_id, $language->slug);
 
 
129
  }
130
  }
131
- }
132
-
133
- // translation disabled
134
- elseif (isset($document->source) && $document->is_disabled_target($source_language, $language) && !isset($document->translations[$language->locale])) {
135
- return 'post' == $type ? parent::post_column($column, $object_id) : parent::term_column('', $column, $object_id);
136
- }
137
-
138
- // source post is uploaded
139
- elseif (isset($document->source) && $document->source == $id) {
140
- // source ready for upload
141
- if ($this->lgtm->can_upload($type, $id)) {
142
- return $actions->upload_icon($id);
143
  }
144
 
145
- // importing source
146
- if ($id == $object_id && 'importing' == $document->status) {
147
- return Lingotek_Actions::importing_icon($document);
148
  }
149
 
150
- // uploaded
151
- return 'post' == $type ? Lingotek_Post_actions::uploaded_icon($id) : Lingotek_Term_actions::uploaded_icon($id);
152
- }
153
-
154
- // translations
155
- elseif (isset($document->translations[$language->locale]) || (isset($document->source) && 'current' == $document->status)){
156
- return Lingotek_Actions::translation_icon($document, $language);
157
- }
158
-
159
- elseif ($type == 'term' && !isset($document->translations[$language->locale]) && $document->source != $object_id) {
160
- return parent::term_column('', $column, $object_id);
161
- }
162
-
163
- // translations exist but are not managed by Lingotek TMS
164
- elseif (empty($document->source)) {
165
- 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));
166
- }
167
-
168
- // no translation
169
  else {
170
  return '<div class="lingotek-color dashicons dashicons-no"></div>';
171
  }
172
  }
173
 
174
- /*
175
- * fills the language and translations columns in the posts, pages and media library tables
176
  * take care that when doing ajax inline edit, the post may not be updated in database yet
177
  *
178
  * @since 0.1
179
  *
180
- * @param string $column column name
181
- * @param int $post_id
182
  */
183
- public function post_column($column, $post_id) {
184
- $this->content_type = get_post_type($post_id);
185
 
186
- echo $this->_column('post', $column, $post_id);
 
 
 
 
 
 
 
 
 
 
187
 
188
- // checking for api errors
189
- $document = $this->lgtm->get_group('post', $post_id);
190
- if (isset($document->source)) {
191
- $source_language = PLL()->model->post->get_language($document->source);
192
- $this->error_icon_html($column, $post_id, $source_language->locale);
193
- }
194
- else {
195
- $this->error_icon_html($column, $post_id);
 
 
 
 
 
 
 
 
 
196
  }
197
  }
198
 
199
- /*
200
- * fills the language and translations columns in the categories and post tags tables
201
  * take care that when doing ajax inline edit, the term may not be updated in database yet
202
  *
203
  * @since 0.2
204
  *
205
- * @param string $empty not used
206
- * @param string $column column name
207
- * @param int term_id
208
  */
209
- public function term_column($custom_data, $column, $term_id) {
 
 
 
 
 
 
 
 
 
 
 
 
 
210
  $this->content_type = $GLOBALS['taxonomy'];
211
- if (!$custom_data) {
212
- echo $this->_column('term', $column, $term_id);
213
- }
214
- else {
215
- echo $this->_column('term', $column, $term_id, $custom_data);
 
 
 
 
 
 
 
 
216
  }
217
- // checking for api errors
218
- $this->error_icon_html($column, $term_id);
219
  }
220
 
221
- /*
222
- * checks for errors in the lingotek_log_errors option and displays an icon
223
  *
224
  * @since 1.2
225
  *
226
- * @param string $column
227
- * @param string $object_id
 
228
  */
229
- protected function error_icon_html($column, $object_id, $source_locale = null) {
230
- // checking for api errors
231
- $source_column = substr($column, 9);
232
- $column_language_only = substr($column, 0, 11);
233
- $errors = get_option('lingotek_log_errors');
234
-
235
- if ($source_column == $source_locale) {
236
- if (isset($errors[$object_id])) {
237
- $api_error = Lingotek_Actions::retrieve_api_error($errors[$object_id]);
238
- echo Lingotek_Actions::display_error_icon('error', $api_error);
 
 
 
 
 
 
 
239
  }
240
  }
241
  }
1
  <?php
2
 
3
+ /**
4
  * Modifies Polylang filters
5
  *
6
  * @since 0.1
7
  */
8
  class Lingotek_Filters_Columns extends PLL_Admin_Filters_Columns {
9
+ /**
10
+ * Lingotek model.
11
+ *
12
+ * @var object
13
+ */
14
+ public $lgtm;
15
 
16
+ /**
17
+ * Constructor
18
  *
19
  * @since 0.1
20
  *
21
+ * @param object $polylang Polylang object.
22
  */
23
+ public function __construct( &$polylang ) {
24
+ parent::__construct( $polylang );
25
 
26
  $this->lgtm = &$GLOBALS['wp_lingotek']->model;
27
 
28
+ // FIXME remove quick edit and bulk edit for now waiting for a solution to remove it only for uploaded documents.
29
+ remove_filter( 'quick_edit_custom_box', array( &$this, 'quick_edit_custom_box' ), 10, 2 );
30
+ remove_filter( 'bulk_edit_custom_box', array( &$this, 'quick_edit_custom_box' ), 10, 2 );
31
  }
32
 
33
+ /**
34
+ * Adds languages and translations columns in posts, pages, media, categories and tags tables
35
  * overrides Polylang method to display all languages including the filtered one
36
  * as well as displaying a tooltip with the language name and locale when there is no flag
37
  *
38
  * @since 0.2
39
  *
40
+ * @param array $columns list of table columns.
41
+ * @param string $before the column before which we want to add our languages.
42
  * @return array modified list of columns
43
  */
44
+ protected function add_column( $columns, $before ) {
45
+ $n = array_search( $before, array_keys( $columns ), true );
46
+ if ( $n ) {
47
+ $end = array_slice( $columns, $n );
48
+ $columns = array_slice( $columns, 0, $n );
49
  }
50
 
51
+ foreach ( $this->model->get_languages_list() as $language ) {
52
+ $columns[ 'language_' . $language->locale ] = $language->flag ? $language->flag :
53
  sprintf('<a href="" title="%s">%s</a>',
54
+ esc_html( "$language->name ($language->locale)" ),
55
+ esc_html( $language->slug )
56
  );
57
  }
58
 
59
+ return isset( $end ) ? array_merge( $columns, $end ) : $columns;
60
  }
61
 
62
+ /**
63
+ * Fills the language and translations columns in the posts and taxonomies lists tables
64
  * take care that when doing ajax inline edit, the post or term may not be updated in database yet
65
  *
66
  * @since 0.2
67
  *
68
+ * @param string $type 'post' or 'term'.
69
+ * @param string $column column name.
70
+ * @param int $object_id id of the current object in row.
71
+ * @param item $custom_data data.
72
  */
73
+ protected function _column( $type, $column, $object_id, $custom_data = null ) {
74
+ $action = 'post' === $type ? 'inline-save' : 'inline-save-tax';
75
+ $inline = defined( 'DOING_AJAX' ) && filter_input( INPUT_GET, 'action' ) === $action && ! empty( filter_input( INPUT_POST, 'inline_lang_choice' ) );
76
  $lang = $inline ?
77
+ $this->model->get_language( filter_input( INPUT_POST, 'inline_lang_choice' ) ) :
78
+ 'post' === $type ? PLL()->model->post->get_language( $object_id ) : PLL()->model->term->get_language( $object_id );
79
 
80
+ if ( false === strpos( $column, 'language_' ) || ! $lang ) {
81
+ if ( $custom_data ) {
82
  return $custom_data;
83
+ } else {
 
84
  return '';
85
  }
86
  }
87
 
88
+ $language = $this->model->get_language( substr( $column, 9 ) );
89
 
90
+ // FIXME should I suppress quick edit?.
91
+ // yes for uploaded posts, but I will need js as the field is built for all posts.
92
+ // /!\ also take care not add this field two times when translations are managed by Polylang.
93
+ // hidden field containing the post language for quick edit (used to filter categories since Polylang 1.7).
94
+ if ( $column === $this->get_first_language_column() ) {
95
+ printf( '<div class="hidden" id="lang_%d">%s</div>', esc_attr( $object_id ), esc_html( $lang->slug ) );
96
  }
97
 
98
+ $id = ($inline && $lang->slug !== $this->model->get_language( filter_input( INPUT_POST, 'old_lang' ) )->slug) ?
99
+ ($language->slug === $lang->slug ? $object_id : 0) :
100
+ 'post' === $type ? PLL()->model->post->get( $object_id, $language ) : PLL()->model->term->get( $object_id, $language );
101
 
102
+ $document = $this->lgtm->get_group( $type, $object_id );
103
+ if ( isset( $document->source ) ) {
104
+ $source_language = 'post' === $type ? PLL()->model->post->get_language( $document->source ) : PLL()->model->term->get_language( $document->source );
105
+ $source_profile = Lingotek_Model::get_profile( $this->content_type, $source_language, $document->source );
106
+ } else {
 
107
  $source_language = $lang;
108
  }
109
 
110
+ // FIXME not very clean.
111
+ $actions = 'post' === $type ? $GLOBALS['wp_lingotek']->post_actions : $GLOBALS['wp_lingotek']->term_actions;
 
 
 
112
 
113
+ $profile = Lingotek_Model::get_profile( $this->content_type, $language, $object_id );
114
+ $disabled = 'disabled' === $profile['profile'];
 
 
 
115
 
116
+ // post ready for upload.
117
+ if ( $this->lgtm->can_upload( $type, $object_id ) && $object_id === $id ) {
118
+ return $disabled ? ('post' === $type ? parent::post_column( $column, $object_id ) : parent::term_column( '', $column, $object_id ))
119
+ : ($document && (count( $document->desc_array ) >= 3) ? $actions->upload_icon( $object_id, true ) : $actions->upload_icon( $object_id ));
120
+ } // if language is set to copy and profile is manual.
121
+ elseif ( ('post' === $type) && ((isset( $source_profile['targets'][ $language->slug ] ) && 'copy' === $source_profile['targets'][ $language->slug ]) || (isset( $profile['targets'][ $language->slug ] ) && 'copy' === $profile['targets'][ $language->slug ] ) && isset( $document->source )) ) {
122
+ if ( isset( $document->desc_array[ $language->slug ] ) ) {
123
+ return 'post' === $type ? parent::post_column( $column, $object_id ) : parent::term_column( '', $column, $object_id );
124
+ } else {
125
+ if ( $document ) {
126
+ return $actions->copy_icon( $document->source, $language->slug );
127
+ } else {
128
+ return $actions->copy_icon( $object_id, $language->slug );
129
  }
130
  }
131
+ } // translation disabled.
132
+ elseif ( isset( $document->source ) && $document->is_disabled_target( $source_language, $language ) && ! isset( $document->translations[ $language->locale ] ) ) {
133
+ return 'post' === $type ? parent::post_column( $column, $object_id ) : parent::term_column( '', $column, $object_id );
134
+ } // source post is uploaded.
135
+ elseif ( isset( $document->source ) && $document->source === $id ) {
136
+ // source ready for upload.
137
+ if ( $this->lgtm->can_upload( $type, $id ) ) {
138
+ return $actions->upload_icon( $id );
 
 
 
 
139
  }
140
 
141
+ // importing source.
142
+ if ( $id === $object_id && 'importing' === $document->status ) {
143
+ return Lingotek_Actions::importing_icon( $document );
144
  }
145
 
146
+ // uploaded.
147
+ return 'post' === $type ? Lingotek_Post_actions::uploaded_icon( $id ) : Lingotek_Term_actions::uploaded_icon( $id );
148
+ } // translations.
149
+ elseif ( isset( $document->translations[ $language->locale ] ) || (isset( $document->source ) && 'current' === $document->status) ) {
150
+ return Lingotek_Actions::translation_icon( $document, $language );
151
+ } elseif ( 'term' === $type && ! isset( $document->translations[ $language->locale ] ) && $document->source !== $object_id ) {
152
+ return parent::term_column( '', $column, $object_id );
153
+ } // translations exist but are not managed by Lingotek TMS.
154
+ elseif ( empty( $document->source ) ) {
155
+ 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 ));
156
+ } // no translation.
 
 
 
 
 
 
 
 
157
  else {
158
  return '<div class="lingotek-color dashicons dashicons-no"></div>';
159
  }
160
  }
161
 
162
+ /**
163
+ * Fills the language and translations columns in the posts, pages and media library tables
164
  * take care that when doing ajax inline edit, the post may not be updated in database yet
165
  *
166
  * @since 0.1
167
  *
168
+ * @param string $column column name.
169
+ * @param int $post_id post id.
170
  */
171
+ public function post_column( $column, $post_id ) {
172
+ $this->content_type = get_post_type( $post_id );
173
 
174
+ $allowed_html = [
175
+ 'a' => [
176
+ 'href' => [],
177
+ 'class' => [],
178
+ 'title' => [],
179
+ ],
180
+ 'div' => [
181
+ 'class' => [],
182
+ ],
183
+ ];
184
+ echo wp_kses( $this->_column( 'post', $column, $post_id ), $allowed_html );
185
 
186
+ /**
187
+ * Setup workflow specific logic for posts.
188
+ */
189
+ $post = get_post( $post_id );
190
+ $language = PLL()->model->post->get_language( $post_id );
191
+ $workflow_id = Lingotek_Model::get_profile_option( 'workflow_id', $post->post_type, $language, false, $post_id );
192
+ $workflow = Lingotek_Workflow_Factory::get_workflow_instance( $workflow_id ); // TODO: put workflow_id here. It is currently not set up.
193
+ $workflow->override_events( $workflow_id ); // Loads appropriate .js file.
194
+ $workflow->echo_posts_modal( $workflow_id ); // adds modal html to page.
195
+
196
+ // checking for api errors.
197
+ $document = $this->lgtm->get_group( 'post', $post_id );
198
+ if ( isset( $document->source ) ) {
199
+ $source_language = PLL()->model->post->get_language( $document->source );
200
+ $this->error_icon_html( $column, $post_id, $source_language->locale );
201
+ } else {
202
+ $this->error_icon_html( $column, $post_id );
203
  }
204
  }
205
 
206
+ /**
207
+ * Fills the language and translations columns in the categories and post tags tables
208
  * take care that when doing ajax inline edit, the term may not be updated in database yet
209
  *
210
  * @since 0.2
211
  *
212
+ * @param string $custom_data data.
213
+ * @param string $column column name.
214
+ * @param int $term_id term id.
215
  */
216
+ public function term_column( $custom_data, $column, $term_id ) {
217
+ $allowed_html = [
218
+ 'a' => [
219
+ 'href' => [],
220
+ 'class' => [],
221
+ 'title' => [],
222
+ ],
223
+ 'div' => [
224
+ 'class' => [],
225
+ ],
226
+ 'span' => [
227
+ 'class' => [],
228
+ ],
229
+ ];
230
  $this->content_type = $GLOBALS['taxonomy'];
231
+
232
+ /**
233
+ * Setup workflow specific logic for terms.
234
+ */
235
+ $workflow_id = Lingotek_Model::get_profile_option( 'workflow_id', $this->content_type, PLL()->model->term->get_language( $term_id ) );
236
+ $workflow = Lingotek_Workflow_Factory::get_workflow_instance( $workflow_id ); // TODO: put workflow_id here. It is currently not set up.
237
+ $workflow->override_events( $workflow_id ); // Loads appropriate .js file.
238
+ $workflow->echo_terms_modal( $workflow_id ); // adds modal html to page.
239
+
240
+ if ( ! $custom_data ) {
241
+ echo wp_kses( $this->_column( 'term', $column, $term_id ), $allowed_html );
242
+ } else {
243
+ echo wp_kses( $this->_column( 'term', $column, $term_id, $custom_data ), $allowed_html );
244
  }
245
+ // checking for api errors.
246
+ $this->error_icon_html( $column, $term_id );
247
  }
248
 
249
+ /**
250
+ * Checks for errors in the lingotek_log_errors option and displays an icon
251
  *
252
  * @since 1.2
253
  *
254
+ * @param string $column column.
255
+ * @param string $object_id id.
256
+ * @param item $source_locale locale.
257
  */
258
+ protected function error_icon_html( $column, $object_id, $source_locale = null ) {
259
+ // checking for api errors.
260
+ $source_column = substr( $column, 9 );
261
+ $column_language_only = substr( $column, 0, 11 );
262
+ $errors = get_option( 'lingotek_log_errors' );
263
+
264
+ if ( $source_column === $source_locale ) {
265
+ if ( isset( $errors[ $object_id ] ) ) {
266
+ $api_error = Lingotek_Actions::retrieve_api_error( $errors[ $object_id ] );
267
+ $allowed_html = [
268
+ 'a' => [
269
+ 'href' => [],
270
+ 'class' => [],
271
+ 'title' => [],
272
+ ],
273
+ ];
274
+ echo wp_kses( Lingotek_Actions::display_error_icon( 'error', $api_error ), $allowed_html );
275
  }
276
  }
277
  }
admin/filters-media.php CHANGED
@@ -1,56 +1,63 @@
1
  <?php
2
 
3
- /*
4
  * Manages automatic upload
5
  *
6
  * @since 0.2
7
  */
8
  class Lingotek_Filters_Media extends PLL_Admin_Filters_Media {
9
- public $lgtm; // Lingotek model
 
 
 
 
 
10
 
11
- /*
12
  * Constructor
13
  *
14
  * @since 0.2
 
15
  */
16
- public function __construct(&$polylang) {
17
- parent::__construct($polylang);
18
 
19
  $this->lgtm = &$GLOBALS['wp_lingotek']->model;
20
 
21
- add_action('edit_attachment', array(&$this, 'edit_attachment'));
22
- add_action('add_attachment', array(&$this, 'add_attachment'), 11); // after Polylang
23
  }
24
 
25
- /*
26
- * marks the attachment as edited if needed
27
  *
28
  * @since 0.2
29
  *
30
- * @param int $post_id
31
  */
32
- public function edit_attachment($post_id) {
33
- $document = $this->lgtm->get_group('post', $post_id);
34
 
35
  // FIXME how to check if the attachment is really modified?
36
- if ($document && $post_id == $document->source) {
37
  $document->source_edited();
38
 
39
- if ($document->is_automatic_upload()) {
40
- $this->lgtm->upload_post($post_id);
41
  }
42
  }
43
  }
44
 
45
- /*
46
- * uploads an attachment when saved for the first time
47
  *
48
  * @since 0.2
49
 
50
- * @param int $post_id
51
  */
52
- public function add_attachment($post_id) {
53
- if ($this->model->is_translated_post_type('attachment') && 'automatic' == Lingotek_Model::get_profile_option('upload', 'attachment', PLL()->model->post->get_language($post_id)) && $this->lgtm->can_upload('post', $post_id))
54
- $this->lgtm->upload_post($post_id);
 
55
  }
56
  }
1
  <?php
2
 
3
+ /**
4
  * Manages automatic upload
5
  *
6
  * @since 0.2
7
  */
8
  class Lingotek_Filters_Media extends PLL_Admin_Filters_Media {
9
+ /**
10
+ * Lingotek model.
11
+ *
12
+ * @var object
13
+ */
14
+ public $lgtm;
15
 
16
+ /**
17
  * Constructor
18
  *
19
  * @since 0.2
20
+ * @param model $polylang polylang.
21
  */
22
+ public function __construct( &$polylang ) {
23
+ parent::__construct( $polylang );
24
 
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
+ /**
32
+ * Marks the attachment as edited if needed
33
  *
34
  * @since 0.2
35
  *
36
+ * @param int $post_id post id.
37
  */
38
+ public function edit_attachment( $post_id ) {
39
+ $document = $this->lgtm->get_group( 'post', $post_id );
40
 
41
  // FIXME how to check if the attachment is really modified?
42
+ if ( $document && $post_id === $document->source ) {
43
  $document->source_edited();
44
 
45
+ if ( $document->is_automatic_upload() ) {
46
+ $this->lgtm->upload_post( $post_id );
47
  }
48
  }
49
  }
50
 
51
+ /**
52
+ * Uploads an attachment when saved for the first time
53
  *
54
  * @since 0.2
55
 
56
+ * @param int $post_id post id.
57
  */
58
+ public function add_attachment( $post_id ) {
59
+ if ( $this->model->is_translated_post_type( 'attachment' ) && 'automatic' === Lingotek_Model::get_profile_option( 'upload', 'attachment', PLL()->model->post->get_language( $post_id ) ) && $this->lgtm->can_upload( 'post', $post_id ) ) {
60
+ $this->lgtm->upload_post( $post_id );
61
+ }
62
  }
63
  }
admin/filters-post.php CHANGED
@@ -99,6 +99,10 @@ class Lingotek_Filters_Post extends PLL_Admin_Filters_Post {
99
  $profile = $content_profiles[$post_type]['sources'][$post_language->slug];
100
  echo $profiles[$profile]['name'];
101
  }
 
 
 
 
102
  else if (!empty($content_profiles)) {
103
  echo $profiles[$content_profiles[$post_type]['profile']]['name'];
104
  }
@@ -139,7 +143,6 @@ class Lingotek_Filters_Post extends PLL_Admin_Filters_Post {
139
  // updated post
140
  if ($document && $post_id == $document->source && $this->post_hash_has_changed($post)) {
141
  $document->source_edited();
142
-
143
  if ($document->is_automatic_upload() && Lingotek_Group_Post::is_valid_auto_upload_post_status($post->post_status)) {
144
  $this->lgtm->upload_post($post_id);
145
  }
@@ -151,8 +154,7 @@ class Lingotek_Filters_Post extends PLL_Admin_Filters_Post {
151
  // new post
152
  if (!isset($_REQUEST['import'])) {
153
  parent::save_post($post_id, $post, $update);
154
-
155
- if (!wp_is_post_revision($post_id) && 'auto-draft' != $post->post_status && Lingotek_Group_Post::is_valid_auto_upload_post_status($post->post_status) && 'automatic' == Lingotek_Model::get_profile_option('upload', $post->post_type, PLL()->model->post->get_language($post_id), false, $post_id) && !(isset($_POST['action']) && 'heartbeat' == $_POST['action']) && $this->lgtm->can_upload('post', $post_id)) {
156
  $this->lgtm->upload_post($post_id);
157
  }
158
  }
99
  $profile = $content_profiles[$post_type]['sources'][$post_language->slug];
100
  echo $profiles[$profile]['name'];
101
  }
102
+ else if (!empty($content_profiles) && !isset($profiles[$content_profiles[$post_type]['profile']]['name']))
103
+ {
104
+ echo esc_html( __('Disabled', 'lingotek-translation') );
105
+ }
106
  else if (!empty($content_profiles)) {
107
  echo $profiles[$content_profiles[$post_type]['profile']]['name'];
108
  }
143
  // updated post
144
  if ($document && $post_id == $document->source && $this->post_hash_has_changed($post)) {
145
  $document->source_edited();
 
146
  if ($document->is_automatic_upload() && Lingotek_Group_Post::is_valid_auto_upload_post_status($post->post_status)) {
147
  $this->lgtm->upload_post($post_id);
148
  }
154
  // new post
155
  if (!isset($_REQUEST['import'])) {
156
  parent::save_post($post_id, $post, $update);
157
+ if (!wp_is_post_revision($post_id) && 'auto-draft' != $post->post_status && 'automatic' == Lingotek_Model::get_profile_option('upload', $post->post_type, PLL()->model->post->get_language($post_id), false, $post_id) && Lingotek_Group_Post::is_valid_auto_upload_post_status($post->post_status) && !(isset($_POST['action']) && 'heartbeat' == $_POST['action']) && $this->lgtm->can_upload('post', $post_id)) {
 
158
  $this->lgtm->upload_post($post_id);
159
  }
160
  }
admin/filters-term.php CHANGED
@@ -1,134 +1,159 @@
1
  <?php
2
 
3
- /*
4
  * Modifies Polylang filters
5
  * Manages automatic upload
6
  *
7
  * @since 0.2
8
  */
9
  class Lingotek_Filters_Term extends PLL_Admin_Filters_Term {
10
- public $lgtm; // Lingotek model
11
- protected $old_term; // used to save old md5sum of a term when it is edited
 
 
 
 
 
 
 
 
 
 
12
 
13
- /*
14
  * Constructor
15
  *
16
  * @since 0.2
 
17
  */
18
- public function __construct(&$polylang) {
19
- parent::__construct($polylang);
20
 
21
  $this->lgtm = &$GLOBALS['wp_lingotek']->model;
22
 
23
- add_action('edit_terms', array(&$this, 'save_old_term'), 10, 2);
24
- add_action('edited_term', array(&$this, 'edited_term'), 10, 3);
25
  }
26
 
27
- /*
28
- * controls whether to display the language metabox or not
29
  *
30
  * @since 0.2
 
31
  */
32
- public function edit_term_form($tag) {
33
- if ($this->model->is_translated_taxonomy($tag->taxonomy)) {
34
- $document = $this->lgtm->get_group('term', $tag->term_id);
35
- if (empty($document->source))
36
- parent::edit_term_form($tag);
 
37
  }
38
  }
39
 
40
- /*
41
- * uploads a term when saved for the first time
42
  *
43
  * @since 0.2
44
 
45
- * @param int $term_id
46
- * @param int $tt_id term taxononomy id
47
- * @param string $taxonomy
48
  */
49
- public function save_term($term_id, $tt_id, $taxonomy) {
50
- if (!$this->model->is_translated_taxonomy($taxonomy))
51
  return;
 
52
 
53
- if (!isset($_REQUEST['import'])) {
54
- parent::save_term($term_id, $tt_id, $taxonomy);
55
 
56
- if ('automatic' == Lingotek_Model::get_profile_option('upload', $taxonomy, PLL()->model->term->get_language($term_id)) && $this->lgtm->can_upload('term', $term_id))
57
- $this->lgtm->upload_term($term_id, $taxonomy); {
 
58
  }
59
  }
60
  }
61
 
62
- /*
63
- * saves the md5sum of a term before it is edited
64
  *
65
  * @since 0.2
66
  *
67
- * @param int $term_id
68
- * @param string $taxonomy
69
  */
70
- public function save_old_term($term_id, $taxonomy) {
71
- if (pll_is_translated_taxonomy($taxonomy))
72
- $this->old_term = md5(Lingotek_Group_Term::get_content(get_term($term_id, $taxonomy)));
 
73
  }
74
 
75
- /*
76
- * marks the term as edited if needed
77
  *
78
  * @since 0.2
79
  *
80
- * @param int $term_id
81
- * @param int $tt_id not used
82
- * @param string $taxonomy
83
  */
84
- public function edited_term($term_id, $tt_id, $taxonomy) {
85
- if (pll_is_translated_taxonomy($taxonomy)) {
86
- $document = $this->lgtm->get_group('term', $term_id);
87
 
88
- if ($document && $term_id == $document->source && md5(Lingotek_Group_Term::get_content(get_term($term_id, $taxonomy))) != $this->old_term) {
89
  $document->source_edited();
90
 
91
- if ($document->is_automatic_upload()) {
92
- $this->lgtm->upload_term($term_id, $taxonomy);
93
  }
94
  }
95
  }
96
  }
97
 
98
- /*
99
- * get translations ids to sync for delete
100
  * since we can't sync all translations as we get conflicts when attempting to act two times on the same
101
  *
102
  * @since 0.2
103
  *
104
- * @param int $term_id
105
  * @return array
106
  */
107
- protected function get_translations_to_sync($term_id) {
108
- // don't synchronize disassociated terms
109
- $group = $this->lgtm->get_group('term', $term_id);
110
- if (empty($group->source))
111
  return array();
 
112
 
113
- if (isset($_REQUEST['delete_tags']) && is_array($_REQUEST['delete_tags']))
114
- $term_ids = array_map('intval', $_REQUEST['delete_tags']);
 
 
 
 
 
 
 
 
115
 
116
  $term_ids[] = $term_id;
117
- return array_diff(PLL()->model->term->get_translations($term_id), $term_ids);
118
  }
119
 
120
- /*
121
- * deletes the Lingotek document when a source document is deleted
122
  *
123
  * @since 0.2
124
  *
125
- * @param int $term_id
126
  */
127
- public function delete_term($term_id) {
128
- $taxonomy = substr(current_filter(), 7);
129
- foreach ($this->get_translations_to_sync($term_id) as $tr_id) {
130
- wp_delete_term($tr_id, $taxonomy); // forces deletion for the translations which are not already in the list
131
  }
132
- $this->lgtm->delete_term($term_id);
133
  }
134
  }
1
  <?php
2
 
3
+ /**
4
  * Modifies Polylang filters
5
  * Manages automatic upload
6
  *
7
  * @since 0.2
8
  */
9
  class Lingotek_Filters_Term extends PLL_Admin_Filters_Term {
10
+ /**
11
+ * Lingotek model.
12
+ *
13
+ * @var object
14
+ */
15
+ public $lgtm;
16
+ /**
17
+ * Old term.
18
+ *
19
+ * @var string.
20
+ */
21
+ protected $old_term;
22
 
23
+ /**
24
  * Constructor
25
  *
26
  * @since 0.2
27
+ * @param object $polylang polylang model.
28
  */
29
+ public function __construct( &$polylang ) {
30
+ parent::__construct( $polylang );
31
 
32
  $this->lgtm = &$GLOBALS['wp_lingotek']->model;
33
 
34
+ add_action( 'edit_terms', array( &$this, 'save_old_term' ), 10, 2 );
35
+ add_action( 'edited_term', array( &$this, 'edited_term' ), 10, 3 );
36
  }
37
 
38
+ /**
39
+ * Controls whether to display the language metabox or not
40
  *
41
  * @since 0.2
42
+ * @param object $tag tag object.
43
  */
44
+ public function edit_term_form( $tag ) {
45
+ if ( $this->model->is_translated_taxonomy( $tag->taxonomy ) ) {
46
+ $document = $this->lgtm->get_group( 'term', $tag->term_id );
47
+ if ( empty( $document->source ) ) {
48
+ parent::edit_term_form( $tag );
49
+ }
50
  }
51
  }
52
 
53
+ /**
54
+ * Uploads a term when saved for the first time
55
  *
56
  * @since 0.2
57
 
58
+ * @param int $term_id id.
59
+ * @param int $tt_id term taxononomy id.
60
+ * @param string $taxonomy taxonomy.
61
  */
62
+ public function save_term( $term_id, $tt_id, $taxonomy ) {
63
+ if ( ! $this->model->is_translated_taxonomy( $taxonomy ) ) {
64
  return;
65
+ }
66
 
67
+ if ( empty( filter_input( INPUT_GET, 'import' ) ) && empty( filter_input( INPUT_POST, 'import' ) ) ) {
68
+ parent::save_term( $term_id, $tt_id, $taxonomy );
69
 
70
+ if ( 'automatic' === Lingotek_Model::get_profile_option( 'upload', $taxonomy, PLL()->model->term->get_language( $term_id ) ) && $this->lgtm->can_upload( 'term', $term_id ) ) {
71
+ $this->lgtm->upload_term( $term_id, $taxonomy );
72
+ } {
73
  }
74
  }
75
  }
76
 
77
+ /**
78
+ * Saves the md5sum of a term before it is edited
79
  *
80
  * @since 0.2
81
  *
82
+ * @param int $term_id term id.
83
+ * @param string $taxonomy taxonomy.
84
  */
85
+ public function save_old_term( $term_id, $taxonomy ) {
86
+ if ( pll_is_translated_taxonomy( $taxonomy ) ) {
87
+ $this->old_term = md5( Lingotek_Group_Term::get_content( get_term( $term_id, $taxonomy ) ) );
88
+ }
89
  }
90
 
91
+ /**
92
+ * Marks the term as edited if needed
93
  *
94
  * @since 0.2
95
  *
96
+ * @param int $term_id term id.
97
+ * @param int $tt_id not used.
98
+ * @param string $taxonomy taxonomy.
99
  */
100
+ public function edited_term( $term_id, $tt_id, $taxonomy ) {
101
+ if ( pll_is_translated_taxonomy( $taxonomy ) ) {
102
+ $document = $this->lgtm->get_group( 'term', $term_id );
103
 
104
+ if ( $document && $term_id === $document->source && md5( Lingotek_Group_Term::get_content( get_term( $term_id, $taxonomy ) ) ) !== $this->old_term ) {
105
  $document->source_edited();
106
 
107
+ if ( $document->is_automatic_upload() ) {
108
+ $this->lgtm->upload_term( $term_id, $taxonomy );
109
  }
110
  }
111
  }
112
  }
113
 
114
+ /**
115
+ * Get translations ids to sync for delete
116
  * since we can't sync all translations as we get conflicts when attempting to act two times on the same
117
  *
118
  * @since 0.2
119
  *
120
+ * @param int $term_id term id.
121
  * @return array
122
  */
123
+ protected function get_translations_to_sync( $term_id ) {
124
+ // don't synchronize disassociated terms.
125
+ $group = $this->lgtm->get_group( 'term', $term_id );
126
+ if ( empty( $group->source ) ) {
127
  return array();
128
+ }
129
 
130
+ $delete_tags = null;
131
+ if ( ! empty( filter_input( INPUT_GET, 'delete_tags' ) ) ) {
132
+ $delete_tags = filter_input( INPUT_GET, 'delete_tags' );
133
+ } elseif ( ! empty( filter_input( INPUT_POST, 'delete_tags' ) ) ) {
134
+ $delete_tags = filter_input( INPUT_POST, 'delete_tags' );
135
+ }
136
+
137
+ if ( isset( $delete_tags ) && is_array( $delete_tags ) ) {
138
+ $term_ids = array_map( 'intval', $delete_tags );
139
+ }
140
 
141
  $term_ids[] = $term_id;
142
+ return array_diff( PLL()->model->term->get_translations( $term_id ), $term_ids );
143
  }
144
 
145
+ /**
146
+ * Deletes the Lingotek document when a source document is deleted
147
  *
148
  * @since 0.2
149
  *
150
+ * @param int $term_id term id.
151
  */
152
+ public function delete_term( $term_id ) {
153
+ $taxonomy = substr( current_filter(), 7 );
154
+ foreach ( $this->get_translations_to_sync( $term_id ) as $tr_id ) {
155
+ wp_delete_term( $tr_id, $taxonomy ); // forces deletion for the translations which are not already in the list.
156
  }
157
+ $this->lgtm->delete_term( $term_id );
158
  }
159
  }
admin/manage/view-content.php CHANGED
@@ -78,7 +78,7 @@ else {
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 ? 'automatic' : 'manual') : $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'];
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 ? 'automatic' : ('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'];
admin/manage/view-strings.php CHANGED
@@ -1,4 +1,4 @@
1
- <h3 style="padding-top:0; margin-top:0; margin-bottom:-25px;"><?php _e('Strings', 'lingotek-translation'); ?> <a href="options-general.php?page=mlang&amp;tab=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();
@@ -40,7 +40,7 @@ $string_table = new Lingotek_Table_String(compact('languages', 'groups', 'select
40
  $string_table->prepare_items($data); ?>
41
 
42
  <div class="form-wrap">
43
- <form id="string-translation" method="post" action="admin.php?page=mlang&amp;tab=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');
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();
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');
admin/post-actions.php CHANGED
@@ -1,151 +1,163 @@
1
  <?php
2
 
3
- /*
4
  * Adds row and bulk actions to posts, pages and media list
5
  * Manages actions which trigger communication with Lingotek TMS
6
-
7
  *
8
  * @since 0.2
9
  */
10
  class Lingotek_Post_actions extends Lingotek_Actions {
11
 
12
- /*
13
  * Constructor
14
  *
15
  * @since 0.2
16
  */
17
  public function __construct() {
18
- parent::__construct('post');
 
 
 
 
 
 
 
 
 
19
 
20
- // row actions
21
- add_filter('post_row_actions', array(&$this, 'post_row_actions'), 10, 2);
22
- add_filter('page_row_actions', array(&$this, 'post_row_actions'), 10, 2); // hierarchical post types
23
- add_filter('media_row_actions', array(&$this, 'post_row_actions'), 10, 2);
24
 
25
- // add bulk actions
26
- add_action('admin_footer-edit.php', array(&$this, 'add_bulk_actions')); // FIXME admin_print_footer_scripts instead?
27
- add_action('admin_footer-upload.php', array(&$this, 'add_bulk_actions'));
28
 
29
- // manage bulk actions, row actions and icon actions
30
- add_action('load-edit.php', array(&$this, 'manage_actions'));
31
- add_action('load-upload.php', array(&$this, 'manage_actions'));
32
 
33
- // add meta box on post and page edit pages, and hook on save
34
- add_action('add_meta_boxes', array(&$this, 'lingotek_add_meta_boxes'));
35
- add_action('save_post', array(&$this, 'lingotek_save_meta_boxes'));
36
  }
37
 
38
- /*
39
- * get the language of a post
40
  *
41
  * @since 0.2
42
  *
43
  * @param int $post_id
44
  * @return object
45
  */
46
- protected function get_language($post_id) {
47
- return PLL()->model->post->get_language($post_id);
48
  }
49
 
50
- /*
51
- * displays the icon of an uploaded post with the relevant link
52
  *
53
  * @since 0.2
54
  *
55
  * @param int $id
56
  */
57
- public static function uploaded_icon($id) {
58
- return self::display_icon('uploaded', get_edit_post_link($id));
59
  }
60
 
61
- /*
62
- * adds a row action link
63
  *
64
  * @since 0.1
65
  *
66
- * @param array $actions list of action links
67
- * @param object $post
68
  * @return array
69
  */
70
- public function post_row_actions($actions, $post) {
71
- if ($this->pllm->is_translated_post_type($post->post_type)) {
72
- $actions = $this->_row_actions($actions, $post->ID);
73
-
74
- $language = PLL()->model->post->get_language($post->ID);
75
- if (!empty($language)) {
76
- $profile = Lingotek_Model::get_profile($post->post_type, $language, $post->ID);
77
- if ('disabled' == $profile['profile'])
78
- unset($actions['lingotek-upload']);
 
79
  }
80
  }
81
  return $actions;
82
  }
83
 
84
- /*
85
- * adds actions to bulk dropdown in posts list table
86
  *
87
  * @since 0.1
88
  */
89
- public function add_bulk_actions() {
90
- if (isset($GLOBALS['post_type']) && $this->pllm->is_translated_post_type($GLOBALS['post_type']))
91
- $this->_add_bulk_actions();
 
92
  }
93
 
94
- /*
95
- * manages Lingotek specific actions before WordPress acts
96
  *
97
  * @since 0.1
98
  */
99
  public function manage_actions() {
100
  global $typenow;
101
- $post_type = 'load-upload.php' == current_filter() ? 'attachment' : $typenow;
102
 
103
- if (!$this->pllm->is_translated_post_type($post_type))
104
  return;
 
105
 
106
- // get the action
107
- // $typenow is empty for media
108
- $wp_list_table = _get_list_table(empty($typenow) ? 'WP_Media_List_Table' : 'WP_Posts_List_Table');
109
  $action = $wp_list_table->current_action();
110
 
111
- if (empty($action))
112
  return;
 
113
 
114
- $redirect = remove_query_arg( array('action', 'action2', 'tags_input', 'post_author', 'comment_status', 'ping_status', '_status', 'post', 'bulk_edit', 'post_view'), wp_get_referer() );
115
- if (!$redirect)
116
- $redirect = admin_url("edit.php?post_type=$typenow");
 
117
 
118
- switch($action) {
119
  case 'bulk-lingotek-upload':
120
- $type = empty($typenow) ? 'media' : 'post';
121
- if (empty($_REQUEST[$type]))
 
122
  return;
 
123
 
124
  $post_ids = array();
125
 
126
- foreach (array_map('intval', $_REQUEST[$type]) as $post_id) {
127
- // safe upload
128
- if ($this->lgtm->can_upload('post', $post_id))
129
  $post_ids[] = $post_id;
130
-
131
- // the document is already translated so will be overwritten
132
- elseif(($document = $this->lgtm->get_group('post', $post_id)) && empty($document->source)) {
133
- // take care to upload only one post in a translation group
134
- $intersect = array_intersect($post_ids, PLL()->model->post->get_translations($post_id));
135
- if (empty($intersect)) {
136
  $post_ids[] = $post_id;
137
- $redirect = add_query_arg('lingotek_warning', 1, $redirect);
138
  }
139
  }
140
  }
141
 
142
- // check if translation is disabled
143
- if (!empty($post_ids)) {
144
- foreach ($post_ids as $key => $post_id) {
145
- $language = PLL()->model->post->get_language($post_id);
146
- $profile = Lingotek_Model::get_profile($post_type, $language);
147
- if ('disabled' == $profile['profile'])
148
- unset($post_ids[$key]);
 
149
  }
150
  }
151
 
@@ -153,192 +165,226 @@ class Lingotek_Post_actions extends Lingotek_Actions {
153
  case 'bulk-lingotek-download':
154
  case 'bulk-lingotek-status':
155
  case 'bulk-lingotek-delete':
156
- if (empty($post_ids)) {
157
- $type = empty($typenow) ? 'media' : 'post';
158
- if (empty($_REQUEST[$type]))
 
159
  return;
 
160
 
161
- $post_ids = array_map('intval', $_REQUEST[$type]);
162
  }
163
 
164
- empty($typenow) ? check_admin_referer('bulk-media') : check_admin_referer('bulk-posts');
165
 
166
- $redirect = add_query_arg($action, 1, $redirect);
167
- $redirect = add_query_arg('ids', implode(',', $post_ids), $redirect);
168
 
169
  break;
170
 
171
  case 'lingotek-upload':
172
- check_admin_referer('lingotek-upload');
173
- $this->lgtm->upload_post((int) $_GET['post']);
174
  break;
175
 
176
  case 'lingotek-copy':
177
- check_admin_referer('lingotek-copy');
178
- $post = get_post((int) $_GET['post']);
179
- $target = $_GET['target'];
180
- $this->lgtm->copy_post($post, $target);
181
  break;
182
 
183
  default:
184
- if (!$this->_manage_actions($action))
185
- return; // do not redirect if this is not one of our actions
186
-
187
  }
188
 
189
- wp_redirect($redirect);
190
  exit();
191
 
192
  }
193
 
194
- /*
195
- * ajax response to upload documents and showing progress
196
  *
197
  * @since 0.1
198
  */
199
  public function ajax_upload() {
200
- check_ajax_referer('lingotek_progress', '_lingotek_nonce');
201
- $this->lgtm->upload_post((int) $_POST['id']);
202
  die();
203
  }
204
 
205
- /*
206
- * adds the lingotek profile meta box on edit pages
207
- *
208
  * @since 0.1
209
- */
210
  public function lingotek_add_meta_boxes() {
211
  global $post;
212
  $lgtm = new Lingotek_Model();
213
- $group = $lgtm->get_group($post->post_type, $post->ID);
214
 
215
- // if it's a new page, $group will be null, so don't check if it's a source page
216
- if ($group) {
217
  $desc_array = $group->desc_array;
218
  $source_id = $desc_array['lingotek']['source'];
219
- // only display the meta box if it's a source
220
- if (isset($desc_array['lingotek']['source']) && $post->ID != $source_id) {
221
  return;
222
  }
223
  }
224
 
 
 
 
 
 
 
225
  add_meta_box('lingotek_post_meta_box', __('Lingotek Translation', 'lingotek-translation'), array( __CLASS__, 'lingotek_edit_meta_box_html'), 'post', 'side', 'default');
226
  add_meta_box('lingotek_page_meta_box', __('Lingotek Translation', 'lingotek-translation'), array( __CLASS__, 'lingotek_edit_meta_box_html'), 'page', 'side', 'default');
227
  }
228
 
229
- /*
230
- * builds the html for the edit post and edit page meta boxes
231
  *
232
  * @since 0.1
233
  */
234
  public static function lingotek_edit_meta_box_html() {
235
- wp_enqueue_script('lingotek_defaults', LINGOTEK_URL .'/js/defaults.js');
236
 
237
  global $post;
238
- $post_type = get_post_type($post->ID);
239
  $lgtm = new Lingotek_Model();
240
- $group = $lgtm->get_group('post', $post->ID);
241
  $profiles = Lingotek::get_profiles();
242
  $content_profiles = get_option('lingotek_content_type');
243
  $language_profiles = self::retrieve_lang_Profiles($post_type, $profiles, $content_profiles);
244
  $default_name = empty($content_profiles) == false ? $profiles[$content_profiles[$post->post_type]['profile']]['name'] : ($post_type == 'page' ? __('Manual', 'lingotek-translation') : __('Automatic', 'lingotek-translation'));
 
 
 
 
 
245
  $content_default_profile = array('default' => array(
246
  'name' => __('Content Default', 'lingotek-translation') . ' (' . $default_name . ')', // Adds in the name of the content type default profile
247
  ));
 
248
  $language_profiles['defaults'] = array(
249
  'content_default' => $default_name,
250
- 'title' => __('Content Default', 'lingotek-translation'),
251
  );
252
- $profiles = array_merge($content_default_profile, $profiles);
253
- $post_profile = self::get_post_profile($post->ID);
254
- if (isset($post_profile)) {
255
- $selected[$post_profile->description] = $profiles[$post_profile->description];
256
- unset($profiles[$post_profile->description]);
257
- $profiles = array_merge($selected, $profiles);
258
  }
259
 
260
- if (isset($group->source)) { // Disables selection of a different profile if content has been uploaded to Lingotek
261
  $args = array(
262
  'document_id' => $group->document_id,
263
  'action' => 'lingotek-delete',
264
  'noheader' => true,
265
  );
266
- if ($post_type == 'page') {
267
  $args['lingotek_redirect'] = true;
268
  }
269
  $site_id = get_current_blog_id();
270
- $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');
271
- $disassociate_url = wp_nonce_url(add_query_arg($args, $url), 'lingotek-delete');
272
  $remove_post = 'post=' . $post->ID;
273
- $disassociate_url = str_replace($remove_post, '', $disassociate_url);
274
  $prefs = Lingotek_Model::get_prefs();
275
- $confirm_message = isset($prefs['delete_document_from_tms']) === false ? __('Are you sure you want to do this?', 'lingotek-translation') : __('Are you sure you want to do this? The document will be deleted from Lingotek TMS.', 'lingotek-translation');
276
- $confirm_message = sprintf(' onclick = "return confirm(\'%s\');"', $confirm_message);
277
- printf('<strong>%s</strong><br><br>', __('Translation Profile', 'lingotek-translation'));
278
- printf('<em>%s</em><br>', __('Disassociate this content to change the Translation Profile', 'lingotek-translation'));
279
- printf(('<a class="button button-small" href="%s" %s>%s</a><br><br>'), esc_url($disassociate_url), $confirm_message, __('Disassociate', 'lingotek-translation'));
280
- printf('<select disabled class="lingotek-profile-setting" name="%1$s" id="%1$s">', 'lingotek_profile_meta');
281
- }
282
- else {
283
- printf('<strong>%s</strong><br><br>', __('Translation Profile', 'lingotek-translation'));
284
- printf('<select class="lingotek-profile-setting" name="%1$s" id="%1$s">', 'lingotek_profile_meta');
285
  }
286
 
287
- foreach ($profiles as $key => $profile) {
288
- echo "\n\t<option value=" . esc_attr($key) . ">" . esc_attr($profile['name']) . '</option>';
289
  }
290
  echo '</select>';
291
- echo '<div id="lingotek-language-profiles" style="display: none;">'.json_encode($language_profiles).'</div>';
292
  }
293
 
294
  public function lingotek_save_meta_boxes() {
295
- if (!isset($_POST['lingotek_profile_meta'])) {
296
  return;
297
  }
298
 
299
  global $post;
300
- $profile_choice = $_POST['lingotek_profile_meta'];
301
  $document_id = 'lingotek_profile_' . $post->ID;
302
- $term = self::get_post_profile($post->ID);
303
- $post_language = $this->get_language($post->ID);
304
- $content_profiles = get_option('lingotek_content_type');
305
-
306
- if ($profile_choice == 'default' && !empty($term)) {
307
- wp_delete_term((int) $term->term_id, 'lingotek_profile');
308
- }
309
- elseif ($profile_choice != 'default') {
310
- if (empty($term)) {
311
- wp_insert_term($document_id, 'lingotek_profile', array('description' => $profile_choice));
312
- }
313
- else {
314
- wp_update_term((int) $term->term_id, 'lingotek_profile', array('description' => $profile_choice));
315
  }
316
 
317
- wp_set_object_terms($post->ID, $document_id, 'lingotek_profile');
318
  }
319
  }
320
 
321
- public static function get_post_profile($post_id) {
322
- if (taxonomy_exists('lingotek_profile')) {
323
- $terms = wp_get_object_terms($post_id, 'lingotek_profile');
324
- $term = array_pop($terms);
325
- return $term;
326
- }
327
- else {
 
 
328
  return 'false';
329
  }
330
  }
331
 
332
- public static function retrieve_lang_Profiles($post_type, $profiles, $content_profiles) {
333
  $language_profiles = array();
334
 
335
- if(isset($content_profiles[$post_type]['sources'])) {
336
- $sources = $content_profiles[$post_type]['sources'];
337
- foreach($sources as $lang_code => $profile) {
338
- $language_profiles[$lang_code] = $profiles[$profile]['name'];
339
- }
340
  }
341
 
342
  return $language_profiles;
343
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
344
  }
1
  <?php
2
 
3
+ /**
4
  * Adds row and bulk actions to posts, pages and media list
5
  * Manages actions which trigger communication with Lingotek TMS
 
6
  *
7
  * @since 0.2
8
  */
9
  class Lingotek_Post_actions extends Lingotek_Actions {
10
 
11
+ /**
12
  * Constructor
13
  *
14
  * @since 0.2
15
  */
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
+ $add_bulk_actions_to_custom_post_types = function($type) {
29
+ add_filter( "bulk_actions-edit-$type", array( &$this, 'add_bulk_actions' ) );
30
+ };
 
31
 
32
+ $this->iterate_custom_post_types($add_bulk_actions_to_custom_post_types);
 
 
33
 
34
+ // manage bulk actions, row actions and icon actions.
35
+ add_action( 'load-edit.php', array( &$this, 'manage_actions' ) );
36
+ add_action( 'load-upload.php', array( &$this, 'manage_actions' ) );
37
 
38
+ // add meta box on post and page edit pages, and hook on save.
39
+ add_action( 'add_meta_boxes', array( &$this, 'lingotek_add_meta_boxes' ) );
40
+ add_action( 'save_post', array( &$this, 'lingotek_save_meta_boxes' ) );
41
  }
42
 
43
+ /**
44
+ * Get the language of a post
45
  *
46
  * @since 0.2
47
  *
48
  * @param int $post_id
49
  * @return object
50
  */
51
+ protected function get_language( $post_id ) {
52
+ return PLL()->model->post->get_language( $post_id );
53
  }
54
 
55
+ /**
56
+ * Displays the icon of an uploaded post with the relevant link
57
  *
58
  * @since 0.2
59
  *
60
  * @param int $id
61
  */
62
+ public static function uploaded_icon( $id ) {
63
+ return self::display_icon( 'uploaded', get_edit_post_link( $id ) );
64
  }
65
 
66
+ /**
67
+ * Adds a row action link
68
  *
69
  * @since 0.1
70
  *
71
+ * @param array $actions list of action links.
72
+ * @param object $post post object.
73
  * @return array
74
  */
75
+ public function post_row_actions( $actions, $post ) {
76
+ if ( $this->pllm->is_translated_post_type( $post->post_type ) ) {
77
+ $actions = $this->_row_actions( $actions, $post->ID );
78
+
79
+ $language = PLL()->model->post->get_language( $post->ID );
80
+ if ( ! empty( $language ) ) {
81
+ $profile = Lingotek_Model::get_profile( $post->post_type, $language, $post->ID );
82
+ if ( 'disabled' === $profile['profile'] ) {
83
+ unset( $actions['lingotek-upload'] );
84
+ }
85
  }
86
  }
87
  return $actions;
88
  }
89
 
90
+ /**
91
+ * Adds actions to bulk dropdown in posts list table
92
  *
93
  * @since 0.1
94
  */
95
+ public function add_bulk_actions( $bulk_actions ) {
96
+ if ( isset( $GLOBALS['post_type'] ) && $this->pllm->is_translated_post_type( $GLOBALS['post_type'] ) ) {
97
+ return $this->_add_bulk_actions( $bulk_actions );
98
+ }
99
  }
100
 
101
+ /**
102
+ * Manages Lingotek specific actions before WordPress acts
103
  *
104
  * @since 0.1
105
  */
106
  public function manage_actions() {
107
  global $typenow;
108
+ $post_type = 'load-upload.php' === current_filter() ? 'attachment' : $typenow;
109
 
110
+ if ( ! $this->pllm->is_translated_post_type( $post_type ) ) {
111
  return;
112
+ }
113
 
114
+ // get the action.
115
+ // $typenow is empty for media.
116
+ $wp_list_table = _get_list_table( empty( $typenow ) ? 'WP_Media_List_Table' : 'WP_Posts_List_Table' );
117
  $action = $wp_list_table->current_action();
118
 
119
+ if ( empty( $action ) ) {
120
  return;
121
+ }
122
 
123
+ $redirect = remove_query_arg( array( 'action', 'action2', 'tags_input', 'post_author', 'comment_status', 'ping_status', '_status', 'post', 'bulk_edit', 'post_view' ), wp_get_referer() );
124
+ if ( ! $redirect ) {
125
+ $redirect = admin_url( "edit.php?post_type=$typenow" );
126
+ }
127
 
128
+ switch ( $action ) {
129
  case 'bulk-lingotek-upload':
130
+ $type = empty( $typenow ) ? 'media' : 'post';
131
+ $filtered_get = filter_input_array( INPUT_GET );
132
+ if ( ! isset( $filtered_get[ $type ] ) ) {
133
  return;
134
+ }
135
 
136
  $post_ids = array();
137
 
138
+ foreach ( array_map( 'intval', $filtered_get[ $type ] ) as $post_id ) {
139
+ // safe upload.
140
+ if ( $this->lgtm->can_upload( 'post', $post_id ) ) {
141
  $post_ids[] = $post_id;
142
+ } // the document is already translated so will be overwritten.
143
+ elseif ( ($document = $this->lgtm->get_group( 'post', $post_id )) && empty( $document->source ) ) {
144
+ // take care to upload only one post in a translation group.
145
+ $intersect = array_intersect( $post_ids, PLL()->model->post->get_translations( $post_id ) );
146
+ if ( empty( $intersect ) ) {
 
147
  $post_ids[] = $post_id;
148
+ $redirect = add_query_arg( 'lingotek_warning', 1, $redirect );
149
  }
150
  }
151
  }
152
 
153
+ // check if translation is disabled.
154
+ if ( ! empty( $post_ids ) ) {
155
+ foreach ( $post_ids as $key => $post_id ) {
156
+ $language = PLL()->model->post->get_language( $post_id );
157
+ $profile = Lingotek_Model::get_profile( $post_type, $language );
158
+ if ( 'disabled' === $profile['profile'] ) {
159
+ unset( $post_ids[ $key ] );
160
+ }
161
  }
162
  }
163
 
165
  case 'bulk-lingotek-download':
166
  case 'bulk-lingotek-status':
167
  case 'bulk-lingotek-delete':
168
+ if ( empty( $post_ids ) ) {
169
+ $type = empty( $typenow ) ? 'media' : 'post';
170
+ $filtered_get = filter_input_array( INPUT_GET );
171
+ if ( ! isset( $filtered_get[ $type ] ) ) {
172
  return;
173
+ }
174
 
175
+ $post_ids = array_map( 'intval', $filtered_get[ $type ] );
176
  }
177
 
178
+ empty( $typenow ) ? check_admin_referer( 'bulk-media' ) : check_admin_referer( 'bulk-posts' );
179
 
180
+ $redirect = add_query_arg( $action, 1, $redirect );
181
+ $redirect = add_query_arg( 'ids', implode( ',', $post_ids ), $redirect );
182
 
183
  break;
184
 
185
  case 'lingotek-upload':
186
+ check_admin_referer( 'lingotek-upload' );
187
+ $this->lgtm->upload_post( (int) filter_input( INPUT_GET, 'post' ) );
188
  break;
189
 
190
  case 'lingotek-copy':
191
+ check_admin_referer( 'lingotek-copy' );
192
+ $post_to_copy = get_post( (int) filter_input( INPUT_GET, 'post' ) );
193
+ $target = filter_input( INPUT_GET, 'target' );
194
+ $this->lgtm->copy_post( $post_to_copy, $target );
195
  break;
196
 
197
  default:
198
+ if ( ! $this->_manage_actions( $action ) ) {
199
+ return; // do not redirect if this is not one of our actions.
200
+ }
201
  }
202
 
203
+ wp_safe_redirect( $redirect );
204
  exit();
205
 
206
  }
207
 
208
+ /**
209
+ * Ajax response to upload documents and showing progress
210
  *
211
  * @since 0.1
212
  */
213
  public function ajax_upload() {
214
+ check_ajax_referer( 'lingotek_progress', '_lingotek_nonce' );
215
+ $this->lgtm->upload_post( (int) filter_input( INPUT_POST, 'id' ) );
216
  die();
217
  }
218
 
219
+ /**
220
+ * Adds the lingotek profile meta box on edit pages
221
+ *
222
  * @since 0.1
223
+ */
224
  public function lingotek_add_meta_boxes() {
225
  global $post;
226
  $lgtm = new Lingotek_Model();
227
+ $group = $lgtm->get_group( $post->post_type, $post->ID );
228
 
229
+ // if it's a new page, $group will be null, so don't check if it's a source page.
230
+ if ( $group ) {
231
  $desc_array = $group->desc_array;
232
  $source_id = $desc_array['lingotek']['source'];
233
+ // only display the meta box if it's a source.
234
+ if ( isset( $desc_array['lingotek']['source'] ) && $post->ID !== $source_id ) {
235
  return;
236
  }
237
  }
238
 
239
+ $add_meta_box_to_custom_post_types = function($type) {
240
+ add_meta_box('lingotek_post_meta_box', __('Lingotek Translation', 'lingotek-translation'), array( __CLASS__, 'lingotek_edit_meta_box_html'), $type, 'side', 'default');
241
+ };
242
+
243
+ $this->iterate_custom_post_types($add_meta_box_to_custom_post_types);
244
+
245
  add_meta_box('lingotek_post_meta_box', __('Lingotek Translation', 'lingotek-translation'), array( __CLASS__, 'lingotek_edit_meta_box_html'), 'post', 'side', 'default');
246
  add_meta_box('lingotek_page_meta_box', __('Lingotek Translation', 'lingotek-translation'), array( __CLASS__, 'lingotek_edit_meta_box_html'), 'page', 'side', 'default');
247
  }
248
 
249
+ /**
250
+ * Builds the html for the edit post and edit page meta boxes.
251
  *
252
  * @since 0.1
253
  */
254
  public static function lingotek_edit_meta_box_html() {
255
+ wp_enqueue_script( 'lingotek_defaults', LINGOTEK_URL . '/js/defaults.js' );
256
 
257
  global $post;
258
+ $post_type = get_post_type( $post->ID );
259
  $lgtm = new Lingotek_Model();
260
+ $group = $lgtm->get_group( 'post', $post->ID );
261
  $profiles = Lingotek::get_profiles();
262
  $content_profiles = get_option('lingotek_content_type');
263
  $language_profiles = self::retrieve_lang_Profiles($post_type, $profiles, $content_profiles);
264
  $default_name = empty($content_profiles) == false ? $profiles[$content_profiles[$post->post_type]['profile']]['name'] : ($post_type == 'page' ? __('Manual', 'lingotek-translation') : __('Automatic', 'lingotek-translation'));
265
+ if ( ! isset( $default_name ) || 'disabled' === $default_name )
266
+ {
267
+ echo esc_html( __('You must enable translation for this content type in Lingotek\'s Content Type Configuration to enable Translation Profiles.', 'lingotek-translation') );
268
+ return;
269
+ }
270
  $content_default_profile = array('default' => array(
271
  'name' => __('Content Default', 'lingotek-translation') . ' (' . $default_name . ')', // Adds in the name of the content type default profile
272
  ));
273
+
274
  $language_profiles['defaults'] = array(
275
  'content_default' => $default_name,
276
+ 'title' => __( 'Content Default', 'lingotek-translation' ),
277
  );
278
+ $profiles = array_merge( $content_default_profile, $profiles );
279
+ $post_profile = self::get_post_profile( $post->ID );
280
+ if ( isset( $post_profile ) ) {
281
+ $selected[ $post_profile->description ] = $profiles[ $post_profile->description ];
282
+ unset( $profiles[ $post_profile->description ] );
283
+ $profiles = array_merge( $selected, $profiles );
284
  }
285
 
286
+ if ( isset( $group->source ) ) { // Disables selection of a different profile if content has been uploaded to Lingotek.
287
  $args = array(
288
  'document_id' => $group->document_id,
289
  'action' => 'lingotek-delete',
290
  'noheader' => true,
291
  );
292
+ if ( $post_type === 'page' ) {
293
  $args['lingotek_redirect'] = true;
294
  }
295
  $site_id = get_current_blog_id();
296
+ $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' );
297
+ $disassociate_url = wp_nonce_url( add_query_arg( $args, $url ), 'lingotek-delete' );
298
  $remove_post = 'post=' . $post->ID;
299
+ $disassociate_url = str_replace( $remove_post, '', $disassociate_url );
300
  $prefs = Lingotek_Model::get_prefs();
301
+ $confirm_message = isset( $prefs['delete_document_from_tms'] ) === false ? __( 'Are you sure you want to do this?', 'lingotek-translation' ) : __( 'Are you sure you want to do this? The document will be deleted from Lingotek TMS.', 'lingotek-translation' );
302
+ $confirm_message = sprintf( ' onclick = "return confirm(\'%s\');"', esc_html( $confirm_message ) );
303
+ printf( '<strong>%s</strong><br><br>', esc_html( __( 'Translation Profile', 'lingotek-translation' ) ) );
304
+ printf( '<em>%s</em><br>', esc_html( __( 'Disassociate this content to change the Translation Profile', 'lingotek-translation' ) ) );
305
+ printf( ('<a class="button button-small" href="%s" %s>%s</a><br><br>'), esc_url( $disassociate_url ), esc_html( $confirm_message ), esc_html( __( 'Disassociate', 'lingotek-translation' ) ) );
306
+ printf( '<select disabled class="lingotek-profile-setting" name="%1$s" id="%1$s">', esc_html( 'lingotek_profile_meta' ) );
307
+ } else {
308
+ printf( '<strong>%s</strong><br><br>', esc_html( __( 'Translation Profile', 'lingotek-translation' ) ) );
309
+ printf( '<select class="lingotek-profile-setting" name="%1$s" id="%1$s">', 'lingotek_profile_meta' );
 
310
  }
311
 
312
+ foreach ( $profiles as $key => $profile ) {
313
+ echo "\n\t<option value=" . esc_attr( $key ) . '>' . esc_attr( $profile['name'] ) . '</option>';
314
  }
315
  echo '</select>';
316
+ echo '<div id="lingotek-language-profiles" style="display: none;">' . wp_json_encode( $language_profiles ) . '</div>';
317
  }
318
 
319
  public function lingotek_save_meta_boxes() {
320
+ if ( null === filter_input( INPUT_POST, 'lingotek_profile_meta' ) ) {
321
  return;
322
  }
323
 
324
  global $post;
325
+ $profile_choice = filter_input( INPUT_POST, 'lingotek_profile_meta' );
326
  $document_id = 'lingotek_profile_' . $post->ID;
327
+ $term = self::get_post_profile( $post->ID );
328
+ $post_language = $this->get_language( $post->ID );
329
+ $content_profiles = get_option( 'lingotek_content_type' );
330
+
331
+ if ( $profile_choice === 'default' && ! empty( $term ) ) {
332
+ wp_delete_term( (int) $term->term_id, 'lingotek_profile' );
333
+ } elseif ( $profile_choice !== 'default' ) {
334
+ if ( empty( $term ) ) {
335
+ wp_insert_term( $document_id, 'lingotek_profile', array( 'description' => $profile_choice ) );
336
+ } else {
337
+ wp_update_term( (int) $term->term_id, 'lingotek_profile', array( 'description' => $profile_choice ) );
 
 
338
  }
339
 
340
+ wp_set_object_terms( $post->ID, $document_id, 'lingotek_profile' );
341
  }
342
  }
343
 
344
+ public static function get_post_profile( $post_id ) {
345
+ if ( taxonomy_exists( 'lingotek_profile' ) ) {
346
+ $terms = get_the_terms( $post_id, 'lingotek_profile' );
347
+ if ( is_array( $terms ) ) {
348
+ return array_pop( $terms );
349
+ } else {
350
+ return null;
351
+ }
352
+ } else {
353
  return 'false';
354
  }
355
  }
356
 
357
+ public static function retrieve_lang_Profiles( $post_type, $profiles, $content_profiles ) {
358
  $language_profiles = array();
359
 
360
+ if ( isset( $content_profiles[ $post_type ]['sources'] ) ) {
361
+ $sources = $content_profiles[ $post_type ]['sources'];
362
+ foreach ( $sources as $lang_code => $profile ) {
363
+ $language_profiles[ $lang_code ] = $profiles[ $profile ]['name'];
364
+ }
365
  }
366
 
367
  return $language_profiles;
368
  }
369
+
370
+ /**
371
+ * Iterates through the enabled custom post types and passes in the type to a provided anonymous method.
372
+ * The provided method is only called if the custom post type has been enabled by Polylong.
373
+ *
374
+ * @param function $method the method to be called. Must take in a single parameter (type)
375
+ */
376
+ private function iterate_custom_post_types($method)
377
+ {
378
+ $polylang_enabled = PLL()->model->get_translated_post_types();
379
+ $custom_post_types = get_post_types( [ '_builtin' => false ] );
380
+ unset( $custom_post_types[ 'polylang_mo' ] );
381
+
382
+ foreach ( $custom_post_types as $type )
383
+ {
384
+ if (isset($polylang_enabled[$type]))
385
+ {
386
+ $method($type);
387
+ }
388
+ }
389
+ }
390
  }
admin/profiles-table.php CHANGED
@@ -1,81 +1,86 @@
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
  class Lingotek_Profiles_Table extends WP_List_Table {
8
 
9
- /*
10
- * constructor
11
  *
12
  * @since 0.2
13
  */
14
  function __construct() {
15
  parent::__construct(array(
16
- 'plural' => 'lingotek-profiles', // do not translate (used for css class)
17
- 'ajax' => false
18
  ));
19
  }
20
 
21
- /*
22
- * displays the item information in a column (default case)
23
  *
24
  * @since 0.2
25
  *
26
- * @param array $item
27
- * @param string $column_name
28
  * @return string
29
  */
30
- function column_default($item, $column_name) {
31
- return isset($item[$column_name]) ? esc_html($item[$column_name]) : '';
32
  }
33
 
34
- /*
35
- * displays the edit link in actions column
36
  *
37
  * @since 0.2
38
  *
39
- * @param array $item
40
  * @return string
41
  */
42
- function column_usage($item){
43
- return empty($item['usage']) ?
44
- __('No content types', 'lingotek-translation') :
45
- sprintf(_n('1 content type', '%d content types', $item['usage'], 'lingotek-translation'), number_format_i18n($item['usage']));
46
  }
47
 
48
- /*
49
- * displays the edit link in actions column
50
  *
51
  * @since 0.2
52
  *
53
- * @param array $item
54
  * @return string
55
  */
56
- function column_actions($item){
57
  $actions = array();
58
 
59
- if ('disabled' != $item['profile'])
60
  $actions[] = sprintf(
61
  '<a href=%s>%s</a>',
62
- esc_url(admin_url('admin.php?page=lingotek-translation_manage&sm=edit-profile&profile='.$item['profile'])),
63
- __('Edit', 'lingotek-translation')
64
  );
 
65
 
66
- if (!in_array($item['profile'], array('automatic', 'manual', 'disabled')) && empty($item['usage']))
67
  $actions[] = sprintf(
68
  '<a href="%s" onclick = "return confirm(\'%s\');">%s</a>',
69
- esc_url(wp_nonce_url('admin.php?page=lingotek-translation_manage&sm=profiles&lingotek_action=delete-profile&noheader=true&profile='.$item['profile'], 'delete-profile')),
70
- __('You are about to permanently delete this profile. Are you sure?', 'lingotek-translation'),
71
- __('Delete', 'lingotek-translation')
72
  );
 
73
 
74
- return implode(' | ', $actions);
75
  }
76
 
77
- /*
78
- * gets the list of columns
79
  *
80
  * @since 0.2
81
  *
@@ -83,14 +88,14 @@ class Lingotek_Profiles_Table extends WP_List_Table {
83
  */
84
  function get_columns() {
85
  return array(
86
- 'name' => __('Profile name', 'lingotek-translation'),
87
- 'usage' => __('Usage', 'lingotek-translation'),
88
- 'actions' => __('Actions', 'lingotek-translation'),
89
  );
90
  }
91
 
92
- /*
93
- * gets the list of sortable columns
94
  *
95
  * @since 0.2
96
  *
@@ -98,36 +103,44 @@ class Lingotek_Profiles_Table extends WP_List_Table {
98
  */
99
  function get_sortable_columns() {
100
  return array(
101
- 'name' => array('name', false),
102
  );
103
  }
104
 
105
- /*
106
- * prepares the list of items ofr displaying
107
  *
108
  * @since 0.2
109
  *
110
- * @param array $data
111
  */
112
- function prepare_items($data = array()) {
113
- $per_page = $this->get_items_per_page('lingotek_profiles_per_page');
114
- $this->_column_headers = array($this->get_columns(), array(), $this->get_sortable_columns());
115
-
116
- function usort_reorder($a, $b){
117
- $result = strcmp($a[$_REQUEST['orderby']], $b[$_REQUEST['orderby']]); // determine sort order
118
- return (empty($_REQUEST['order']) || $_REQUEST['order'] == 'asc') ? $result : -$result; // send final sort direction to usort
 
 
 
 
 
 
 
119
  };
120
 
121
- if (!empty($_REQUEST['orderby'])) // no sort by default
122
- usort($data, 'usort_reorder');
 
123
 
124
- $total_items = count($data);
125
- $this->items = array_slice($data, ($this->get_pagenum() - 1) * $per_page, $per_page);
126
 
127
  $this->set_pagination_args(array(
128
  'total_items' => $total_items,
129
  'per_page' => $per_page,
130
- 'total_pages' => ceil($total_items/$per_page)
131
  ));
132
  }
133
  }
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
+ * Lingotek Profiles Table Class.
9
+ */
10
  class Lingotek_Profiles_Table extends WP_List_Table {
11
 
12
+ /**
13
+ * Constructor
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
+ /**
25
+ * Displays the item information in a column (default case)
26
  *
27
  * @since 0.2
28
  *
29
+ * @param array $item item.
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
 
37
+ /**
38
+ * Displays the edit link in actions column
39
  *
40
  * @since 0.2
41
  *
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
 
51
+ /**
52
+ * Displays the edit link in actions column
53
  *
54
  * @since 0.2
55
  *
56
+ * @param array $item item.
57
  * @return string
58
  */
59
+ function column_actions( $item ) {
60
  $actions = array();
61
 
62
+ if ( 'disabled' !== $item['profile'] ) {
63
  $actions[] = sprintf(
64
  '<a href=%s>%s</a>',
65
+ esc_url( admin_url( 'admin.php?page=lingotek-translation_manage&sm=edit-profile&profile=' . $item['profile'] ) ),
66
+ __( 'Edit', 'lingotek-translation' )
67
  );
68
+ }
69
 
70
+ if ( ! in_array( $item['profile'], array( 'automatic', 'manual', 'disabled' ), true ) && empty( $item['usage'] ) ) {
71
  $actions[] = sprintf(
72
  '<a href="%s" onclick = "return confirm(\'%s\');">%s</a>',
73
+ esc_url( wp_nonce_url( 'admin.php?page=lingotek-translation_manage&sm=profiles&lingotek_action=delete-profile&noheader=true&profile=' . $item['profile'], 'delete-profile' ) ),
74
+ __( 'You are about to permanently delete this profile. Are you sure?', 'lingotek-translation' ),
75
+ __( 'Delete', 'lingotek-translation' )
76
  );
77
+ }
78
 
79
+ return implode( ' | ', $actions );
80
  }
81
 
82
+ /**
83
+ * Gets the list of columns
84
  *
85
  * @since 0.2
86
  *
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
  );
95
  }
96
 
97
+ /**
98
+ * Gets the list of sortable columns
99
  *
100
  * @since 0.2
101
  *
103
  */
104
  function get_sortable_columns() {
105
  return array(
106
+ 'name' => array( 'name', false ),
107
  );
108
  }
109
 
110
+ /**
111
+ * Prepares the list of items ofr displaying
112
  *
113
  * @since 0.2
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
+ /**
122
+ * Custom sort comparator.
123
+ *
124
+ * @param array $a assoc. array representing a profile.
125
+ * @param array $b assoc. array representing a profile.
126
+ * @return int sort direction.
127
+ */
128
+ function usort_reorder( $a, $b ) {
129
+ $result = strcmp( $a[ filter_input( INPUT_GET, 'orderby' ) ], $b[ filter_input( INPUT_GET, 'orderby' ) ] ); // determine sort order.
130
+ return (empty( filter_input( INPUT_GET, 'order' ) ) || 'asc' === filter_input( INPUT_GET, 'order' ) ) ? $result : -$result; // send final sort direction to usort.
131
  };
132
 
133
+ if ( ! empty( filter_input( INPUT_GET, 'orderby' ) ) ) { // no sort by default.
134
+ usort( $data, 'usort_reorder' );
135
+ }
136
 
137
+ $total_items = count( $data );
138
+ $this->items = array_slice( $data, ($this->get_pagenum() - 1) * $per_page, $per_page );
139
 
140
  $this->set_pagination_args(array(
141
  'total_items' => $total_items,
142
  'per_page' => $per_page,
143
+ 'total_pages' => ceil( $total_items / $per_page ),
144
  ));
145
  }
146
  }
admin/settings.php CHANGED
@@ -1,62 +1,60 @@
1
  <div class="wrap">
2
- <h2><?php _e('Settings', 'lingotek-translation'); ?></h2>
3
-
4
- <?php
5
- if (strlen($access_token)) {
6
- ?>
7
-
8
- <?php
9
-
10
- $menu_items = array(
11
- 'account' => __('Account', 'lingotek-translation'),
12
- );
13
-
14
- $community_required_menu_items = array(
15
- 'defaults' => __('Defaults', 'lingotek-translation'),
16
- 'preferences' => __('Preferences', 'lingotek-translation'),
17
- //'advanced' => __('Advanced', 'lingotek-translation'),
18
- //'logging' => __('Logging', 'lingotek-translation'),
19
- 'utilities' => __('Utilities', 'lingotek-translation'),
20
- );
21
-
22
- if($community_id !== FALSE){
23
- $menu_items = array_merge($menu_items, $community_required_menu_items);
24
- }
25
-
26
- ?>
27
-
28
- <h3 class="nav-tab-wrapper">
29
- <?php
30
- $menu_item_index = 0;
31
- foreach ($menu_items as $menu_item_key => $menu_item_label) {
32
- $use_as_default = ($menu_item_index === 0 && !isset($_GET['sm'])) ? TRUE : FALSE;
33
- $alias = NULL;
34
- // custom sub sub-menus
35
- if(isset($_GET['sm']) && $_GET['sm'] == "edit-profile") {
36
- $alias = "profiles";
37
- }
38
- ?>
39
-
40
- <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; ?>"
41
- href="admin.php?page=<?php echo $_GET['page']; ?>&amp;sm=<?php echo $menu_item_key; ?>"><?php echo $menu_item_label; ?></a>
42
- <?php
43
- $menu_item_index++;
44
- }
45
- ?>
46
- </h3>
47
-
48
- <?php
49
- settings_errors();
50
- $submenu = isset($_GET['sm']) ? sanitize_text_field($_GET['sm']) : 'account';
51
- $dir = dirname(__FILE__) . '/settings/';
52
- $filename = $dir . 'view-' . $submenu . ".php";
53
- if (file_exists($filename))
54
- include $filename;
55
- else
56
- echo "TO-DO: create <i>" . 'settings/view-' . $submenu . ".php</i>";
57
- ?>
58
-
59
- <?php
60
- }
61
- ?>
62
  </div>
1
  <div class="wrap">
2
+ <h2><?php esc_html_e( 'Settings', 'lingotek-translation' ); ?></h2>
3
+
4
+ <?php
5
+ if ( strlen( $access_token ) ) {
6
+ ?>
7
+
8
+ <?php
9
+
10
+ $menu_items = array(
11
+ 'account' => __( 'Account', 'lingotek-translation' ),
12
+ );
13
+
14
+ $community_required_menu_items = array(
15
+ 'defaults' => __( 'Defaults', 'lingotek-translation' ),
16
+ 'preferences' => __( 'Preferences', 'lingotek-translation' ),
17
+ 'utilities' => __( 'Utilities', 'lingotek-translation' ),
18
+ );
19
+
20
+ if ( false !== $community_id ) {
21
+ $menu_items = array_merge( $menu_items, $community_required_menu_items );
22
+ }
23
+
24
+ ?>
25
+
26
+ <h3 class="nav-tab-wrapper">
27
+ <?php
28
+ $menu_item_index = 0;
29
+ foreach ( $menu_items as $menu_item_key => $menu_item_label ) {
30
+ $use_as_default = (0 === $menu_item_index && empty( filter_input( INPUT_GET, 'sm' ) )) ? true : false;
31
+ $alias = null;
32
+ // custom sub sub-menus.
33
+ if ( ! empty( filter_input( INPUT_GET, 'sm' ) ) && 'edit-profile' === filter_input( INPUT_GET, 'sm' ) ) {
34
+ $alias = 'profiles';
35
+ }
36
+ ?>
37
+
38
+ <a class="nav-tab <?php if ( $use_as_default || ( ! empty( filter_input( INPUT_GET, 'sm' ) ) && filter_input( INPUT_GET, 'sm' ) === $menu_item_key) || $alias === $menu_item_key ) : ?> nav-tab-active<?php endif; ?>"
39
+ 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>
40
+ <?php
41
+ $menu_item_index++;
42
+ }
43
+ ?>
44
+ </h3>
45
+
46
+ <?php
47
+ settings_errors();
48
+ $submenu = ! empty( filter_input( INPUT_GET, 'sm' ) ) ? sanitize_text_field( filter_input( INPUT_GET, 'sm' ) ) : 'account';
49
+ $dir = dirname( __FILE__ ) . '/settings/';
50
+ $filename = $dir . 'view-' . $submenu . '.php';
51
+ if ( file_exists( $filename ) ) {
52
+ include $filename;
53
+ } else { echo 'TO-DO: create <i>settings/view-' . esc_html( $submenu ) . '.php</i>';
54
+ }
55
+ ?>
56
+
57
+ <?php
58
+ }
59
+ ?>
 
 
60
  </div>
admin/settings/connect-account.php CHANGED
@@ -1,29 +1,39 @@
1
- <?php /* Redirect Access Token */ ?>
2
  <script>
3
- var hash = window.location.hash;
4
- if (hash.length && hash.indexOf("access_token") !== -1) {
5
- var url_with_access_token = window.location.origin + window.location.pathname + window.location.search + '&' + hash.substr(1);
6
- window.location.href = url_with_access_token;
7
- }
8
- else if (window.location.search.indexOf("connect") != -1) {
9
- window.location.href = "<?php echo $connect_url ?>";
10
- }
11
  </script>
12
- <?php /* Connect Your Account Button */ ?>
13
  <div class="wrap">
14
- <h2><?php _e('Connect Your Account', 'lingotek-translation') ?></h2>
15
- <div>
16
- <p class="description">
17
- <?php _e('Get started by clicking the button below to connect your Lingotek account to this Wordpress installation.', 'lingotek-translation') ?>
18
- </p>
19
- <hr/>
20
- <p>
21
- <a class="button button-large button-hero" href="<?php echo $connect_account_cloak_url_new ?>">
22
- <img src="<?php echo LINGOTEK_URL; ?>/img/lingotek-icon.png" style="padding: 0 4px 2px 0;" align="absmiddle"/> <?php _e('Connect New Account', 'lingotek-translation') ?>
23
- </a>
24
- </p>
25
- <hr/>
26
- <p class="description"><?php echo sprintf( __('Do you already have a Lingotek account? <a href="%s">Connect Lingotek Account</a>', 'lingotek-translation'), esc_attr($connect_account_cloak_url_prod)) ?></p>
27
- <p class="description"><?php echo sprintf( __('Do you have a Lingotek sandbox account? <a href="%s">Connect Sandbox Account</a>', 'lingotek-translation'), esc_attr($connect_account_cloak_url_test)) ?></p>
28
- </div>
29
- </div>
 
 
 
 
 
 
 
 
 
 
1
+ <!-- Redirect Access Token -->
2
  <script>
3
+ var hash = window.location.hash;
4
+ if (hash.length && hash.indexOf("access_token") !== -1) {
5
+ var url_with_access_token = window.location.origin + window.location.pathname + window.location.search + '&' + hash.substr(1);
6
+ window.location.href = url_with_access_token;
7
+ }
8
+ else if (window.location.search.indexOf("connect") != -1) {
9
+ window.location.href = "<?php echo esc_url_raw( $connect_url ) ?>";
10
+ }
11
  </script>
12
+ <!-- Connect Your Account Button -->
13
  <div class="wrap">
14
+ <h2><?php esc_html_e( 'Connect Your Account', 'lingotek-translation' ) ?></h2>
15
+ <div>
16
+ <p class="description">
17
+ <?php esc_html_e( 'Get started by clicking the button below to connect your Lingotek account to this Wordpress installation.', 'lingotek-translation' ) ?>
18
+ </p>
19
+ <hr/>
20
+ <p>
21
+ <a class="button button-large button-hero" href="<?php echo esc_url_raw( $connect_account_cloak_url_new ) ?>">
22
+ <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' ) ?>
23
+ </a>
24
+ </p>
25
+ <hr/>
26
+ <p class="description">
27
+ <?php
28
+ $allowed_html = [
29
+ 'a' => [
30
+ 'href' => [],
31
+ ],
32
+ ];
33
+
34
+ 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 ) )
35
+ ?>
36
+ </p>
37
+ <p class="description"><?php echo sprintf( wp_kses( __( 'Do you have a Lingotek sandbox account? <a href="%s">Connect Sandbox Account</a>', 'lingotek-translation' ), $allowed_html ), esc_attr( $connect_account_cloak_url_test ) ) ?></p>
38
+ </div>
39
+ </div>
admin/settings/view-account.php CHANGED
@@ -1,126 +1,125 @@
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 ($ltk_num_communities == 1) {
13
- $ltk_community_id = $ltk_communities->entities[0]->properties->id;
14
- $this->set_community_resources($ltk_community_id);
15
- echo '<script type="text/javascript">document.body.innerHTML = ""; window.location = "admin.php?page=lingotek-translation_tutorial";</script>';
16
- }
17
  }
18
  ?>
19
 
20
- <h3><?php _e('Account', 'lingotek-translation'); ?></h3>
21
- <p class="description"><?php _e('Lingotek account connection and community selection.', 'lingotek-translation'); ?></p>
22
 
23
  <table class="form-table">
24
- <tr>
25
- <th scope="row">
26
- <?php _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 _e('Yes', 'lingotek-translation') ?><span title="<?php _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 __('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', $token_details['login_id']
42
- );
43
- ?>
44
- </label>
45
- </td>
46
- </tr>
47
- <tr>
48
- <th scope="row"><?php echo __('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', $token_details['access_token']
54
- );
55
- printf(
56
- '<input name="%s" class="regular-text" type="text" value="%s" disabled="disabled" />', 'access_token', $token_details['access_token']
57
- );
58
- ?>
59
- </label>
60
- </td>
61
- </tr>
62
- <tr>
63
- <th scope="row"><?php echo __('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', $base_url
69
- );
70
- ?>
71
- </label>
72
- </td>
73
- </tr>
74
- <tr>
75
- <th></th>
76
- <td>
77
- <?php
78
- $confirm_message = __('Are you sure you would like to disconnect your Lingotek account? \n\nAfter disconnecting, you will need to re-connect an account to continue using Lingotek.', 'lingotek-translation');
79
- echo '<a class="button" href="' . $redirect_url . '&delete_access_token=true" onclick="return confirm(\'' . $confirm_message . '\')">' . __('Disconnect', 'lingotek-translation') . '</a>';
80
- ?>
81
- </td>
82
- </tr>
83
- </tbody>
84
  </table>
85
 
86
  <hr/>
87
 
88
- <form method="post" action="admin.php?page=<?php echo $page_key; ?>" class="validate"> <?php /* &amp;noheader=true */ ?>
89
- <?php wp_nonce_field($page_key, '_wpnonce_' . $page_key); ?>
90
 
91
- <table class="form-table">
92
- <tr>
93
- <th scope="row"><label for="lingotek_community"><?php _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
 
101
- $communities = array();
102
- if (isset($api_communities->entities)) {
103
- foreach ($api_communities->entities as $community) {
104
- $communities[$community->properties->id] = $community->properties->title; // . ' (' . $community->properties->id . ')';
105
- }
 
 
 
 
 
 
 
 
 
 
 
 
106
 
107
- $num_communities = count($communities);
108
- if($num_communities == 1 && !$community_id){
109
- update_option('lingotek_community', current(array_keys($communities)));
110
- }
111
- if(!$community_id && $num_communities > 1) {
112
- echo "\n\t" . '<option value="">'.__('Select', 'lingotek-translation').'...</option>';
113
- }
114
- foreach ($communities as $community_id_option => $community_title) {
115
- $selected = ($default_community_id == $community_id_option) ? 'selected="selected"' : '';
116
- echo "\n\t" . '<option value="' . esc_attr($community_id_option) . '" '.$selected.'>' . $community_title . '</option>';
117
- }
118
- }
119
- ?>
120
- </select>
121
- </td>
122
- </tr>
123
- </table>
124
-
125
- <?php submit_button(__('Save Changes', 'lingotek-translation'), 'primary', 'submit', false); ?>
126
- </form>
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;
14
+ $this->set_community_resources( $ltk_community_id );
15
+ echo '<script type="text/javascript">document.body.innerHTML = ""; window.location = "admin.php?page=lingotek-translation_tutorial";</script>';
16
+ }
17
  }
18
  ?>
19
 
20
+ <h3><?php esc_html_e( 'Account', 'lingotek-translation' ); ?></h3>
21
+ <p class="description"><?php esc_html_e( 'Lingotek account connection and community selection.', 'lingotek-translation' ); ?></p>
22
 
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>
75
+ <th></th>
76
+ <td>
77
+ <?php
78
+ $confirm_message = __( 'Are you sure you would like to disconnect your Lingotek account? \n\nAfter disconnecting, you will need to re-connect an account to continue using Lingotek.', 'lingotek-translation' );
79
+ echo '<a class="button" href="' . esc_html( $redirect_url ) . '&delete_access_token=true" onclick="return confirm(\'' . esc_html( $confirm_message ) . '\')">' . esc_html( __( 'Disconnect', 'lingotek-translation' ) ) . '</a>';
80
+ ?>
81
+ </td>
82
+ </tr>
83
+ </tbody>
84
  </table>
85
 
86
  <hr/>
87
 
88
+ <form method="post" action="admin.php?page=<?php echo esc_html( $page_key ); ?>" class="validate">
89
+ <?php wp_nonce_field( $page_key, '_wpnonce_' . $page_key ); ?>
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
+ </table>
123
 
124
+ <?php submit_button( __( 'Save Changes', 'lingotek-translation' ), 'primary', 'submit', false ); ?>
125
+ </form>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin/settings/view-defaults.php CHANGED
@@ -2,141 +2,135 @@
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);
9
- if (array_key_exists('refresh', $_POST)) {
10
- $refresh_success = $this->set_community_resources($community_id);
11
- if ($refresh_success['projects'] == TRUE && $refresh_success['workflows'] == TRUE) {
12
- add_settings_error('lingotek_community_resources', 'options', __('Resources from Lingotek were successfully updated for projects and workflows.', 'lingotek-translation'), 'updated');
13
- }
14
- else if ($refresh_success['projects'] == TRUE) {
15
- add_settings_error('lingotek_community_resources', 'error', __('Resources from Lingotek were successfully updated for projects.', 'lingotek-translation'), 'updated');
16
- }
17
- else if ($refresh_success['workflows'] == TRUE) {
18
- add_settings_error('lingotek_community_resources', 'error', __('Resources from Lingotek were successfully updated for workflows.', 'lingotek-translation'), 'updated');
19
- }
20
- else if ($refresh_success['workflows'] == FALSE || $refresh_success['projects'] == FALSE) {
21
- 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');
22
- }
23
- }
24
- else {
25
- $options = array();
26
- $settings = $this->get_profiles_settings(true);
27
- foreach ($settings as $key => $setting) {
28
- if (isset($_POST[$key])) {
29
- $options[$key] = $_POST[$key];
30
- }
31
- }
32
- update_option('lingotek_defaults', $options);
33
- add_settings_error('lingotek_defaults', 'defaultgs', __('Your <i>Defaults</i> were sucessfully saved.', 'lingotek-translation'), 'updated');
34
-
35
- if (isset($_POST['update_callback'])) {
36
- $client = new Lingotek_API();
37
- if ($client->update_callback_url($options['project_id']))
38
- add_settings_error('lingotek_defaults', 'defaultgs', __('Your callback url was successfully updated.', 'lingotek-translation'), 'updated');
39
- }
40
-
41
- //adds new project if text box is filled out
42
- if (!empty($_POST['new_project'])) {
43
- $client = new Lingotek_API();
44
- $title = stripslashes($_POST['new_project']);
45
-
46
- if ($new_id = $client->create_project($title, $community_id)) {
47
- add_settings_error('lingotek_defaults', 'defaultgs', __('Your new project was successfully created.', 'lingotek-translation'), 'updated');
48
- $this->set_community_resources($community_id);// updates the cache to include the newly created project
49
- $options['project_id'] = $new_id;
50
- update_option('lingotek_defaults', $options);
51
- }
52
- }
53
  }
54
  settings_errors();
55
  }
56
- $settings = $this->get_profiles_settings(true);
57
- $options = get_option('lingotek_defaults');
58
-
59
- // Code to determine which filter scenario will be displayed (Not configured, defaults, custom filters)
60
- $primary_filter_id = array_search('okf_json@with-html-subfilter.fprm', $settings['primary_filter_id']['options']);
61
- $secondary_filter_id = array_search('okf_html@wordpress.fprm', $settings['secondary_filter_id']['options']);
62
- $default_filters = array($primary_filter_id => 'okf_json@with-html-subfilter.fprm', $secondary_filter_id => 'okf_html@wordpress.fprm');
63
- $default_filters_exist = FALSE;
64
- $extra_filters_exist = FALSE;
65
- $no_filters_exist = FALSE;
66
-
67
- if ($settings['primary_filter_id']['options'] == $default_filters) {
68
- $default_filters_exist = TRUE;
69
- $options['primary_filter_id'] = $primary_filter_id;
70
- $options['secondary_filter_id'] = $secondary_filter_id;
71
- update_option('lingotek_defaults', $options);
72
- }
73
- else {
74
- $num = count(array_diff_assoc($settings['primary_filter_id']['options'], $default_filters));
75
- if ($num > 0) {
76
- $extra_filters_exist = TRUE;
77
- }
78
- else {
79
- $options['primary_filter_id'] = '';
80
- $options['secondary_filter_id'] = '';
81
- update_option('lingotek_defaults', $options);
82
- $no_filters_exist = TRUE;
83
- }
84
  }
85
- unset($settings['primary_filter_id']['options'][$secondary_filter_id]);
86
- unset($settings['secondary_filter_id']['options'][$primary_filter_id]);
87
  ?>
88
 
89
- <h3><?php _e('Defaults', 'lingotek-translation'); ?></h3>
90
- <p class="description"><?php _e('The default automation settings and resources that should be used for this site. These settings can be overriden using translation profiles and content type configuration.', 'lingotek-translation'); ?></p>
91
 
92
 
93
- <form id="lingotek-settings" method="post" action="admin.php?page=<?php echo $page_key; ?>" class="validate">
94
- <?php wp_nonce_field($page_key, '_wpnonce_' . $page_key); ?>
95
 
96
- <table class="form-table"><?php foreach ($settings as $key => $setting) { ?>
97
- <tr id="<?php echo $key.'_row'?>">
98
- <th scope="row"><label for="<?php echo $key; ?>"><?php echo $setting['label'] ?></label></th>
99
  <td>
100
- <select name="<?php echo $key ?>" id="<?php echo $key ?>"><?php
101
- foreach ($setting['options'] as $id => $title) {
102
- $selected = array_key_exists($key, $options) && ($options[$key] == $id) ? 'selected="selected"' : '';
103
- echo "\n\t<option value='" . esc_attr($id) . "' $selected>" . $title . '</option>';
104
- } ?>
105
  </select><?php
106
- if ('project_id' == $key) { ?>
107
- <?php
108
-
109
- if (empty($setting['options'])) { ?>
110
- <script> document.getElementById('project_id').style.display = 'none';</script>
111
- <input type="text" name="new_project" id="new_project" placeholder="<?php _e('Enter new project name', 'lingotek-translation') ?>" />
112
- <?php }
113
- else { ?>
114
-
115
- <input type="text" style="display:none" name="new_project" id="new_project" placeholder="<?php _e('Enter new project name', 'lingotek-translation') ?>" />
116
- <input type="checkbox" name="update_callback" id="update_callback"/>
117
- <label for="update_callback" id="callback_label"><?php _e('Update the callback url for this project.', 'lingotek-translation') ?></label>
118
-
119
- <br/><a href="#" id="create" onclick="toggleTextbox()" style="padding-left:3px; color:#999; font-size:80%; text-decoration:none"><b>+</b> <?php echo _e('Create New Project', 'lingotek-translation') ?></a>
120
- <?php } ?>
121
- <?php } ?>
122
- <!-- Code to handle displaying of Primary and Secondary Filters -->
123
- <?php if($no_filters_exist) { ?>
124
- <script> document.getElementById("primary_filter_id_row").style.display = "none";</script>
125
- <script> document.getElementById("secondary_filter_id_row").style.display = "none";</script> <?php
126
- if ('primary_filter_id' == $key) { ?>
127
- <tr id="filters_row"><th><?php _e('Filters', 'lingotek-translation') ?></th><td><i><?php _e('Not configured', 'lingotek-translation') ?></i></td></tr>
128
- <?php }
129
- }
130
- if ($default_filters_exist) { ?>
131
- <script> document.getElementById("primary_filter_id_row").style.display = "none";</script>
132
- <script> document.getElementById("secondary_filter_id_row").style.display = "none";</script>
133
- <?php } ?>
134
- <!-- End of filter code -->
135
  </tr><?php } ?>
136
  </table>
137
 
138
  <p>
139
- <?php submit_button(__('Save Changes', 'lingotek-translation'), 'primary', 'submit', false); ?>
140
- <?php submit_button(__( 'Refresh Resources', 'lingotek-translation'), 'secondary', 'refresh', false ); ?>
141
  </p>
142
  </form>
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 );
9
+ if ( ! empty( filter_input( INPUT_POST, 'refresh' ) ) ) {
10
+ $refresh_success = $this->set_community_resources( $community_id );
11
+ if ( true === $refresh_success['projects'] && true === $refresh_success['workflows'] ) {
12
+ add_settings_error( 'lingotek_community_resources', 'options', __( 'Resources from Lingotek were successfully updated for projects and workflows.', 'lingotek-translation' ), 'updated' );
13
+ } elseif ( true === $refresh_success['projects'] ) {
14
+ add_settings_error( 'lingotek_community_resources', 'error', __( 'Resources from Lingotek were successfully updated for projects.', 'lingotek-translation' ), 'updated' );
15
+ } elseif ( true === $refresh_success['workflows'] ) {
16
+ add_settings_error( 'lingotek_community_resources', 'error', __( 'Resources from Lingotek were successfully updated for workflows.', 'lingotek-translation' ), 'updated' );
17
+ } elseif ( false === $refresh_success['workflows'] || false === $refresh_success['projects'] ) {
18
+ 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' );
19
+ }
20
+ } else {
21
+ $options = array();
22
+ $settings = $this->get_profiles_settings( true );
23
+ foreach ( $settings as $key => $setting ) {
24
+ if ( ! empty( filter_input( INPUT_POST, $key ) ) ) {
25
+ $options[ $key ] = filter_input( INPUT_POST, $key );
26
+ }
27
+ }
28
+ update_option( 'lingotek_defaults', $options );
29
+ add_settings_error( 'lingotek_defaults', 'defaultgs', __( 'Your <i>Defaults</i> were sucessfully saved.', 'lingotek-translation' ), 'updated' );
30
+
31
+ if ( ! empty( filter_input( INPUT_POST, 'update_callback' ) ) ) {
32
+ $client = new Lingotek_API();
33
+ if ( $client->update_callback_url( $options['project_id'] ) ) {
34
+ add_settings_error( 'lingotek_defaults', 'defaultgs', __( 'Your callback url was successfully updated.', 'lingotek-translation' ), 'updated' );
35
+ }
36
+ }
37
+
38
+ // adds new project if text box is filled out.
39
+ if ( ! empty( filter_input( INPUT_POST, 'new_project' ) ) ) {
40
+ $client = new Lingotek_API();
41
+ $title = stripslashes( filter_input( INPUT_POST, 'new_project' ) );
42
+
43
+ if ( $new_id = $client->create_project( $title, $community_id ) ) {
44
+ add_settings_error( 'lingotek_defaults', 'defaultgs', __( 'Your new project was successfully created.', 'lingotek-translation' ), 'updated' );
45
+ $this->set_community_resources( $community_id );// updates the cache to include the newly created project.
46
+ $options['project_id'] = $new_id;
47
+ update_option( 'lingotek_defaults', $options );
48
+ }
49
+ }
 
 
 
50
  }
51
  settings_errors();
52
  }
53
+ $settings = $this->get_profiles_settings( true );
54
+ $options = get_option( 'lingotek_defaults' );
55
+
56
+ // Code to determine which filter scenario will be displayed (Not configured, defaults, custom filters).
57
+ $primary_filter_id = array_search( 'okf_json@with-html-subfilter.fprm', $settings['primary_filter_id']['options'], true );
58
+ $secondary_filter_id = array_search( 'okf_html@wordpress.fprm', $settings['secondary_filter_id']['options'], true );
59
+ $default_filters = array( $primary_filter_id => 'okf_json@with-html-subfilter.fprm', $secondary_filter_id => 'okf_html@wordpress.fprm' );
60
+ $default_filters_exist = false;
61
+ $extra_filters_exist = false;
62
+ $no_filters_exist = false;
63
+
64
+ if ( $settings['primary_filter_id']['options'] === $default_filters ) {
65
+ $default_filters_exist = true;
66
+ $options['primary_filter_id'] = $primary_filter_id;
67
+ $options['secondary_filter_id'] = $secondary_filter_id;
68
+ update_option( 'lingotek_defaults', $options );
69
+ } else {
70
+ $num = count( array_diff_assoc( $settings['primary_filter_id']['options'], $default_filters ) );
71
+ if ( $num > 0 ) {
72
+ $extra_filters_exist = true;
73
+ } else {
74
+ $options['primary_filter_id'] = '';
75
+ $options['secondary_filter_id'] = '';
76
+ update_option( 'lingotek_defaults', $options );
77
+ $no_filters_exist = true;
78
+ }
 
 
79
  }
80
+ unset( $settings['primary_filter_id']['options'][ $secondary_filter_id ] );
81
+ unset( $settings['secondary_filter_id']['options'][ $primary_filter_id ] );
82
  ?>
83
 
84
+ <h3><?php esc_html_e( 'Defaults', 'lingotek-translation' ); ?></h3>
85
+ <p class="description"><?php esc_html_e( 'The default automation settings and resources that should be used for this site. These settings can be overriden using translation profiles and content type configuration.', 'lingotek-translation' ); ?></p>
86
 
87
 
88
+ <form id="lingotek-settings" method="post" action="admin.php?page=<?php echo esc_html( $page_key ); ?>" class="validate">
89
+ <?php wp_nonce_field( $page_key, '_wpnonce_' . $page_key ); ?>
90
 
91
+ <table class="form-table"><?php foreach ( $settings as $key => $setting ) { ?>
92
+ <tr id="<?php echo esc_html( $key ) . '_row'?>">
93
+ <th scope="row"><label for="<?php echo esc_html( $key ); ?>"><?php echo esc_html( $setting['label'] ) ?></label></th>
94
  <td>
95
+ <select name="<?php echo esc_html( $key ) ?>" id="<?php echo esc_html( $key ) ?>"><?php
96
+ foreach ( $setting['options'] as $id => $title ) {
97
+ $selected = array_key_exists( $key, $options ) && ($options[ $key ] === $id) ? 'selected="selected"' : '';
98
+ echo "\n\t<option value='" . esc_attr( $id ) . "' " . esc_html( $selected ) . '>' . esc_html( $title ) . '</option>';
99
+ } ?>
100
  </select><?php
101
+ if ( 'project_id' === $key ) { ?>
102
+ <?php
103
+
104
+ if ( empty( $setting['options'] ) ) { ?>
105
+ <script> document.getElementById('project_id').style.display = 'none';</script>
106
+ <input type="text" name="new_project" id="new_project" placeholder="<?php esc_html_e( 'Enter new project name', 'lingotek-translation' ) ?>" />
107
+ <?php } else { ?>
108
+
109
+ <input type="text" style="display:none" name="new_project" id="new_project" placeholder="<?php esc_html_e( 'Enter new project name', 'lingotek-translation' ) ?>" />
110
+ <input type="checkbox" name="update_callback" id="update_callback"/>
111
+ <label for="update_callback" id="callback_label"><?php esc_html_e( 'Update the callback url for this project.', 'lingotek-translation' ) ?></label>
112
+
113
+ <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>
114
+ <?php } ?>
115
+ <?php } ?>
116
+ <!-- Code to handle displaying of Primary and Secondary Filters. -->
117
+ <?php if ( $no_filters_exist ) { ?>
118
+ <script> document.getElementById("primary_filter_id_row").style.display = "none";</script>
119
+ <script> document.getElementById("secondary_filter_id_row").style.display = "none";</script> <?php
120
+ if ( 'primary_filter_id' === $key ) { ?>
121
+ <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>
122
+ <?php }
123
+ }
124
+ if ( $default_filters_exist ) { ?>
125
+ <script> document.getElementById("primary_filter_id_row").style.display = "none";</script>
126
+ <script> document.getElementById("secondary_filter_id_row").style.display = "none";</script>
127
+ <?php } ?>
128
+ <!-- End of filter code. -->
 
129
  </tr><?php } ?>
130
  </table>
131
 
132
  <p>
133
+ <?php submit_button( __( 'Save Changes', 'lingotek-translation' ), 'primary', 'submit', false ); ?>
134
+ <?php submit_button( __( 'Refresh Resources', 'lingotek-translation' ), 'secondary', 'refresh', false ); ?>
135
  </p>
136
  </form>
admin/settings/view-preferences.php CHANGED
@@ -1,121 +1,111 @@
1
  <?php
2
 
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
- 'draft' => __('Draft', 'lingotek-translation'),
11
- 'pending' => __('Pending Review', 'lingotek-translation'),
12
- 'publish' => __('Published', 'lingotek-translation'),
13
- //'future' => __('Scheduled', 'lingotek-translation'),
14
- 'private' => __('Privately Published', 'lingotek-translation'),
15
- )),
16
- 'auto_upload_post_statuses' => array( // blacklist
17
- 'type' => 'checkboxes',
18
- 'label' => __('Auto upload statuses', 'lingotek-translation'),
19
- 'description' => __('The post statuses checked above are enabled for automatic upload (when using automatic uploading translation profiles).', 'lingotek-translation'),
20
- 'values' => array(
21
- 'draft' => __('Draft', 'lingotek-translation'),
22
- 'pending' => __('Pending Review', 'lingotek-translation'),
23
- 'publish' => __('Published', 'lingotek-translation'),
24
- 'future' => __('Scheduled', 'lingotek-translation'),
25
- 'private' => __('Privately Published', 'lingotek-translation'),
26
- )
27
- ),
28
- 'delete_document_from_tms' => array(
29
- 'type' => 'checkboxes',
30
- 'label' => __('Disassociation', 'lingotek-translation'),
31
- 'description' => __('Your documents will remain in your WordPress site but will be deleted from the Lingotek TMS if this option is checked.', 'lingotek-translation'),
32
- 'values' => array(
33
- 'delete' => __('Delete documents from Lingotek TMS when disassociating.', 'lingotek-translation'),
34
- )
35
- ),
36
- 'delete_linked_content' => array(
37
- 'type' => 'checkboxes',
38
- 'label' => __('Deleting Content', 'wp-lingotek'),
39
- 'description' => __('When enabled, deleting source or target content will also delete all linked content.', 'wp-lingotek'),
40
- 'values' => array(
41
- 'enabled' => __('Delete linked content', 'wp-lingotek')
42
- )),
43
- 'import_enabled' => array(
44
- 'type' => 'checkboxes',
45
- 'label' => __('Import', 'wp-lingotek'),
46
- 'description' => __('When checked, an "Import" submenu will appear.', 'wp-lingotek'),
47
- 'values' => array(
48
- 'enabled' => __('Enable importing from Lingotek Content Cloud. (beta)', 'wp-lingotek')
49
- )),
 
 
50
  );
51
 
52
  $page_key = $this->plugin_slug . '_settings&sm=preferences';
53
 
54
- if (!empty($_POST)) {
55
- check_admin_referer($page_key, '_wpnonce_' . $page_key);
56
- $options = array();
57
- foreach ($setting_details as $key => $setting) {
58
- if (isset($_POST[$key])) {
59
- $options[$key] = $_POST[$key];
60
- }
61
- else {
62
- $options[$key] = null;
63
- }
64
- }
65
- update_option('lingotek_prefs', $options);
66
 
67
- add_settings_error('lingotek_prefs', 'prefs', __('Your preferences were successfully updated.', 'lingotek-translation'), 'updated');
68
- settings_errors();
69
  }
70
- // else {
71
- // $selected_options = Lingotek_Model::get_prefs();
72
- //
73
- // $options = array();
74
- // if (!isset($selected_options['import_enabled'])){
75
- // $options['import_enabled'] = 'enabled';
76
- // }
77
- //
78
- // update_option('lingotek_prefs', $options);
79
- // }
80
-
81
  $selected_options = Lingotek_Model::get_prefs();
82
 
83
  ?>
84
 
85
- <h3><?php _e('Preferences', 'lingotek-translation'); ?></h3>
86
- <p class="description"><?php _e('These are your preferred settings.', 'lingotek-translation'); ?></p>
87
 
88
 
89
- <form id="lingotek-settings" method="post" action="admin.php?page=<?php echo $page_key; ?>" class="validate">
90
- <?php wp_nonce_field($page_key, '_wpnonce_' . $page_key); ?>
91
 
92
- <table class="form-table"><?php foreach ($setting_details as $key => $setting) { ?>
93
 
94
- <tr>
95
- <th scope="row"><label for="<?php echo $key; ?>"><?php echo $setting['label'] ?></label></th>
96
- <td>
97
- <?php if ($setting['type'] == 'dropdown') { ?>
98
- <select name="<?php echo $key ?>" id="<?php echo $key ?>">
99
- <?php
100
- foreach ($setting['values'] as $id => $title) {
101
- echo "\n\t" . '<option value="' . esc_attr($id) . '" ' . selected($selected_options[$key], $id) . '>' . $title . '</option>';
102
- }
103
- ?>
104
- </select>
105
- <?php } else if ($setting['type'] == 'checkboxes') {
106
- echo '<ul class="pref-statuses">';
107
- foreach ($setting['values'] as $id => $title) {
108
- $cb_name = $key.'['.esc_attr($id) . ']';
109
- $checked = checked('1', (isset($selected_options[$key][$id]) && $selected_options[$key][$id]), false);
110
- echo '<li><input type="checkbox" id="'.$cb_name.'" name="'.$cb_name.'" value="1" ' . $checked. '><label for="'.$cb_name.'">' . $title . '</label></li>';
111
- }
112
- echo '</ul>';
113
- } ?>
114
- <p class="description">
115
- <?php echo $setting['description']; ?>
116
- </p>
117
- </tr><?php } ?>
118
- </table>
119
 
120
- <?php submit_button(__('Save Changes', 'lingotek-translation'), 'primary', 'submit', false); ?>
121
  </form>
1
  <?php
2
 
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
+ 'draft' => __( 'Draft', 'lingotek-translation' ),
11
+ 'pending' => __( 'Pending Review', 'lingotek-translation' ),
12
+ 'publish' => __( 'Published', 'lingotek-translation' ),
13
+ 'private' => __( 'Privately Published', 'lingotek-translation' ),
14
+ ),
15
+ ),
16
+ 'auto_upload_post_statuses' => array( // blacklist.
17
+ 'type' => 'checkboxes',
18
+ 'label' => __( 'Auto upload statuses', 'lingotek-translation' ),
19
+ 'description' => __( 'The post statuses checked above are enabled for automatic upload (when using automatic uploading translation profiles).', 'lingotek-translation' ),
20
+ 'values' => array(
21
+ 'draft' => __( 'Draft', 'lingotek-translation' ),
22
+ 'pending' => __( 'Pending Review', 'lingotek-translation' ),
23
+ 'publish' => __( 'Published', 'lingotek-translation' ),
24
+ 'future' => __( 'Scheduled', 'lingotek-translation' ),
25
+ 'private' => __( 'Privately Published', 'lingotek-translation' ),
26
+ ),
27
+ ),
28
+ 'delete_document_from_tms' => array(
29
+ 'type' => 'checkboxes',
30
+ 'label' => __( 'Disassociation', 'lingotek-translation' ),
31
+ 'description' => __( 'Your documents will remain in your WordPress site but will be deleted from the Lingotek TMS if this option is checked.', 'lingotek-translation' ),
32
+ 'values' => array(
33
+ 'delete' => __( 'Delete documents from Lingotek TMS when disassociating.', 'lingotek-translation' ),
34
+ ),
35
+ ),
36
+ 'delete_linked_content' => array(
37
+ 'type' => 'checkboxes',
38
+ 'label' => __( 'Deleting Content', 'wp-lingotek' ),
39
+ 'description' => __( 'When enabled, deleting source or target content will also delete all linked content.', 'wp-lingotek' ),
40
+ 'values' => array(
41
+ 'enabled' => __( 'Delete linked content', 'wp-lingotek' ),
42
+ ),
43
+ ),
44
+ 'import_enabled' => array(
45
+ 'type' => 'checkboxes',
46
+ 'label' => __( 'Import', 'wp-lingotek' ),
47
+ 'description' => __( 'When checked, an "Import" submenu will appear.', 'wp-lingotek' ),
48
+ 'values' => array(
49
+ 'enabled' => __( 'Enable importing from Lingotek Content Cloud. (beta)', 'wp-lingotek' ),
50
+ ),
51
+ ),
52
  );
53
 
54
  $page_key = $this->plugin_slug . '_settings&sm=preferences';
55
 
56
+ if ( ! empty( $_POST ) ) {
57
+ check_admin_referer( $page_key, '_wpnonce_' . $page_key );
58
+ $options = array();
59
+ foreach ( $setting_details as $key => $setting ) {
60
+ if ( ! empty( filter_input( INPUT_POST, $key ) ) ) {
61
+ $options[ $key ] = filter_input( INPUT_POST, $key );
62
+ } else {
63
+ $options[ $key ] = null;
64
+ }
65
+ }
66
+ update_option( 'lingotek_prefs', $options );
 
67
 
68
+ add_settings_error( 'lingotek_prefs', 'prefs', __( 'Your preferences were successfully updated.', 'lingotek-translation' ), 'updated' );
69
+ settings_errors();
70
  }
 
 
 
 
 
 
 
 
 
 
 
71
  $selected_options = Lingotek_Model::get_prefs();
72
 
73
  ?>
74
 
75
+ <h3><?php esc_html_e( 'Preferences', 'lingotek-translation' ); ?></h3>
76
+ <p class="description"><?php esc_html_e( 'These are your preferred settings.', 'lingotek-translation' ); ?></p>
77
 
78
 
79
+ <form id="lingotek-settings" method="post" action="admin.php?page=<?php echo esc_html( $page_key ); ?>" class="validate">
80
+ <?php wp_nonce_field( $page_key, '_wpnonce_' . $page_key ); ?>
81
 
82
+ <table class="form-table"><?php foreach ( $setting_details as $key => $setting ) { ?>
83
 
84
+ <tr>
85
+ <th scope="row"><label for="<?php echo esc_html( $key ); ?>"><?php echo esc_html( $setting['label'] ) ?></label></th>
86
+ <td>
87
+ <?php if ( 'dropdown' === $setting['type'] ) { ?>
88
+ <select name="<?php echo esc_html( $key ); ?>" id="<?php echo esc_html( $key ); ?>">
89
+ <?php
90
+ foreach ( $setting['values'] as $id => $title ) {
91
+ echo "\n\t" . '<option value="' . esc_attr( $id ) . '" ' . selected( $selected_options[ $key ], $id ) . '>' . esc_html( $title ) . '</option>';
92
+ }
93
+ ?>
94
+ </select>
95
+ <?php } elseif ( 'checkboxes' === $setting['type'] ) {
96
+ echo '<ul class="pref-statuses">';
97
+ foreach ( $setting['values'] as $id => $title ) {
98
+ $cb_name = $key . '[' . esc_attr( $id ) . ']';
99
+ $checked = checked( '1', (isset( $selected_options[ $key ][ $id ] ) && $selected_options[ $key ][ $id ]), false );
100
+ 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>';
101
+ }
102
+ echo '</ul>';
103
+ } ?>
104
+ <p class="description">
105
+ <?php echo esc_html( $setting['description'] ); ?>
106
+ </p>
107
+ </tr><?php } ?>
108
+ </table>
109
 
110
+ <?php submit_button( __( 'Save Changes', 'lingotek-translation' ), 'primary', 'submit', false ); ?>
111
  </form>
admin/settings/view-utilities.php CHANGED
@@ -1,51 +1,55 @@
1
  <?php
2
  $page_key = $this->plugin_slug . '_settings&sm=utilities';
3
 
4
- if (!empty($_POST)) {
5
- check_admin_referer($page_key, '_wpnonce_' . $page_key);
6
 
7
- // progress dialog placeholder
8
- if (!empty($_POST['utility_disassociate'])) {
9
  $ids = Lingotek_Utilities::get_all_document_ids();
10
- if (!empty($ids))
11
- printf('<div id="lingotek-progressdialog" title="%s"><div id="lingotek-progressbar"></div></div>', __('Disassociating content...', 'lingotek-translation'));
 
12
  }
13
 
14
  $utilities = array();
15
- if(array_key_exists('utility_set_default_language', $_POST) && $_POST['utility_set_default_language'] == 'on'){
16
  $utilities[] = 'utility_set_default_language';
17
  }
18
 
19
- $GLOBALS['wp_lingotek']->utilities->run_utilities($utilities);
20
 
21
  settings_errors();
22
  }
23
 
24
  ?>
25
- <h3><?php _e('Utilities', 'lingotek-translation'); ?></h3>
26
- <p class="description"><?php _e('These utilities are designed to help you prepare and maintain your multilingual content.', 'lingotek-translation'); ?></p>
27
 
28
- <h4><?php _e('Language', 'lingotek-translation'); ?></h4>
29
- <form id="lingotek-utilities" method="post" action="admin.php?page=<?php echo $page_key; ?>" class="validate"><?php
30
- wp_nonce_field($page_key, '_wpnonce_' . $page_key);
31
 
 
 
 
32
  printf(
33
  '<p><input type="checkbox" name="%1$s" id="%1$s"/><label for="%1$s">%2$s</label></p>',
34
  'utility_set_default_language',
35
- __('Set <i>default language</i> as the language for all content that has not been assigned a language.', 'lingotek-translation')
36
  );
37
 
38
  ?>
39
- <h4><?php _e('Disassociation', 'lingotek-translation'); ?></h4>
40
  <?php
41
 
42
  printf(
43
  '<p><input type="checkbox" name="%1$s" id="%1$s"/><label for="%1$s">%2$s</label></p>',
44
  'utility_disassociate',
45
- __('Disassociate all the content from Lingotek TMS.', 'lingotek-translation')
46
  );
47
 
48
- $confirm_disassociate = __('You are about to disassociate all your content from Lingotek TMS. Are you sure ?', 'lingotek-translation');
49
 
50
  $confirm_js = "
51
  d = document.getElementById('utility_disassociate');
@@ -53,7 +57,5 @@ if (!empty($_POST)) {
53
  return confirm('$confirm_disassociate');
54
  }";
55
 
56
- submit_button(__('Run Utilities', 'lingotek-translation'), 'primary', 'submit', true, sprintf('onclick="%s"', $confirm_js)); ?>
57
  </form><?php
58
-
59
-
1
  <?php
2
  $page_key = $this->plugin_slug . '_settings&sm=utilities';
3
 
4
+ if ( ! empty( $_POST ) ) {
5
+ check_admin_referer( $page_key, '_wpnonce_' . $page_key );
6
 
7
+ // progress dialog placeholder.
8
+ if ( ! empty( filter_input( INPUT_POST, 'utility_disassociate' ) ) ) {
9
  $ids = Lingotek_Utilities::get_all_document_ids();
10
+ if ( ! empty( $ids ) ) {
11
+ printf( '<div id="lingotek-progressdialog" title="%s"><div id="lingotek-progressbar"></div></div>', esc_html( __( 'Disassociating content...', 'lingotek-translation' ) ) );
12
+ }
13
  }
14
 
15
  $utilities = array();
16
+ if ( 'on' === filter_input( INPUT_POST, 'utility_set_default_language' ) ) {
17
  $utilities[] = 'utility_set_default_language';
18
  }
19
 
20
+ $GLOBALS['wp_lingotek']->utilities->run_utilities( $utilities );
21
 
22
  settings_errors();
23
  }
24
 
25
  ?>
26
+ <h3><?php esc_html_e( 'Utilities', 'lingotek-translation' ); ?></h3>
27
+ <p class="description"><?php esc_html_e( 'These utilities are designed to help you prepare and maintain your multilingual content.', 'lingotek-translation' ); ?></p>
28
 
29
+ <h4><?php esc_html_e( 'Language', 'lingotek-translation' ); ?></h4>
30
+ <form id="lingotek-utilities" method="post" action="admin.php?page=<?php echo esc_attr( $page_key ); ?>" class="validate"><?php
31
+ wp_nonce_field( $page_key, '_wpnonce_' . $page_key );
32
 
33
+ $allowed_html = [
34
+ 'i' => [],
35
+ ];
36
  printf(
37
  '<p><input type="checkbox" name="%1$s" id="%1$s"/><label for="%1$s">%2$s</label></p>',
38
  'utility_set_default_language',
39
+ wp_kses( __( 'Set <i>default language</i> as the language for all content that has not been assigned a language.', 'lingotek-translation' ), $allowed_html )
40
  );
41
 
42
  ?>
43
+ <h4><?php esc_html_e( 'Disassociation', 'lingotek-translation' ); ?></h4>
44
  <?php
45
 
46
  printf(
47
  '<p><input type="checkbox" name="%1$s" id="%1$s"/><label for="%1$s">%2$s</label></p>',
48
  'utility_disassociate',
49
+ esc_html( __( 'Disassociate all the content from Lingotek TMS.', 'lingotek-translation' ) )
50
  );
51
 
52
+ $confirm_disassociate = __( 'You are about to disassociate all your content from Lingotek TMS. Are you sure ?', 'lingotek-translation' );
53
 
54
  $confirm_js = "
55
  d = document.getElementById('utility_disassociate');
57
  return confirm('$confirm_disassociate');
58
  }";
59
 
60
+ submit_button( __( 'Run Utilities', 'lingotek-translation' ), 'primary', 'submit', true, sprintf( 'onclick="%s"', $confirm_js ) ); ?>
61
  </form><?php
 
 
admin/string-actions.php CHANGED
@@ -1,144 +1,155 @@
1
  <?php
2
 
 
 
 
3
  class Lingotek_String_actions extends Lingotek_Actions {
4
 
5
- /*
6
  * Constructor
7
  *
8
  * @since 0.2
9
  */
10
  public function __construct() {
11
- parent::__construct('string');
12
 
13
- if (isset($this->pllm->options['default_lang']) && 'automatic' == Lingotek_Model::get_profile_option('upload', 'string', $this->pllm->get_language($this->pllm->options['default_lang'])))
14
- add_action('updated_option', array(&$this, 'updated_option'));
 
15
  }
16
 
17
- /*
18
- * get the language of strings sources
19
  *
20
  * @since 0.2
21
  *
22
- * @param string $name
23
  * @return object
24
  */
25
- protected function get_language($name) {
26
- return $this->pllm->get_language($this->pllm->options['default_lang']);;
 
27
  }
28
 
29
 
30
- /*
31
- * displays the icon of an uploaded strings group (no link)
32
  *
33
  * @since 0.2
34
  *
35
- * @param int $id
36
  */
37
- public static function uploaded_icon($id) {
38
- return self::display_icon('uploaded', '#');
39
  }
40
 
41
- /*
42
- * creates an html action link
43
  *
44
  * @since 0.2
45
  *
46
- * @param array $args parameters to add to the link
47
- * @param bool $warning whether to display an alert or not, optional, defaults to false
48
  * @return string
49
  */
50
- protected function get_action_link($args, $warning = false) {
51
  $args['page'] = 'lingotek-translation_manage';
52
  $args['noheader'] = true;
53
- return parent::get_action_link($args, $warning);
54
  }
55
 
56
- /*
57
- * adds a row actions links
58
  *
59
  * @since 0.2
60
  *
61
- * @param string $name strings group name
62
  * @return array
63
  */
64
- public function row_actions($name) {
65
- return $this->_row_actions(array(), $name);
66
  }
67
 
68
- /*
69
- * manages Lingotek actions
70
  *
71
  * @since 0.2
 
 
72
  */
73
- public function manage_actions($action) {
74
 
75
- $redirect = remove_query_arg( array('action', 'action2'), wp_get_referer() );
76
- if (!$redirect)
77
- $redirect = admin_url("admin.php?page=lingotek-translation_manage&sm=strings");
 
78
 
79
- switch($action) {
80
  case 'bulk-lingotek-upload':
81
  $ids = array();
82
 
83
- foreach ($_REQUEST['strings'] as $id) {
84
- // safe upload
85
- if ($this->lgtm->can_upload('string', $id))
86
  $ids[] = $id;
 
87
  }
88
 
89
  case 'bulk-lingotek-request':
90
  case 'bulk-lingotek-download':
91
  case 'bulk-lingotek-status':
92
  case 'bulk-lingotek-delete':
93
- if (empty($ids)) {
94
- if (empty($_REQUEST['strings']))
95
  return;
 
96
 
97
  $ids = $_REQUEST['strings'];
98
  }
99
 
100
- check_admin_referer('bulk-lingotek-strings-translations');
101
- $redirect = add_query_arg($action, 1, $redirect);
102
- $redirect = add_query_arg('ids', implode(',', array_map('intval', $ids)), $redirect);
103
 
104
  break;
105
 
106
  case 'lingotek-upload':
107
- check_admin_referer('lingotek-upload');
108
- $this->lgtm->upload_strings($_GET['string']);
109
  break;
110
 
111
  default:
112
- if (!$this->_manage_actions($action))
113
- return; // do not redirect if this is not one of our actions
114
-
115
  }
116
 
117
- wp_redirect($redirect);
118
  exit();
119
 
120
  }
121
 
122
- /*
123
- * ajax response to upload documents and showing progress
124
  *
125
  * @since 0.2
126
  */
127
  public function ajax_upload() {
128
- check_ajax_referer('lingotek_progress', '_lingotek_nonce');
129
- $this->lgtm->upload_strings($_POST['id']);
130
  die();
131
  }
132
 
133
- /*
134
- * automatic upload of strings when an option is updated
135
  *
136
  * @since 0.2
137
  */
138
  public function updated_option() {
139
- foreach (Lingotek_Model::get_strings() as $id) {
140
- if ($this->lgtm->can_upload('string', $id['context']))
141
- $this->lgtm->upload_strings($id['context']);
 
142
  }
143
  }
144
  }
1
  <?php
2
 
3
+ /**
4
+ * Lingotek String Actions class.
5
+ */
6
  class Lingotek_String_actions extends Lingotek_Actions {
7
 
8
+ /**
9
  * Constructor
10
  *
11
  * @since 0.2
12
  */
13
  public function __construct() {
14
+ parent::__construct( 'string' );
15
 
16
+ if ( isset( $this->pllm->options['default_lang'] ) && 'automatic' === Lingotek_Model::get_profile_option( 'upload', 'string', $this->pllm->get_language( $this->pllm->options['default_lang'] ) ) ) {
17
+ add_action( 'updated_option', array( &$this, 'updated_option' ) );
18
+ }
19
  }
20
 
21
+ /**
22
+ * Get the language of strings sources
23
  *
24
  * @since 0.2
25
  *
26
+ * @param string $name name.
27
  * @return object
28
  */
29
+ protected function get_language( $name ) {
30
+ return $this->pllm->get_language( $this->pllm->options['default_lang'] );
31
+ ;
32
  }
33
 
34
 
35
+ /**
36
+ * Displays the icon of an uploaded strings group (no link)
37
  *
38
  * @since 0.2
39
  *
40
+ * @param int $id id.
41
  */
42
+ public static function uploaded_icon( $id ) {
43
+ return self::display_icon( 'uploaded', '#' );
44
  }
45
 
46
+ /**
47
+ * Creates an html action link
48
  *
49
  * @since 0.2
50
  *
51
+ * @param array $args parameters to add to the link.
52
+ * @param bool $warning whether to display an alert or not, optional, defaults to false.
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
  }
60
 
61
+ /**
62
+ * Adds a row actions links.
63
  *
64
  * @since 0.2
65
  *
66
+ * @param string $name strings group name.
67
  * @return array
68
  */
69
+ public function row_actions( $name ) {
70
+ return $this->_row_actions( array(), $name );
71
  }
72
 
73
+ /**
74
+ * Manages Lingotek actions
75
  *
76
  * @since 0.2
77
+ *
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' );
85
+ }
86
 
87
+ switch ( $action ) {
88
  case 'bulk-lingotek-upload':
89
  $ids = array();
90
 
91
+ foreach ( $_REQUEST['strings'] as $id ) {
92
+ // safe upload.
93
+ if ( $this->lgtm->can_upload( 'string', $id ) ) {
94
  $ids[] = $id;
95
+ }
96
  }
97
 
98
  case 'bulk-lingotek-request':
99
  case 'bulk-lingotek-download':
100
  case 'bulk-lingotek-status':
101
  case 'bulk-lingotek-delete':
102
+ if ( empty( $ids ) ) {
103
+ if ( empty( $_REQUEST['strings'] ) ) {
104
  return;
105
+ }
106
 
107
  $ids = $_REQUEST['strings'];
108
  }
109
 
110
+ check_admin_referer( 'bulk-lingotek-strings-translations' );
111
+ $redirect = add_query_arg( $action, 1, $redirect );
112
+ $redirect = add_query_arg( 'ids', implode( ',', array_map( 'intval', $ids ) ), $redirect );
113
 
114
  break;
115
 
116
  case 'lingotek-upload':
117
+ check_admin_referer( 'lingotek-upload' );
118
+ $this->lgtm->upload_strings( $_GET['string'] );
119
  break;
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
+ /**
133
+ * Ajax response to upload documents and showing progress
134
  *
135
  * @since 0.2
136
  */
137
  public function ajax_upload() {
138
+ check_ajax_referer( 'lingotek_progress', '_lingotek_nonce' );
139
+ $this->lgtm->upload_strings( filter_input( INPUT_POST, 'id' ) );
140
  die();
141
  }
142
 
143
+ /**
144
+ * Automatic upload of strings when an option is updated
145
  *
146
  * @since 0.2
147
  */
148
  public function updated_option() {
149
+ foreach ( Lingotek_Model::get_strings() as $id ) {
150
+ if ( $this->lgtm->can_upload( 'string', $id['context'] ) ) {
151
+ $this->lgtm->upload_strings( $id['context'] );
152
+ }
153
  }
154
  }
155
  }
admin/strings-table.php CHANGED
@@ -1,102 +1,126 @@
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
  class Lingotek_Strings_Table extends WP_List_Table {
8
- public $pllm, $lgtm, $string_actions;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
- /*
11
- * constructor
12
  *
13
  * @since 0.2
 
14
  */
15
- function __construct($string_actions) {
16
  parent::__construct(array(
17
- 'plural' => 'lingotek-strings-translations', // do not translate (used for css class)
18
- 'ajax' => false
19
  ));
20
  $this->pllm = $GLOBALS['polylang']->model;
21
  $this->lgtm = $GLOBALS['wp_lingotek']->model;
22
  $this->string_actions = $string_actions;
23
  }
24
 
25
- /*
26
- * displays the item information in a column (default case)
27
  *
28
  * @since 0.2
29
  *
30
- * @param array $item
31
- * @param string $column_name
32
- * @return string
33
  */
34
- function column_default($item, $column_name) {
35
- // generic case (count)
36
- if (false === strpos($column_name, 'language_'))
37
- return $item[$column_name];
38
-
39
- // language column
40
- $language = $this->pllm->get_language(substr($column_name, 9));
41
- $document = $this->lgtm->get_group('string', $item['context']); // FIXME
42
-
43
- // post ready for upload
44
- if ($this->lgtm->can_upload('string', $item['context']) && $language->slug == $this->pllm->options['default_lang'])
45
- echo $this->string_actions->upload_icon($item['context']);
46
-
47
- // translation disabled
48
- elseif (isset($document->source) && $document->is_disabled_target($language))
49
- echo '<div class="lingotek-color dashicons dashicons-no"></div>';
50
-
51
- // source post is uploaded
52
- elseif (isset($document->source) && $document->source == $language->mo_id)
53
- echo 'importing' == $document->status ? Lingotek_Actions::importing_icon($document) : Lingotek_String_actions::uploaded_icon($item['context']);
54
-
55
- // translations
56
- elseif (isset($document->translations[$language->locale]) || (isset($document->source) && 'current' == $document->status))
57
- echo Lingotek_Actions::translation_icon($document, $language);
58
 
59
- // no translation
60
- else
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  echo '<div class="lingotek-color dashicons dashicons-no"></div>';
 
 
 
 
 
 
 
 
 
62
 
63
  $language_only = 'language_' . $language->slug;
64
- $errors = get_option('lingotek_log_errors');
65
- if ($language_only == $this->get_first_language_column()) {
66
- if (isset($errors[$item['context']])) {
67
- $api_error = Lingotek_Actions::retrieve_api_error($errors[$item['context']]);
68
- echo Lingotek_Actions::display_error_icon('error', $api_error);
69
  }
70
  }
71
  }
72
 
73
- /*
74
- * displays the checkbox in first column
75
  *
76
  * @since 0.2
77
  *
78
- * @param array $item
79
  * @return string
80
  */
81
- function column_cb($item){
82
- return sprintf('<input type="checkbox" name="strings[]" value="%d" />', esc_attr($item['row']));
83
  }
84
 
85
- /*
86
- * displays the item information in the column 'group'
87
  * displays the row actions links
88
  *
89
  * @since 0.2
90
  *
91
- * @param object $item
92
  * @return string
93
  */
94
- function column_context($item) {
95
- return $item['context'] . $this->row_actions($this->string_actions->row_actions($item['context']));
96
  }
97
 
98
- /*
99
- * gets the list of columns
100
  *
101
  * @since 0.2
102
  *
@@ -104,25 +128,24 @@ class Lingotek_Strings_Table extends WP_List_Table {
104
  */
105
  function get_columns() {
106
  $columns = array(
107
- 'cb' => '<input type="checkbox" />', //checkbox
108
- 'context' => __('Group', 'lingotek-translation'),
109
- 'count' => __('Count', 'lingotek-translation'),
110
  );
111
 
112
- foreach ($GLOBALS['polylang']->model->get_languages_list() as $lang) {
113
- if (!$lang->flag) {
114
- $columns['language_' . $lang->slug] = $lang->slug;
115
- }
116
- else {
117
- $columns['language_' . $lang->slug] = $lang->flag;
118
  }
119
  }
120
 
121
  return $columns;
122
  }
123
 
124
- /*
125
- * gets the list of sortable columns
126
  *
127
  * @since 0.2
128
  *
@@ -130,65 +153,74 @@ class Lingotek_Strings_Table extends WP_List_Table {
130
  */
131
  function get_sortable_columns() {
132
  return array(
133
- 'context' => array('context', false),
134
- 'count' => array('count', false),
135
  );
136
  }
137
 
138
- /*
139
- * prepares the list of items ofr displaying
140
  *
141
  * @since 0.2
142
  *
143
- * @param array $data
144
  */
145
- function prepare_items($data = array()) {
146
- $per_page = $this->get_items_per_page('lingotek_strings_per_page');
147
- $this->_column_headers = array($this->get_columns(), array(), $this->get_sortable_columns());
148
-
149
- function usort_reorder($a, $b){
150
- $result = strcmp($a[$_REQUEST['orderby']], $b[$_REQUEST['orderby']]); // determine sort order
151
- return (empty($_REQUEST['order']) || $_REQUEST['order'] == 'asc') ? $result : -$result; // send final sort direction to usort
 
 
 
 
 
 
 
152
  };
153
 
154
- if (!empty($_REQUEST['orderby'])) // no sort by default
155
- usort($data, 'usort_reorder');
 
156
 
157
- $total_items = count($data);
158
- $this->items = array_slice($data, ($this->get_pagenum() - 1) * $per_page, $per_page);
159
 
160
  $this->set_pagination_args(array(
161
  'total_items' => $total_items,
162
  'per_page' => $per_page,
163
- 'total_pages' => ceil($total_items/$per_page)
164
  ));
165
  }
166
 
167
- /*
168
- * get the list of possible bulk actions
169
  *
170
  * @since 0.2
171
  *
172
  * @return array
173
  */
174
  function get_bulk_actions() {
175
- foreach (Lingotek_String_actions::$actions as $action => $strings)
176
- $arr['bulk-lingotek-' . $action] = $strings['action'];
 
177
  return $arr;
178
  }
179
 
180
- /*
181
- * returns the first language column
182
  *
183
  * @since 1.2
184
  *
185
  * @return string first language column name
186
  */
187
  protected function get_first_language_column() {
188
- foreach ($this->pllm->get_languages_list() as $language) {
189
- $columns[] = 'language_'.$language->slug;
190
  }
191
 
192
- return empty($columns) ? '' : reset($columns);
193
  }
194
  }
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
+ * Lingotek Strings Table class.
9
+ */
10
  class Lingotek_Strings_Table extends WP_List_Table {
11
+ /**
12
+ * Polylang model.
13
+ *
14
+ * @var object
15
+ */
16
+ public $pllm;
17
+ /**
18
+ * Lingotek model.
19
+ *
20
+ * @var object.
21
+ */
22
+ public $lgtm;
23
+ /**
24
+ * String actions.
25
+ *
26
+ * @var object
27
+ */
28
+ public $string_actions;
29
 
30
+ /**
31
+ * Constructor
32
  *
33
  * @since 0.2
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
 
46
+ /**
47
+ * Displays the item information in a column (default case)
48
  *
49
  * @since 0.2
50
  *
51
+ * @param array $item item.
52
+ * @param string $column_name column name.
 
53
  */
54
+ function column_default( $item, $column_name ) {
55
+ // generic case (count).
56
+ if ( false === strpos( $column_name, 'language_' ) ) {
57
+ return $item[ $column_name ];
58
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ $allowed_html = [
65
+ 'a' => [
66
+ 'class' => array(),
67
+ 'title' => array(),
68
+ 'href' => array(),
69
+ ],
70
+ ];
71
+ // post ready for upload.
72
+ if ( $this->lgtm->can_upload( 'string', $item['context'] ) && $language->slug === $this->pllm->options['default_lang'] ) {
73
+ echo wp_kses( $this->string_actions->upload_icon( $item['context'] ), $allowed_html );
74
+ } // translation disabled.
75
+ elseif ( isset( $document->source ) && $document->is_disabled_target( $language ) ) {
76
  echo '<div class="lingotek-color dashicons dashicons-no"></div>';
77
+ } // source post is uploaded.
78
+ elseif ( isset( $document->source ) && $document->source === $language->mo_id ) {
79
+ echo wp_kses( 'importing' === $document->status ? Lingotek_Actions::importing_icon( $document ) : Lingotek_String_actions::uploaded_icon( $item['context'] ), $allowed_html );
80
+ } // translations.
81
+ elseif ( isset( $document->translations[ $language->locale ] ) || (isset( $document->source ) && 'current' === $document->status) ) {
82
+ echo wp_kses( Lingotek_Actions::translation_icon( $document, $language ), $allowed_html );
83
+ } // no translation.
84
+ else { echo '<div class="lingotek-color dashicons dashicons-no"></div>';
85
+ }
86
 
87
  $language_only = 'language_' . $language->slug;
88
+ $errors = get_option( 'lingotek_log_errors' );
89
+ if ( $language_only === $this->get_first_language_column() ) {
90
+ if ( isset( $errors[ $item['context'] ] ) ) {
91
+ $api_error = Lingotek_Actions::retrieve_api_error( $errors[ $item['context'] ] );
92
+ echo esc_html( Lingotek_Actions::display_error_icon( 'error', $api_error ) );
93
  }
94
  }
95
  }
96
 
97
+ /**
98
+ * Displays the checkbox in first column
99
  *
100
  * @since 0.2
101
  *
102
+ * @param array $item item.
103
  * @return string
104
  */
105
+ function column_cb( $item ) {
106
+ return sprintf( '<input type="checkbox" name="strings[]" value="%d" />', esc_attr( $item['row'] ) );
107
  }
108
 
109
+ /**
110
+ * Displays the item information in the column 'group'
111
  * displays the row actions links
112
  *
113
  * @since 0.2
114
  *
115
+ * @param object $item item.
116
  * @return string
117
  */
118
+ function column_context( $item ) {
119
+ return $item['context'] . $this->row_actions( $this->string_actions->row_actions( $item['context'] ) );
120
  }
121
 
122
+ /**
123
+ * Gets the list of columns
124
  *
125
  * @since 0.2
126
  *
128
  */
129
  function get_columns() {
130
  $columns = array(
131
+ 'cb' => '<input type="checkbox" />', // checkbox.
132
+ 'context' => __( 'Group', 'lingotek-translation' ),
133
+ 'count' => __( 'Count', 'lingotek-translation' ),
134
  );
135
 
136
+ foreach ( $GLOBALS['polylang']->model->get_languages_list() as $lang ) {
137
+ if ( ! $lang->flag ) {
138
+ $columns[ 'language_' . $lang->slug ] = $lang->slug;
139
+ } else {
140
+ $columns[ 'language_' . $lang->slug ] = $lang->flag;
 
141
  }
142
  }
143
 
144
  return $columns;
145
  }
146
 
147
+ /**
148
+ * Gets the list of sortable columns
149
  *
150
  * @since 0.2
151
  *
153
  */
154
  function get_sortable_columns() {
155
  return array(
156
+ 'context' => array( 'context', false ),
157
+ 'count' => array( 'count', false ),
158
  );
159
  }
160
 
161
+ /**
162
+ * Prepares the list of items ofr displaying
163
  *
164
  * @since 0.2
165
  *
166
+ * @param array $data data.
167
  */
168
+ function prepare_items( $data = array() ) {
169
+ $per_page = $this->get_items_per_page( 'lingotek_strings_per_page' );
170
+ $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() );
171
+
172
+ /**
173
+ * Custom sorting comparator.
174
+ *
175
+ * @param array $a array of strings.
176
+ * @param array $b array of strings.
177
+ * @return int sort direction.
178
+ */
179
+ function usort_reorder( $a, $b ) {
180
+ $result = strcmp( $a[ filter_input( INPUT_GET, 'orderby' ) ], $b[ filter_input( INPUT_GET, 'orderby' ) ] ); // determine sort order.
181
+ return (empty( filter_input( INPUT_GET, 'order' ) ) || 'asc' === filter_input( INPUT_GET, 'order' ) ) ? $result : -$result; // send final sort direction to usort.
182
  };
183
 
184
+ if ( ! empty( filter_input( INPUT_GET, 'orderby' ) ) ) { // no sort by default.
185
+ usort( $data, 'usort_reorder' );
186
+ }
187
 
188
+ $total_items = count( $data );
189
+ $this->items = array_slice( $data, ($this->get_pagenum() - 1) * $per_page, $per_page );
190
 
191
  $this->set_pagination_args(array(
192
  'total_items' => $total_items,
193
  'per_page' => $per_page,
194
+ 'total_pages' => ceil( $total_items / $per_page ),
195
  ));
196
  }
197
 
198
+ /**
199
+ * Get the list of possible bulk actions
200
  *
201
  * @since 0.2
202
  *
203
  * @return array
204
  */
205
  function get_bulk_actions() {
206
+ foreach ( Lingotek_String_actions::$actions as $action => $strings ) {
207
+ $arr[ 'bulk-lingotek-' . $action ] = $strings['action'];
208
+ }
209
  return $arr;
210
  }
211
 
212
+ /**
213
+ * Returns the first language column
214
  *
215
  * @since 1.2
216
  *
217
  * @return string first language column name
218
  */
219
  protected function get_first_language_column() {
220
+ foreach ( $this->pllm->get_languages_list() as $language ) {
221
+ $columns[] = 'language_' . $language->slug;
222
  }
223
 
224
+ return empty( $columns ) ? '' : reset( $columns );
225
  }
226
  }
admin/table-string.php CHANGED
@@ -1,74 +1,79 @@
1
- <?php
2
-
3
- /*
4
- * extends the Polylang class to disable the input fields
5
- *
6
- * @since 0.3
7
- */
8
- class Lingotek_Table_String extends PLL_Table_String {
9
- /*
10
- * displays the translations to edit (disabled)
11
- *
12
- * @since 0.3
13
- *
14
- * @param array $item
15
- * @return string
16
- */
17
- function column_translations($item) {
18
- $out = '';
19
- foreach($item['translations'] as $key => $translation) {
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
- }
31
-
32
- function prepare_items($data = null) {
33
- $listlanguages = $GLOBALS['polylang']->model->get_languages_list();
34
- // $data = $this->strings;
35
-
36
- // Filter for search string
37
- $s = empty( $_GET['s'] ) ? '' : wp_unslash( $_GET['s'] );
38
- foreach ( $data as $key => $row ) {
39
- if ( ( -1 !== $this->selected_group && $row['context'] !== $this->selected_group ) || ( ! empty( $s ) && stripos( $row['name'], $s ) === false && stripos( $row['string'], $s ) === false ) ) {
40
- unset( $data[ $key ] );
41
- }
42
- }
43
-
44
- // Load translations
45
- foreach ($listlanguages as $language) {
46
- // filters by language if requested
47
- if (($lg = get_user_meta(get_current_user_id(), 'pll_filter_content', true)) && $language->slug != $lg)
48
- continue;
49
-
50
- $mo = new PLL_MO();
51
- $mo->import_from_db($language);
52
- foreach ($data as $key=>$row) {
53
- $data[$key]['translations'][$language->slug] = $mo->translate($row['string']);
54
- $data[$key]['row'] = $key; // store the row number for convenience
55
- }
56
- }
57
-
58
- $per_page = $this->get_items_per_page( 'pll_strings_per_page' );
59
- $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() );
60
-
61
- if ( ! empty( $_GET['orderby'] ) ) { // No sort by default
62
- usort( $data, array( $this, 'usort_reorder' ) );
63
- }
64
-
65
- $total_items = count( $data );
66
- $this->items = array_slice( $data, ( $this->get_pagenum() - 1 ) * $per_page, $per_page );
67
-
68
- $this->set_pagination_args( array(
69
- 'total_items' => $total_items,
70
- 'per_page' => $per_page,
71
- 'total_pages' => ceil( $total_items / $per_page ),
72
- ) );
73
- }
74
- }
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Extends the Polylang class to disable the input fields
5
+ *
6
+ * @since 0.3
7
+ */
8
+ class Lingotek_Table_String extends PLL_Table_String {
9
+ /**
10
+ * Displays the translations to edit (disabled).
11
+ *
12
+ * @since 0.3
13
+ *
14
+ * @param array $item item.
15
+ * @return string
16
+ */
17
+ function column_translations( $item ) {
18
+ $out = '';
19
+ foreach ( $item['translations'] as $key => $translation ) {
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
+ }
31
+
32
+ /**
33
+ * Prepares items for display.
34
+ *
35
+ * @param array $data data.
36
+ */
37
+ function prepare_items( $data = null ) {
38
+ $listlanguages = $GLOBALS['polylang']->model->get_languages_list();
39
+
40
+ // Filter for search string.
41
+ $s = empty( filter_input( INPUT_GET, 's' ) ) ? '' : wp_unslash( filter_input( INPUT_GET, 's' ) );
42
+ foreach ( $data as $key => $row ) {
43
+ if ( ( -1 !== $this->selected_group && $row['context'] !== $this->selected_group ) || ( ! empty( $s ) && stripos( $row['name'], $s ) === false && stripos( $row['string'], $s ) === false ) ) {
44
+ unset( $data[ $key ] );
45
+ }
46
+ }
47
+
48
+ // Load translations.
49
+ foreach ( $listlanguages as $language ) {
50
+ // filters by language if requested.
51
+ if ( ($lg = get_user_meta( get_current_user_id(), 'pll_filter_content', true )) && $language->slug !== $lg ) {
52
+ continue;
53
+ }
54
+
55
+ $mo = new PLL_MO();
56
+ $mo->import_from_db( $language );
57
+ foreach ( $data as $key => $row ) {
58
+ $data[ $key ]['translations'][ $language->slug ] = $mo->translate( $row['string'] );
59
+ $data[ $key ]['row'] = $key; // store the row number for convenience.
60
+ }
61
+ }
62
+
63
+ $per_page = $this->get_items_per_page( 'pll_strings_per_page' );
64
+ $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() );
65
+
66
+ if ( ! empty( filter_input( INPUT_GET, 'orderby' ) ) ) { // No sort by default.
67
+ usort( $data, array( $this, 'usort_reorder' ) );
68
+ }
69
+
70
+ $total_items = count( $data );
71
+ $this->items = array_slice( $data, ( $this->get_pagenum() - 1 ) * $per_page, $per_page );
72
+
73
+ $this->set_pagination_args( array(
74
+ 'total_items' => $total_items,
75
+ 'per_page' => $per_page,
76
+ 'total_pages' => ceil( $total_items / $per_page ),
77
+ ) );
78
+ }
79
+ }
admin/workflows/professional-translation-workflow.php ADDED
@@ -0,0 +1,105 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ */
6
+ class Lingotek_Professional_Translation_Workflow extends Lingotek_Workflow {
7
+
8
+ /**
9
+ * Adds the thickbox Wordpress component. Loades the professional-workflow js file that attaches listeners to uploads.
10
+ * Sends the workflow id to the js file.
11
+ *
12
+ * @param string $id the workflow id.
13
+ */
14
+ public function override_events( $id ) {
15
+ add_thickbox();
16
+ wp_enqueue_script( 'lingotek_professional_workflow', LINGOTEK_URL . '/js/workflow/professional-workflow.js' );
17
+ $vars = [
18
+ 'id' => $id,
19
+ ];
20
+ wp_localize_script( 'lingotek_professional_workflow', 'workflow_vars', $vars );
21
+ }
22
+
23
+ /**
24
+ * Writes a modal to the output buffer that contains information about this workflow.
25
+ *
26
+ * @param string $id the workflow id.
27
+ */
28
+ public function echo_info_modal( $id ) {
29
+ if ( ! $this->info_modal_launched ) {
30
+ $this->info_modal_launched = true;
31
+ $args = [
32
+ 'header' => __( 'Professional Translation Workflow', 'lingotek-translation' ),
33
+ 'body' => __( "The Professional Translation Workflow allows you to have any of your content
34
+ translated professionally. Translations are priced by word count and can be requested from within
35
+ the Wordpress Posts or Pages tab.
36
+ <br><br>In order to use this workflow you must set up a payment method and purchase Word Credits.
37
+ <br><br>Would you like to set up a payment method?", 'lingotek-translation' ),
38
+ 'id' => $id,
39
+ ];
40
+ $this->_echo_modal( $args );
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Writes a modal to the output buffer that tells the user how much it is going to cost.
46
+ *
47
+ * @param string $id the workflow id.
48
+ */
49
+ public function echo_posts_modal( $id ) {
50
+ if ( ! $this->post_modal_launched ) {
51
+ $this->post_modal_launched = true;
52
+ $args = [
53
+ 'header' => __( 'Confirm Document Upload', 'lingotek-translation' ),
54
+ 'body' => __( "You have the Professional Translation workflow selected. This means that all
55
+ translations of this document will cost Word Credits.
56
+ <br><br>Any translations of the uploaded document will be <b>final</b>. A new transaction(s) will be made if this document is
57
+ edited and re-translations are requested.
58
+ <br><br>Would you like to continue?", 'lingotek-translation' ),
59
+ 'id' => $id,
60
+ ];
61
+ $this->_echo_modal( $args );
62
+ $this->echo_request_modal( $id );
63
+ }
64
+ }
65
+
66
+
67
+ /**
68
+ * Writes a modal to the output buffer that tells the user how much it is going to cost.
69
+ *
70
+ * @param string $id the workflow id.
71
+ */
72
+ public function echo_terms_modal( $id ) {
73
+ if ( ! $this->terms_modal_launched ) {
74
+ $this->terms_modal_launched = true;
75
+ $args = [
76
+ 'header' => __( 'Lingotek Terms', 'lingotek-translation' ),
77
+ 'body' => __( 'This is an example of a terms modal.', 'lingotek-translation' ),
78
+ 'id' => $id,
79
+ ];
80
+ $this->_echo_modal( $args );
81
+ $this->echo_request_modal( $id );
82
+ }
83
+
84
+ }
85
+
86
+ /**
87
+ * Writes a modal to the output buffer that is launched when the user clicks on the 'request translation'
88
+ * option.
89
+ *
90
+ * @param string $id the workflow id.
91
+ */
92
+ public function echo_request_modal( $id ) {
93
+ $args = [
94
+ 'header' => __( 'Confirm Request Translation', 'lingotek-translation' ),
95
+ 'body' => __( "You have the Professional Translation workflow selected. This document will be translated by a professional
96
+ in the selected language.
97
+
98
+ <br><br>The approximated cost to translate this document is 13 Word Credits.
99
+ <br><br>The translation request is <b>final</b> meaning that if the source document is changed then it will cost Word Credits to request re-translation.
100
+ <br><br> Would you like to request this translation?", 'lingotek-translation' ),
101
+ 'id' => $id . '-request',
102
+ ];
103
+ $this->_echo_modal( $args );
104
+ }
105
+ }
admin/workflows/workflow-factory.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * WorkflowFactory
5
+ *
6
+ * Returns an instance of a Workflow object.
7
+ */
8
+ class Lingotek_Workflow_Factory {
9
+
10
+ const BASE_WORKFLOW = 'Lingotek_Workflow';
11
+
12
+ /**
13
+ * Constructor. Loads the base workflow class and the base workflow js file.
14
+ */
15
+ public function __construct() {
16
+ self::class_load( self::BASE_WORKFLOW );
17
+ wp_enqueue_script( 'lingotek_workflow_namespace', LINGOTEK_URL . '/js/workflow/workflow.js' );
18
+ }
19
+ /**
20
+ * An associative array that maps a workflowId to a Workflow object.
21
+ *
22
+ * @var array
23
+ */
24
+ private static $map = [
25
+ 'professional-translation' => 'Lingotek_Professional_Translation_Workflow',
26
+ ];
27
+
28
+ /**
29
+ * Checks the map to see if a specialized workflow exists. A BasicWorkflow is returned
30
+ * if a specialized workflow type does not exist.
31
+ *
32
+ * @param string $workflow_id the Id of the given workflow.
33
+ */
34
+ public static function get_workflow_instance( $workflow_id ) {
35
+ if ( ! isset( self::$map[ $workflow_id ] ) )
36
+ {
37
+ return new Lingotek_Workflow();
38
+ }
39
+ else
40
+ {
41
+ self::class_load( self::$map[ $workflow_id ] );
42
+ return new self::$map[ $workflow_id ]();
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Echos the information modals describing various details about the workflow.
48
+ */
49
+ public static function echo_info_modals() {
50
+ add_thickbox();
51
+ foreach ( self::$map as $id => $class ) {
52
+ $workflow = new $class();
53
+ $workflow->echo_info_modal( $id );
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Lazyloads classes as they are needed.
59
+ *
60
+ * @param string $class class name to be loaded.
61
+ */
62
+ private static function class_load( $class ) {
63
+ if ( ! isset( $class ) ) { return; }
64
+ if ( ! class_exists( $class ) ) { require_once( LINGOTEK_WORKFLOWS . '/' . Lingotek::convert_class_to_file( $class ) . '.php' ); }
65
+ }
66
+ }
admin/workflows/workflow.php ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * The base class that all specialized workflows can override.
5
+ */
6
+ class Lingotek_Workflow {
7
+
8
+ /**
9
+ * If a modal has already been written to the output buffer then we don't
10
+ * want to write it again.
11
+ *
12
+ * @var boolean
13
+ */
14
+ protected $info_modal_launched = false;
15
+
16
+ /**
17
+ * If a modal has already been written to the output buffer then we don't
18
+ * want to write it again.
19
+ *
20
+ * @var boolean
21
+ */
22
+ protected $post_modal_launched = false;
23
+
24
+ /**
25
+ * If a modal has already been written to the output buffer then we don't
26
+ * want to write it again.
27
+ *
28
+ * @var boolean
29
+ */
30
+ protected $terms_modal_launched = false;
31
+
32
+ /**
33
+ * This method is called when the Posts or Pages pages are loaded. The overriding class may choose to
34
+ * load a custom js file to handle events or do any sort of custom 'prep work'.
35
+ *
36
+ * @param string $id the workflow id.
37
+ */
38
+ public function override_events( $id ) {}
39
+
40
+ /**
41
+ * Writes a modal to the output buffer. This is called when the Translation > Settings > Defaults pages is loaded.
42
+ * The modal should contain information about the workflow.
43
+ * NOTE: The workflow-defaults.js file is already loaded and set up to launch this modal. The workflow_id embedded in the
44
+ * html is used to identify the modal and show it to the user.
45
+ *
46
+ * @param string $id the workflow id.
47
+ */
48
+ public function echo_info_modal( $id ) {}
49
+
50
+ /**
51
+ * This method is called when the Posts or Pages columns are being rendered.
52
+ *
53
+ * @param string $id the workflow id.
54
+ */
55
+ public function echo_posts_modal( $id ) {}
56
+
57
+ /**
58
+ * This method is called when the Terms table is being rendered.
59
+ *
60
+ * @param string $id the workflow id.
61
+ */
62
+ public function echo_terms_modal( $id ) {}
63
+
64
+ /**
65
+ * This method writes the modal that should be displayed when
66
+ * the request icon is clicked.
67
+ *
68
+ * @param string $id the workflow id.
69
+ */
70
+ public function echo_request_modal( $id ) {}
71
+
72
+ /**
73
+ * This method acts as a template for building the modals. The arguments passed
74
+ * are inserted into the html string and then echo'd. If any extra html elements
75
+ * need to be added at a later date, they must be added to the $allowed_html array so
76
+ * that they are not stripped away during the wp_kses() call.
77
+ *
78
+ * @param array $args the arguments to populate the modal.
79
+ */
80
+ protected function _echo_modal( $args ) {
81
+ /**
82
+ * This allows us to use the 'display' CSS attribute. WP
83
+ * blacklists it by default.
84
+ */
85
+ add_filter( 'safe_style_css', function( $styles ) {
86
+ $styles[] = 'display';
87
+ $styles[] = 'position';
88
+ $styles[] = 'bottom';
89
+ return $styles;
90
+ } );
91
+
92
+ $allowed_html = [
93
+ 'div' => [
94
+ 'id' => [],
95
+ 'style' => [],
96
+ ],
97
+ 'h2' => [
98
+ 'style' => [],
99
+ ],
100
+ 'br' => [],
101
+ 'b' => [],
102
+ 'p' => [
103
+ 'style' => [],
104
+ ],
105
+ 'a' => [
106
+ 'id' => [],
107
+ 'href' => [],
108
+ 'style' => [],
109
+ 'class' => []
110
+ ],
111
+ ];
112
+ $id = isset( $args['id'] ) ? '-' . $args['id'] : '';
113
+ echo wp_kses( "<div id='modal-window-id" . esc_attr( $id ) . "' style='display:none; height:100%;' >
114
+ <h2 style='text-align:center; font-size:large;'>" . esc_html( $args['header'] ) . "</h2>
115
+ <p style='text-align:center; font-size:110%;'>" . wp_kses( $args['body'], $allowed_html ) . "</p>
116
+ <br>
117
+ <a id='yes" . esc_attr( $id ) . "' class='lingotek-color dashicons' href='#' style='position:absolute; float:left; bottom:30px;'>Continue</a>
118
+ <div style='float:right; padding-right:55px;'>
119
+ <a id='no" . esc_attr( $id ) . "' class='lingotek-color dashicons' href='#' style='position:absolute; float:right; bottom:30px;'>Cancel</a>
120
+ </div>
121
+ </div>", $allowed_html);
122
+ }
123
+ }
include/group-post.php CHANGED
@@ -263,7 +263,7 @@ class Lingotek_Group_Post extends Lingotek_Group {
263
  public static function is_valid_auto_upload_post_status($post_status) {
264
  $prefs = Lingotek_Model::get_prefs();
265
  $valid_statuses = $prefs['auto_upload_post_statuses'];
266
- $valid = array_key_exists($post_status, $valid_statuses) && $valid_statuses[$post_status];
267
  return $valid;
268
  }
269
 
@@ -294,14 +294,15 @@ class Lingotek_Group_Post extends Lingotek_Group {
294
 
295
  $client = new Lingotek_API();
296
 
297
- if (false === ($translation = $client->get_translation($this->document_id, $locale, $this->source))) {
298
- return;
299
- }
 
 
300
 
301
  self::$creating_translation = true;
302
  $prefs = Lingotek_Model::get_prefs(); // need an array by default
303
 
304
- $translation = json_decode($translation, true); // wp_insert_post expects array
305
  $tr_post = $translation['post'];
306
 
307
  $post = get_post($this->source); // source post
@@ -381,6 +382,17 @@ class Lingotek_Group_Post extends Lingotek_Group {
381
  add_filter('content_filtered_save_pre', 'wp_filter_post_kses');
382
  }
383
 
 
 
 
 
 
 
 
 
 
 
 
384
  /*
385
  * copies source meta strings to translations or deletes meta if set to ignore
386
  *
263
  public static function is_valid_auto_upload_post_status($post_status) {
264
  $prefs = Lingotek_Model::get_prefs();
265
  $valid_statuses = $prefs['auto_upload_post_statuses'];
266
+ $valid = isset( $valid_statuses[$post_status] ) && $valid_statuses[$post_status];
267
  return $valid;
268
  }
269
 
294
 
295
  $client = new Lingotek_API();
296
 
297
+ $translation = $client->get_translation($this->document_id, $locale, $this->source);
298
+
299
+ if (!$translation || $this->translationNotReady( json_decode($translation, true) )) return; // If the request failed.
300
+
301
+ $translation = json_decode($translation, true); // wp_insert_post expects array
302
 
303
  self::$creating_translation = true;
304
  $prefs = Lingotek_Model::get_prefs(); // need an array by default
305
 
 
306
  $tr_post = $translation['post'];
307
 
308
  $post = get_post($this->source); // source post
382
  add_filter('content_filtered_save_pre', 'wp_filter_post_kses');
383
  }
384
 
385
+ /**
386
+ * TMS will return an associative array with empty fields if the translation is not ready.
387
+ *
388
+ * @param array $translation the array returned from TMS.
389
+ */
390
+ private function translationNotReady($translation) {
391
+ return empty( trim( $translation['post']['post_title'] ) ) &&
392
+ empty( trim( $translation['post']['post_content'] ) ) &&
393
+ empty( trim( $translation['post']['post_excerpt'] ) );
394
+ }
395
+
396
  /*
397
  * copies source meta strings to translations or deletes meta if set to ignore
398
  *
include/model.php CHANGED
@@ -130,8 +130,8 @@ class Lingotek_Model {
130
  }
131
  }
132
 
133
- // default profile is manual except for post
134
- $default = 'post' == $type ? 'automatic' : 'manual';
135
 
136
  $profile = isset($content_types[$type]['sources'][$language->slug]) ?
137
  $content_types[$type]['sources'][$language->slug] :
@@ -644,7 +644,7 @@ class Lingotek_Model {
644
 
645
  // if a post is not a target, then it is source
646
  $sources[$language->slug] = $n - $targets[$language->slug];
647
- $sources[$language->slug] -= $disabled[$language->slug];
648
  }
649
 
650
  // untranslated posts have no associated translation group in DB
@@ -665,7 +665,7 @@ class Lingotek_Model {
665
  // total of posts translations groups = untranslated + number of translation groups stored in DB
666
  $count_posts = (array) wp_count_posts($post_type);
667
  unset($count_posts['trash'], $count_posts['auto-draft']); // don't count trash and auto-draft
668
- $total = array_sum($count_posts) - $n_translated + count($groups) - array_sum($disabled);
669
 
670
  return $r[$post_type] = compact('sources', 'targets', 'total');
671
  }
@@ -738,7 +738,7 @@ class Lingotek_Model {
738
 
739
  // if a term is not a target, then it is a source
740
  $sources[$language->slug] = $n - $targets[$language->slug];
741
- $sources[$language->slug] -= $disabled[$language->slug];
742
  }
743
 
744
  $total = count($groups);
@@ -773,7 +773,7 @@ class Lingotek_Model {
773
  }
774
  }
775
 
776
- $total -= array_sum($disabled);
777
  return $r[$taxonomy] = compact('sources', 'targets', 'total');
778
  }
779
  }
130
  }
131
  }
132
 
133
+ // default profile is manual except for post. Custom types are set to disabled by default.
134
+ $default = 'post' == $type ? 'automatic' : ('page' === $type ? 'manual' : 'disabled');
135
 
136
  $profile = isset($content_types[$type]['sources'][$language->slug]) ?
137
  $content_types[$type]['sources'][$language->slug] :
644
 
645
  // if a post is not a target, then it is source
646
  $sources[$language->slug] = $n - $targets[$language->slug];
647
+ // $sources[$language->slug] -= $disabled[$language->slug];
648
  }
649
 
650
  // untranslated posts have no associated translation group in DB
665
  // total of posts translations groups = untranslated + number of translation groups stored in DB
666
  $count_posts = (array) wp_count_posts($post_type);
667
  unset($count_posts['trash'], $count_posts['auto-draft']); // don't count trash and auto-draft
668
+ $total = array_sum($count_posts) - $n_translated + count($groups);
669
 
670
  return $r[$post_type] = compact('sources', 'targets', 'total');
671
  }
738
 
739
  // if a term is not a target, then it is a source
740
  $sources[$language->slug] = $n - $targets[$language->slug];
741
+ // $sources[$language->slug] -= $disabled[$language->slug];
742
  }
743
 
744
  $total = count($groups);
773
  }
774
  }
775
 
776
+ // $total -= array_sum($disabled);
777
  return $r[$taxonomy] = compact('sources', 'targets', 'total');
778
  }
779
  }
js/workflow/professional-workflow.js ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(document).ready(function() {
2
+ var yes = '#yes-' + workflow_vars.id;
3
+ var no = '#no-' + workflow_vars.id;
4
+ var yes_request = yes + '-request';
5
+ var no_request = no + '-request';
6
+
7
+ jQuery(".dashicons-upload").on('click', function(event){
8
+ event.preventDefault();
9
+ jQuery(this).addClass('thickbox');
10
+ var url = Workflow.modals.replace_href(this);
11
+ jQuery(yes).attr('href', url);
12
+ jQuery(this).attr('href', '#TB_inline?width=500&height=300&inlineId=modal-window-id-' + workflow_vars.id);
13
+ });
14
+
15
+ jQuery(".dashicons-plus").on('click', function(event){
16
+ event.preventDefault();
17
+ jQuery(this).addClass('thickbox');
18
+ var url = Workflow.modals.replace_href(this);
19
+ jQuery(yes_request).attr('href', url);
20
+ jQuery(this).attr('href', '#TB_inline?width=500&height=300&inlineId=modal-window-id-' + workflow_vars.id + '-request');
21
+ });
22
+
23
+ jQuery(yes + ',' + yes_request).on('click', function() {
24
+ Workflow.modals.close_modal('TB_closeWindowButton');
25
+ });
26
+ jQuery(no + ',' + no_request).on('click', function() {
27
+ Workflow.modals.close_modal('TB_closeWindowButton');
28
+ });
29
+ })
js/workflow/workflow-defaults.js ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(document).ready(function() {
2
+ var lastSel = jQuery('#workflow_id option:selected');
3
+ // try new rollback here.
4
+ jQuery('select').change(function(e) {
5
+
6
+ if (Workflow.workflows.hasOwnProperty(this.value))
7
+ {
8
+ var workflow = this.value;
9
+ jQuery('#yes-' + workflow).attr('href', Workflow.workflows[this.value]);
10
+
11
+ jQuery('#no-' + workflow).on('click', function() {
12
+ lastSel.attr('selected', true);
13
+ Workflow.modals.close_modal('TB_closeWindowButton');
14
+ });
15
+
16
+ tb_show('Default Settings', '#TB_inline?width=500&height=300&inlineId=modal-window-id-' + workflow);
17
+ }
18
+ });
19
+ });
js/workflow/workflow.js ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Workflow = {};
2
+
3
+ Workflow.modals = {};
4
+
5
+ Workflow.modals.close_modal = function(id) {
6
+ jQuery('#' + id).trigger('click');
7
+ }
8
+
9
+ Workflow.modals.replace_href = function(element) {
10
+ if (!jQuery(element).attr('url'))
11
+ {
12
+ jQuery(element).attr('url', jQuery(element).attr('href'));
13
+ }
14
+ return jQuery(element).attr('url');
15
+ }
16
+
17
+ Workflow.workflows = {
18
+ 'professional-translation' : 'https://www.lingotek.com/'
19
+ }
lingotek.php CHANGED
@@ -1,66 +1,172 @@
1
  <?php
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.2.6
6
- Author: Lingotek and Frédéric Demarle
7
- Author uri: http://lingotek.com
8
- Description: Lingotek offers convenient cloud-based localization and translation.
9
- Text Domain: lingotek-translation
10
- Domain Path: /languages
11
- GitHub Plugin URI: https://github.com/lingotek/lingotek-translation
12
- */
13
-
14
- // don't access directly
15
- if (!function_exists('add_action'))
16
  exit();
 
17
 
18
- define('LINGOTEK_VERSION', '1.2.6'); // plugin version (should match above meta)
19
- define('LINGOTEK_MIN_PLL_VERSION', '1.8');
20
- define('LINGOTEK_BASENAME', plugin_basename(__FILE__)); // plugin name as known by WP
21
- define('LINGOTEK_PLUGIN_SLUG', 'lingotek-translation');// plugin slug (should match above meta: Text Domain)
22
- define('LINGOTEK_DIR', dirname(__FILE__)); // our directory
23
- define('LINGOTEK_INC', LINGOTEK_DIR . '/include');
24
- define('LINGOTEK_ADMIN_INC', LINGOTEK_DIR . '/admin');
25
- define('LINGOTEK_URL', plugins_url('', __FILE__));
 
26
 
27
  class Lingotek {
28
- public $model; // Lingotek model
 
 
 
 
 
 
 
 
 
 
 
29
  public $callback;
30
 
31
- // array to map Lingotek locales to WP locales
32
- // map as 'WP locale' => 'Lingotek locale'
 
 
 
 
33
  public static $lingotek_locales = array(
34
- 'af' => 'af-ZA', 'ak' => 'ak-GH', 'am' => 'am-ET', 'ar' => 'ar', 'as' => 'as-IN', 'az' => 'az-AZ',
35
- 'ba' => 'ba-RU', 'bel' => 'be-BY', 'bg_BG' => 'bg-BG', 'bn_BD' => 'bn-BD', 'bo' => 'bo-CN', 'bs_BA' => 'bs-BA',
36
- 'ca' => 'ca-ES', 'co' => 'co-FR', 'cs_CZ' => 'cs-CZ', 'cy' => 'cy-GB', 'da_DK' => 'da-DK', 'de_CH' => 'de-CH',
37
- 'de_DE' => 'de-DE', 'dv' => 'dv-MV', 'el' => 'el-GR', 'en_AU' => 'en-AU', 'en_CA' => 'en-CA', 'en_GB' => 'en-GB',
38
- 'en_US' => 'en-US', 'eo' => 'eo-FR', 'es_AR' => 'es-AR', 'es_CL' => 'es-CL', 'es_CO' => 'es-CO', 'es_ES' => 'es-ES',
39
- 'es_MX' => 'es-MX', 'es_PE' => 'es-PE', 'es_PR' => 'es-PR', 'es_VE' => 'es-VE', 'et' => 'et-EE', 'eu' => 'eu-ES',
40
- 'fa_IR' => 'fa-IR', 'fi' => 'fi-FI', 'fr_FR' => 'fr-FR', 'ga' => 'ga-IE', 'gd' => 'gd-GB', 'gl_ES' => 'gl-ES',
41
- 'gn' => 'gn-BO', 'haw_US' => 'haw-US', 'he_IL' => 'he-IL', 'hi_IN' => 'hi-IN', 'hr' => 'hr-HR', 'hu_HU' => 'hu-HU',
42
- 'hy' => 'hy-AM', 'id_ID' => 'id-ID', 'is_IS' => 'is-IS', 'it_IT' => 'it-IT', 'ja' => 'ja-JP', 'jv_ID' => 'jv-ID',
43
- 'ka_GE' => 'ka-GE', 'kin' => 'kin-RW', 'kk' => 'kk-KZ', 'kn' => 'kn-IN', 'ko_KR' => 'ko-KR', 'ky_KY' => 'ky-KG',
44
- 'lb_LU' => 'lb-LU', 'lo' => 'lo-LA', 'lt_LT' => 'lt-LT', 'lv' => 'lv-LV', 'mg_MG' => 'mg-MG', 'mk_MK' => 'mk-MK',
45
- 'ml_IN' => 'ml-IN', 'mn' => 'mn-MN', 'mr' => 'mr-IN', 'ms_MY' => 'ms-MY', 'my_MM' => 'my-MM', 'ne_NP' => 'ne-NP',
46
- 'nl_BE' => 'nl-BE', 'nl_NL' => 'nl-NL', 'nn_NO' => 'nn-NO', 'pa_IN' => 'pa-IN', 'pl_PL' => 'pl-PL', 'ps' => 'ps-AF',
47
- 'pt_BR' => 'pt-BR', 'pt_PT' => 'pt-PT', 'ro_RO' => 'ro-RO', 'ru_RU' => 'ru-RU', 'sa_IN' => 'sa-IN', 'sd_PK' => 'sd-PK',
48
- 'si_LK' => 'si-LK', 'sk_SK' => 'sk-SK', 'sl_SI' => 'sl-SI', 'so_SO' => 'so-SO', 'sq' => 'sq-SQ', 'sr_RS' => 'sr-CS',
49
- 'su_ID' => 'su-ID', 'sv_SE' => 'sv-SE', 'sw' => 'sw-TZ', 'ta_IN' => 'ta-IN', 'te' => 'te-IN', 'tg' => 'tg-TJ',
50
- 'th' => 'th-TH', 'tir' => 'ti-ER', 'tl' => 'tl-PH', 'tr_TR' => 'tr-TR', 'ug_CN' => 'ug-CN', 'uk' => 'uk-UA',
51
- 'ur' => 'ur-PK', 'uz_UZ' => 'uz-UZ', 'vi' => 'vi-VN', 'zh_CN' => 'zh-CN', 'zh_HK' => 'zh-HK', 'zh_TW' => 'zh-TW',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
52
  );
53
 
54
  /**
55
  *
56
  * Unique identifier for your plugin.
57
  *
58
- *
59
  * The variable name is used as the text domain when internationalizing strings
60
  * of text. Its value should match the Text Domain file header in the main
61
  * plugin file.
62
  *
63
- * @since 1.0.0
64
  *
65
  * @var string
66
  */
@@ -75,48 +181,54 @@ class Lingotek {
75
  */
76
  protected static $instance = null;
77
 
78
- protected static $logging = FALSE;
79
 
80
- /*
81
- * constructor
82
  *
83
  * @since 0.1
84
  */
85
  public function __construct() {
86
- // manages plugin activation and deactivation
87
- register_activation_hook( __FILE__, array(&$this, 'activate'));
88
- register_deactivation_hook( __FILE__, array(&$this, 'deactivate'));
89
 
90
- // stopping here if we are going to deactivate the plugin (avoids breaking rewrite rules)
91
- if (isset($_GET['action'], $_GET['plugin']) && 'deactivate' == $_GET['action'] && plugin_basename(__FILE__) == $_GET['plugin'])
92
  return;
 
93
 
94
- // loads the admin side of Polylang for the dashboard
95
- if (defined('DOING_AJAX') && DOING_AJAX && isset($_REQUEST['action']) && 'lingotek_language' == $_REQUEST['action']) {
96
- define('PLL_AJAX_ON_FRONT', false);
97
- add_filter('pll_model', create_function('$c', 'return "PLL_Admin_Model";'));
 
 
 
 
 
98
  }
99
 
100
- spl_autoload_register(array(&$this, 'autoload')); // autoload classes
101
 
102
- // init
103
- add_filter('pll_model', array(&$this, 'pll_model'));
104
- add_action('init', array(&$this, 'init'));
105
- add_action('admin_init', array(&$this, 'admin_init'));
106
 
107
- // add Lingotek locale to languages
108
- add_filter('pll_languages_list', array(&$this, 'pre_set_languages_list'));
109
 
110
- // flag title
111
- add_filter('pll_flag_title', array(&$this, 'pll_flag_title'), 10, 3);
112
 
113
- // adds a pointer upon plugin activation to draw attention to Lingotek
114
- if (!get_option('lingotek_token')) {
115
- add_action('init', array(&$this, 'lingotek_activation_pointer'));
116
  }
117
 
118
- // adds extra plugin compatibility - borrowed from Polylang
119
- if (!defined('LINGOTEK_PLUGINS_COMPAT') || LINGOTEK_PLUGINS_COMPAT) {
120
  Lingotek_Plugins_Compat::instance();
121
  }
122
  }
@@ -142,89 +254,88 @@ class Lingotek {
142
  public static function get_instance() {
143
 
144
  // If the single instance hasn't been set, set it now.
145
- if ( null == self::$instance ) {
146
  self::$instance = new self;
147
  }
148
 
149
  return self::$instance;
150
  }
151
 
152
- /*
153
- * activation or deactivation for all blogs
154
  * method taken from Polylang
155
  *
156
  * @since 0.1
157
  *
158
- * @param string $what either 'activate' or 'deactivate'
159
  */
160
- protected function do_for_all_blogs($what) {
161
- // network
162
- if (is_multisite() && isset($_GET['networkwide']) && ($_GET['networkwide'] == 1)) {
163
  global $wpdb;
164
 
165
- foreach ($wpdb->get_col("SELECT blog_id FROM $wpdb->blogs") as $blog_id) {
166
- switch_to_blog($blog_id);
167
- $what == 'activate' ? $this->_activate() : $this->_deactivate();
168
  }
169
  restore_current_blog();
 
 
 
170
  }
171
-
172
- // single blog
173
- else
174
- $what == 'activate' ? $this->_activate() : $this->_deactivate();
175
  }
176
 
177
- /*
178
- * plugin activation for multisite
179
  *
180
  * @since 0.1
181
  */
182
  public function activate() {
183
- $this->do_for_all_blogs('activate');
184
  }
185
 
186
- /*
187
- * plugin activation
188
  *
189
  * @since 0.1
190
  */
191
  protected function _activate() {
192
  global $polylang;
193
 
194
- if (isset($polylang)) {
195
- $polylang->model->clean_languages_cache(); // to add lingotek_locale property
196
  }
197
 
198
- // default profiles
199
- if (false === get_option('lingotek_profiles')) {
200
  $profiles = array(
201
  'automatic' => array(
202
  'profile' => 'automatic',
203
- 'name' => __('Automatic', 'lingotek-translation'),
204
  'upload' => 'automatic',
205
- 'download' => 'automatic'
206
  ),
207
  'manual' => array(
208
  'profile' => 'manual',
209
- 'name' => __('Manual', 'lingotek-translation'),
210
  'upload' => 'manual',
211
- 'download' => 'manual'
212
  ),
213
  'disabled' => array(
214
  'profile' => 'disabled',
215
- 'name' => __('Disabled', 'lingotek-translation'),
216
  ),
217
  );
218
- update_option('lingotek_profiles', $profiles);
219
  }
220
 
221
- // for the end point for the Lingoteck callback in rewrite rules
222
- // don't use flush_rewrite_rules at network activation. See #32471
223
- delete_option('rewrite_rules');
224
  }
225
 
226
- /*
227
- * provides localized version of the canned translation profiles
228
  *
229
  * @since 1.0
230
  *
@@ -234,176 +345,182 @@ class Lingotek {
234
  $default_profiles = array(
235
  'automatic' => array(
236
  'profile' => 'automatic',
237
- 'name' => __('Automatic', 'lingotek-translation'),
238
  'upload' => 'automatic',
239
- 'download' => 'automatic'
240
  ),
241
  'manual' => array(
242
  'profile' => 'manual',
243
- 'name' => __('Manual', 'lingotek-translation'),
244
  'upload' => 'manual',
245
- 'download' => 'manual'
246
  ),
247
  'disabled' => array(
248
  'profile' => 'disabled',
249
- 'name' => __('Disabled', 'lingotek-translation'),
250
  ),
251
  );
252
 
253
- $profiles = get_option('lingotek_profiles');
254
- if (is_array($profiles)) {
255
- $profiles = array_merge($default_profiles, $profiles);
256
- }
257
- else {
258
  $profiles = $default_profiles;
259
  }
260
 
261
- //localize canned profile names
262
- foreach($profiles as $k=>$v){
263
- if(in_array($k,array('automatic','manual','disabled'))){
264
- $profile_name = $profiles[$k]['name'];
265
- $profiles[$k]['name'] = __($profile_name,'lingotek-translation');// localize canned profile names
266
  }
267
  }
268
 
269
- update_option('lingotek_profiles', $profiles);
270
  return $profiles;
271
  }
272
 
273
- /*
274
- * plugin deactivation for multisite
275
  *
276
  * @since 0.1
277
  */
278
  public function deactivate() {
279
- $this->do_for_all_blogs('deactivate');
280
  }
281
 
282
- /*
283
- * plugin deactivation
284
  *
285
  * @since 0.5
286
  */
287
  protected function _deactivate() {
288
- delete_option('rewrite_rules');
289
  }
290
 
291
- /*
292
- * blog creation on multisite (to set default options)
293
  *
294
  * @since 0.1
295
  *
296
- * @param int $blog_id
297
  */
298
- public function wpmu_new_blog($blog_id) {
299
- switch_to_blog($blog_id);
300
  $this->_activate();
301
  restore_current_blog();
302
  }
303
 
304
- /*
305
- * autoload classes
306
  *
307
  * @since 0.1
308
  *
309
- * @param string $class
310
  */
311
- public function autoload($class) {
312
- // not a Lingotek class
313
- if (0 !== strncmp('Lingotek_', $class, 9))
314
  return;
 
315
 
316
- $class = str_replace('_', '-', strtolower(substr($class, 9)));
317
- foreach (array(LINGOTEK_INC, LINGOTEK_ADMIN_INC) as $path) {
318
- if (file_exists($file = "$path/$class.php")) {
319
- require_once($file);
320
  break;
321
  }
322
  }
323
  }
324
 
325
- /*
326
- * set the Polylang model class to PLL_Admin_Model on Lingotek admin pages
327
  *
328
  * @since 0.2
329
  *
330
- * @param string $class
331
- * @return string modified class 'PLL_Model' | 'PLL_Admin_Model'
332
  */
333
- public function pll_model($class) {
334
- if (PLL_ADMIN && isset($_GET['page']) && in_array($_GET['page'], array('lingotek-translation', 'lingotek-translation_manage', 'lingotek-translation_settings', 'lingotek-translation_network')))
335
  return 'PLL_Admin_Model';
 
336
  return $class;
337
  }
338
 
339
- /*
340
- * setups Lingotek model and callback
341
  * sets filters to call Lingotek child classes instead of Polylang classes
342
  *
343
  * @since 0.1
344
- *
345
  */
346
  public function init() {
347
- if (!defined('POLYLANG_VERSION'))
348
  return;
 
349
 
350
  add_rewrite_rule( 'lingotek/?$', 'index.php?lingotek=1&$matches[1]', 'top' );
351
 
352
- if (is_admin())
353
  new Lingotek_Admin();
 
354
 
355
- // admin side
356
- if (PLL_ADMIN && !PLL_SETTINGS) {
357
  $this->model = new Lingotek_Model();
358
 
359
- // overrides Polylang classes
360
- $classes = array('Filters_Post', 'Filters_Term', 'Filters_Media', 'Filters_Columns');
361
- foreach ($classes as $class)
362
- add_filter('pll_' . strtolower($class) , create_function('$v', "return 'Lingotek_$class';"));
 
 
 
 
363
 
364
- // add actions to posts, media and terms list
365
- // no need to load this if there is no language yet
366
- if ($GLOBALS['polylang']->model->get_languages_list()) {
367
  $this->post_actions = new Lingotek_Post_Actions();
368
  $this->term_actions = new Lingotek_Term_Actions();
369
  $this->string_actions = new Lingotek_String_actions();
 
370
  }
371
 
372
  $this->utilities = new Lingotek_Utilities();
373
- }
374
-
375
- // callback
376
- elseif (!PLL_ADMIN && !PLL_AJAX_ON_FRONT) {
377
- $GLOBALS['wp']->add_query_var('lingotek');
378
 
379
  $this->model = new Lingotek_Model();
380
- $this->callback = new Lingotek_Callback($this->model);
381
  }
382
  }
383
 
384
- /*
385
- * some init
386
  *
387
  * @since 0.1
388
  */
389
  public function admin_init() {
390
- // plugin i18n, only needed for backend
391
- load_plugin_textdomain('lingotek-translation', false, basename(LINGOTEK_DIR).'/languages');
392
 
393
- if (!defined('POLYLANG_VERSION'))
394
- add_action('all_admin_notices', array(&$this, 'pll_inactive_notice'));
395
 
396
- elseif (version_compare(POLYLANG_VERSION, LINGOTEK_MIN_PLL_VERSION, '<'))
397
- add_action('all_admin_notices', array(&$this, 'pll_old_notice'));
398
 
399
- elseif (isset($GLOBALS['polylang']) && !count($GLOBALS['polylang']->model->get_languages_list()))
400
  self::create_first_language();
 
401
 
402
- wp_enqueue_style('lingotek_admin', LINGOTEK_URL .'/css/admin.css', array(), LINGOTEK_VERSION);
403
  }
404
 
405
- /*
406
- * displays a notice if Polylang is inactive
407
  *
408
  * @since 0.1
409
  */
@@ -414,158 +531,179 @@ class Lingotek {
414
  add_query_arg(
415
  array(
416
  'action' => $action,
417
- 'plugin' => $slug
418
  ),
419
  admin_url( 'update.php' )
420
  ),
421
- $action.'_'.$slug
422
  );
423
  printf(
424
  '<div class="error" style="height:55px"><p style="font-size:1.5em">%s<a href="%s">%s</a></p></div>',
425
- __('Lingotek Translation requires Polylang to work. ', 'lingotek-translation'), $url, __('Install Polylang', 'lingotek-translation')
426
  );
427
  }
428
 
429
- /*
430
- * displays a notice if Polylang is obsolete
431
  *
432
  * @since 0.1
433
  */
434
  public function pll_old_notice() {
 
 
 
435
  printf(
436
  '<div class="error"><p>%s</p></div>',
437
  sprintf(
438
- __('Lingotek Translation requires Polylang %s to work. Please upgrade Polylang.', 'lingotek-translation'),
439
- '<strong>' . LINGOTEK_MIN_PLL_VERSION . '</strong>'
440
  )
441
  );
442
  }
443
 
444
- /*
445
- * creates at least on language to avoid breaking the Lingotek Dashboard
446
  *
447
  * @since 0.2
448
  */
449
  static protected function create_first_language() {
450
  global $polylang;
451
 
452
- include(PLL_ADMIN_INC.'/languages.php');
453
  $locale = get_locale();
454
 
455
- // attempts to set the default language from the current locale
456
- foreach ($languages as $lang) {
457
- if (get_locale() == $lang[1])
458
  $language = $lang;
 
459
  }
460
 
461
- // defaults to en_US
462
- if (empty($language))
463
- $language = array('en', 'en_US', 'English');
 
464
 
465
- $pll_model = new PLL_Admin_Model($polylang->options); // need admin model
466
  $pll_model->add_language(array(
467
  'slug' => $language[0],
468
  'locale' => $language[1],
469
  'name' => $language[2],
470
- 'rtl' => isset($language[3]) ? 1 : 0,
471
- 'term_group' => 0
472
  ));
473
  }
474
 
475
- /*
476
- * adds Lingotek locale to the PLL_Language objects
477
  * uses the map otherwise uses a stupid fallback
478
  *
479
  * @since 0.1
480
  *
481
- * @param array $languages list of language objects
482
  * @return array
483
  */
484
- public function pre_set_languages_list($languages) {
485
- foreach ($languages as $key => $language) {
486
- if (is_object($language))
487
- $languages[$key]->lingotek_locale = self::map_to_lingotek_locale($language->locale); // backward compatibility with Polylang < 1.7.3
488
- else
489
- $languages[$key]['lingotek_locale'] = self::map_to_lingotek_locale($language['locale']);
490
  }
491
 
492
  return $languages;
493
  }
494
 
495
- /*
496
- * maps a Lingotek locale to a WordPress locale
497
  *
498
  * @since 0.3
499
  *
500
- * @param string $lingotek_locale Lingotek locale
501
- * @return string WordPress locale
502
  */
503
- public static function map_to_wp_locale($lingotek_locale) {
504
- // look for the locale in the map (take care that Lingotek sends locales with either '_' or '-'
505
- // if not found just replace '-' by '_'
506
- $wp_locale = array_search(str_replace('_', '-', $lingotek_locale), self::$lingotek_locales);
507
- return $wp_locale ? $wp_locale : str_replace('-', '_', $lingotek_locale);
508
  }
509
 
510
- /*
511
- * maps a WordPres locale to a Lingotek locale
 
 
 
 
 
 
 
 
 
512
  *
513
  * @since 0.3
514
  *
515
- * @param string $wp_locale WordPress locale
516
  * @return string Lingotek locale
517
  */
518
- public static function map_to_lingotek_locale($wp_locale) {
519
- // look for the locale in the map
520
- // if not found just replace '_ 'by '-'
521
- return isset(self::$lingotek_locales[$wp_locale]) ? self::$lingotek_locales[$wp_locale] : str_replace('_', '-', $wp_locale);
522
  }
523
 
524
- /*
525
- * modifies the flag title to add the locale
526
  *
527
  * @since 0.3
528
  *
529
- * @param string $name language name
530
- * @param string $slug language code
531
- * @param string $locale language locale
532
  * @return string
533
  */
534
- public function pll_flag_title($name, $slug, $locale) {
535
  return "$name ($locale)";
536
  }
537
 
538
- public static function log($data, $label = NULL) {
539
- if (self::$logging) {
540
- $log_string = "";
541
- if (is_string($label))
 
 
 
 
 
 
542
  $log_string .= $label . "\n";
543
- if (is_string($data)) {
544
- $log_string .= $data;
545
  }
546
- else {
547
- $log_string .= print_r($data, TRUE);
 
 
548
  }
549
- error_log($log_string);
550
  }
551
  }
552
 
553
- /*
554
  * Creates a pointer to draw attention to the new Lingotek menu item upon plugin activation
555
  * code borrowed from Polylang
 
556
  * @since 1.0.1
557
  */
558
  public function lingotek_activation_pointer() {
559
- $content = __('You’ve just installed Lingotek Translation! Click below to activate your account and automatically translate your website for free!', 'lingotek-translation');
560
 
561
  $buttons = array(
562
  array(
563
- 'label' => __('Close')
564
  ),
565
  array(
566
- 'label' => __('Activate Account', 'lingotek-translation'),
567
- 'link' => admin_url('admin.php?page=' . $this->plugin_slug . '_settings&connect=new'),
568
- )
569
  );
570
 
571
  $args = array(
@@ -576,12 +714,12 @@ class Lingotek {
576
  'align' => 'left',
577
  ),
578
  'width' => 380,
579
- 'title' => __('Congratulations!', 'lingotek-translation'),
580
  'content' => $content,
581
- 'buttons' => $buttons
582
  );
583
 
584
- new Lingotek_Pointer($args);
585
  }
586
  }
587
 
1
  <?php
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.2.7
6
+ Author: Lingotek and Frédéric Demarle
7
+ Author uri: http://lingotek.com
8
+ Description: Lingotek offers convenient cloud-based localization and translation.
9
+ Text Domain: lingotek-translation
10
+ Domain Path: /languages
11
+ GitHub Plugin URI: https://github.com/lingotek/lingotek-translation
12
+ */
13
+
14
+ // don't access directly.
15
+ if ( ! function_exists( 'add_action' ) ) {
16
  exit();
17
+ }
18
 
19
+ define( 'LINGOTEK_VERSION', '1.2.7' ); // 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
 
29
  class Lingotek {
30
+ /**
31
+ * Lingotek model.
32
+ *
33
+ * @var object
34
+ */
35
+ public $model;
36
+
37
+ /**
38
+ * Callback method
39
+ *
40
+ * @var method
41
+ */
42
  public $callback;
43
 
44
+ /**
45
+ * Array to map Lingotek locales to WP locales.
46
+ * map as 'WP locale' => 'Lingotek locale'.
47
+ *
48
+ * @var array
49
+ */
50
  public static $lingotek_locales = array(
51
+ 'af' => 'af-ZA',
52
+ 'ak' => 'ak-GH',
53
+ 'am' => 'am-ET',
54
+ 'ar' => 'ar',
55
+ 'as' => 'as-IN',
56
+ 'az' => 'az-AZ',
57
+ 'ba' => 'ba-RU',
58
+ 'bel' => 'be-BY',
59
+ 'bg_BG' => 'bg-BG',
60
+ 'bn_BD' => 'bn-BD',
61
+ 'bo' => 'bo-CN',
62
+ 'bs_BA' => 'bs-BA',
63
+ 'ca' => 'ca-ES',
64
+ 'co' => 'co-FR',
65
+ 'cs_CZ' => 'cs-CZ',
66
+ 'cy' => 'cy-GB',
67
+ 'da_DK' => 'da-DK',
68
+ 'de_CH' => 'de-CH',
69
+ 'de_DE' => 'de-DE',
70
+ 'dv' => 'dv-MV',
71
+ 'el' => 'el-GR',
72
+ 'en_AU' => 'en-AU',
73
+ 'en_CA' => 'en-CA',
74
+ 'en_GB' => 'en-GB',
75
+ 'en_US' => 'en-US',
76
+ 'eo' => 'eo-FR',
77
+ 'es_AR' => 'es-AR',
78
+ 'es_CL' => 'es-CL',
79
+ 'es_CO' => 'es-CO',
80
+ 'es_ES' => 'es-ES',
81
+ 'es_MX' => 'es-MX',
82
+ 'es_PE' => 'es-PE',
83
+ 'es_PR' => 'es-PR',
84
+ 'es_VE' => 'es-VE',
85
+ 'et' => 'et-EE',
86
+ 'eu' => 'eu-ES',
87
+ 'fa_IR' => 'fa-IR',
88
+ 'fi' => 'fi-FI',
89
+ 'fr_FR' => 'fr-FR',
90
+ 'ga' => 'ga-IE',
91
+ 'gd' => 'gd-GB',
92
+ 'gl_ES' => 'gl-ES',
93
+ 'gn' => 'gn-BO',
94
+ 'haw_US' => 'haw-US',
95
+ 'he_IL' => 'he-IL',
96
+ 'hi_IN' => 'hi-IN',
97
+ 'hr' => 'hr-HR',
98
+ 'hu_HU' => 'hu-HU',
99
+ 'hy' => 'hy-AM',
100
+ 'id_ID' => 'id-ID',
101
+ 'is_IS' => 'is-IS',
102
+ 'it_IT' => 'it-IT',
103
+ 'ja' => 'ja-JP',
104
+ 'jv_ID' => 'jv-ID',
105
+ 'ka_GE' => 'ka-GE',
106
+ 'kin' => 'kin-RW',
107
+ 'kk' => 'kk-KZ',
108
+ 'kn' => 'kn-IN',
109
+ 'ko_KR' => 'ko-KR',
110
+ 'ky_KY' => 'ky-KG',
111
+ 'lb_LU' => 'lb-LU',
112
+ 'lo' => 'lo-LA',
113
+ 'lt_LT' => 'lt-LT',
114
+ 'lv' => 'lv-LV',
115
+ 'mg_MG' => 'mg-MG',
116
+ 'mk_MK' => 'mk-MK',
117
+ 'ml_IN' => 'ml-IN',
118
+ 'mn' => 'mn-MN',
119
+ 'mr' => 'mr-IN',
120
+ 'ms_MY' => 'ms-MY',
121
+ 'my_MM' => 'my-MM',
122
+ 'ne_NP' => 'ne-NP',
123
+ 'nl_BE' => 'nl-BE',
124
+ 'nl_NL' => 'nl-NL',
125
+ 'nn_NO' => 'nn-NO',
126
+ 'pa_IN' => 'pa-IN',
127
+ 'pl_PL' => 'pl-PL',
128
+ 'ps' => 'ps-AF',
129
+ 'pt_BR' => 'pt-BR',
130
+ 'pt_PT' => 'pt-PT',
131
+ 'ro_RO' => 'ro-RO',
132
+ 'ru_RU' => 'ru-RU',
133
+ 'sa_IN' => 'sa-IN',
134
+ 'sd_PK' => 'sd-PK',
135
+ 'si_LK' => 'si-LK',
136
+ 'sk_SK' => 'sk-SK',
137
+ 'sl_SI' => 'sl-SI',
138
+ 'so_SO' => 'so-SO',
139
+ 'sq' => 'sq-SQ',
140
+ 'sr_RS' => 'sr-CS',
141
+ 'su_ID' => 'su-ID',
142
+ 'sv_SE' => 'sv-SE',
143
+ 'sw' => 'sw-TZ',
144
+ 'ta_IN' => 'ta-IN',
145
+ 'te' => 'te-IN',
146
+ 'tg' => 'tg-TJ',
147
+ 'th' => 'th-TH',
148
+ 'tir' => 'ti-ER',
149
+ 'tl' => 'tl-PH',
150
+ 'tr_TR' => 'tr-TR',
151
+ 'ug_CN' => 'ug-CN',
152
+ 'uk' => 'uk-UA',
153
+ 'ur' => 'ur-PK',
154
+ 'uz_UZ' => 'uz-UZ',
155
+ 'vi' => 'vi-VN',
156
+ 'zh_CN' => 'zh-CN',
157
+ 'zh_HK' => 'zh-HK',
158
+ 'zh_TW' => 'zh-TW',
159
  );
160
 
161
  /**
162
  *
163
  * Unique identifier for your plugin.
164
  *
 
165
  * The variable name is used as the text domain when internationalizing strings
166
  * of text. Its value should match the Text Domain file header in the main
167
  * plugin file.
168
  *
169
+ * @since 1.0.0==
170
  *
171
  * @var string
172
  */
181
  */
182
  protected static $instance = null;
183
 
184
+ protected static $logging = false;
185
 
186
+ /**
187
+ * Constructor
188
  *
189
  * @since 0.1
190
  */
191
  public function __construct() {
192
+ // manages plugin activation and deactivation.
193
+ register_activation_hook( __FILE__, array( &$this, 'activate' ) );
194
+ register_deactivation_hook( __FILE__, array( &$this, 'deactivate' ) );
195
 
196
+ // stopping here if we are going to deactivate the plugin (avoids breaking rewrite rules).
197
+ if ( ! empty( filter_input( INPUT_GET, 'action' ) ) && ! empty( filter_input( INPUT_GET, 'plugin' ) ) && 'deactivate' === filter_input( INPUT_GET, 'action' ) && plugin_basename( __FILE__ ) === filter_input( INPUT_GET, 'plugin' ) ) {
198
  return;
199
+ }
200
 
201
+ $action = filter_input( INPUT_GET, 'action' );
202
+ $action = isset( $action ) ? $action : filter_input( INPUT_POST, 'action' );
203
+ // loads the admin side of Polylang for the dashboard.
204
+ if ( defined( 'DOING_AJAX' ) && DOING_AJAX && isset( $action ) && 'lingotek_language' === $action ) {
205
+ define( 'PLL_AJAX_ON_FRONT', false );
206
+ $method = function( $c ) {
207
+ return 'PLL_Admin_Model';
208
+ };
209
+ add_filter( 'pll_model', $method );
210
  }
211
 
212
+ spl_autoload_register( array( &$this, 'autoload' ) ); // autoload classes.
213
 
214
+ // init.
215
+ add_filter( 'pll_model', array( &$this, 'pll_model' ) );
216
+ add_action( 'init', array( &$this, 'init' ) );
217
+ add_action( 'admin_init', array( &$this, 'admin_init' ) );
218
 
219
+ // add Lingotek locale to languages.
220
+ add_filter( 'pll_languages_list', array( &$this, 'pre_set_languages_list' ) );
221
 
222
+ // flag title.
223
+ add_filter( 'pll_flag_title', array( &$this, 'pll_flag_title' ), 10, 3 );
224
 
225
+ // adds a pointer upon plugin activation to draw attention to Lingotek.
226
+ if ( ! get_option( 'lingotek_token' ) ) {
227
+ add_action( 'init', array( &$this, 'lingotek_activation_pointer' ) );
228
  }
229
 
230
+ // adds extra plugin compatibility - borrowed from Polylang.
231
+ if ( ! defined( 'LINGOTEK_PLUGINS_COMPAT' ) || LINGOTEK_PLUGINS_COMPAT ) {
232
  Lingotek_Plugins_Compat::instance();
233
  }
234
  }
254
  public static function get_instance() {
255
 
256
  // If the single instance hasn't been set, set it now.
257
+ if ( null === self::$instance ) {
258
  self::$instance = new self;
259
  }
260
 
261
  return self::$instance;
262
  }
263
 
264
+ /**
265
+ * Activation or deactivation for all blogs
266
  * method taken from Polylang
267
  *
268
  * @since 0.1
269
  *
270
+ * @param string $what either 'activate' or 'deactivate'.
271
  */
272
+ protected function do_for_all_blogs( $what ) {
273
+ // network.
274
+ if ( is_multisite() && ! empty( filter_input( INPUT_GET, 'networkwide' ) ) && ( 1 === filter_input( INPUT_GET, 'networkwide' ) ) ) {
275
  global $wpdb;
276
 
277
+ foreach ( $wpdb->get_col( "SELECT blog_id FROM $wpdb->blogs" ) as $blog_id ) {
278
+ switch_to_blog( $blog_id );
279
+ 'activate' === $what ? $this->_activate() : $this->_deactivate();
280
  }
281
  restore_current_blog();
282
+ } // single blog.
283
+ else {
284
+ 'activate' === $what ? $this->_activate() : $this->_deactivate();
285
  }
 
 
 
 
286
  }
287
 
288
+ /**
289
+ * Plugin activation for multisite
290
  *
291
  * @since 0.1
292
  */
293
  public function activate() {
294
+ $this->do_for_all_blogs( 'activate' );
295
  }
296
 
297
+ /**
298
+ * Plugin activation
299
  *
300
  * @since 0.1
301
  */
302
  protected function _activate() {
303
  global $polylang;
304
 
305
+ if ( isset( $polylang ) ) {
306
+ $polylang->model->clean_languages_cache(); // to add lingotek_locale property.
307
  }
308
 
309
+ // default profiles.
310
+ if ( false === get_option( 'lingotek_profiles' ) ) {
311
  $profiles = array(
312
  'automatic' => array(
313
  'profile' => 'automatic',
314
+ 'name' => __( 'Automatic', 'lingotek-translation' ),
315
  'upload' => 'automatic',
316
+ 'download' => 'automatic',
317
  ),
318
  'manual' => array(
319
  'profile' => 'manual',
320
+ 'name' => __( 'Manual', 'lingotek-translation' ),
321
  'upload' => 'manual',
322
+ 'download' => 'manual',
323
  ),
324
  'disabled' => array(
325
  'profile' => 'disabled',
326
+ 'name' => __( 'Disabled', 'lingotek-translation' ),
327
  ),
328
  );
329
+ update_option( 'lingotek_profiles', $profiles );
330
  }
331
 
332
+ // for the end point for the Lingoteck callback in rewrite rules.
333
+ // don't use flush_rewrite_rules at network activation. See #32471.
334
+ delete_option( 'rewrite_rules' );
335
  }
336
 
337
+ /**
338
+ * Provides localized version of the canned translation profiles
339
  *
340
  * @since 1.0
341
  *
345
  $default_profiles = array(
346
  'automatic' => array(
347
  'profile' => 'automatic',
348
+ 'name' => __( 'Automatic', 'lingotek-translation' ),
349
  'upload' => 'automatic',
350
+ 'download' => 'automatic',
351
  ),
352
  'manual' => array(
353
  'profile' => 'manual',
354
+ 'name' => __( 'Manual', 'lingotek-translation' ),
355
  'upload' => 'manual',
356
+ 'download' => 'manual',
357
  ),
358
  'disabled' => array(
359
  'profile' => 'disabled',
360
+ 'name' => __( 'Disabled', 'lingotek-translation' ),
361
  ),
362
  );
363
 
364
+ $profiles = get_option( 'lingotek_profiles' );
365
+ if ( is_array( $profiles ) ) {
366
+ $profiles = array_merge( $default_profiles, $profiles );
367
+ } else {
 
368
  $profiles = $default_profiles;
369
  }
370
 
371
+ // localize canned profile names.
372
+ foreach ( $profiles as $k => $v ) {
373
+ if ( in_array( $k,array( 'automatic', 'manual', 'disabled' ), true ) ) {
374
+ $profile_name = $profiles[ $k ]['name'];
375
+ $profiles[ $k ]['name'] = __( $profile_name,'lingotek-translation' );// localize canned profile names.
376
  }
377
  }
378
 
379
+ update_option( 'lingotek_profiles', $profiles );
380
  return $profiles;
381
  }
382
 
383
+ /**
384
+ * Plugin deactivation for multisite
385
  *
386
  * @since 0.1
387
  */
388
  public function deactivate() {
389
+ $this->do_for_all_blogs( 'deactivate' );
390
  }
391
 
392
+ /**
393
+ * Plugin deactivation
394
  *
395
  * @since 0.5
396
  */
397
  protected function _deactivate() {
398
+ delete_option( 'rewrite_rules' );
399
  }
400
 
401
+ /**
402
+ * Blog creation on multisite (to set default options)
403
  *
404
  * @since 0.1
405
  *
406
+ * @param int $blog_id blog id.
407
  */
408
+ public function wpmu_new_blog( $blog_id ) {
409
+ switch_to_blog( $blog_id );
410
  $this->_activate();
411
  restore_current_blog();
412
  }
413
 
414
+ /**
415
+ * Autoload classes
416
  *
417
  * @since 0.1
418
  *
419
+ * @param string $class class name.
420
  */
421
+ public function autoload( $class ) {
422
+ // not a Lingotek class.
423
+ if ( 0 !== strncmp( 'Lingotek_', $class, 9 ) ) {
424
  return;
425
+ }
426
 
427
+ $class = self::convert_class_to_file( $class );
428
+ foreach ( array( LINGOTEK_WORKFLOWS, LINGOTEK_INC, LINGOTEK_ADMIN_INC ) as $path ) {
429
+ if ( file_exists( $file = "$path/$class.php" ) ) {
430
+ require_once( $file );
431
  break;
432
  }
433
  }
434
  }
435
 
436
+ /**
437
+ * Set the Polylang model class to PLL_Admin_Model on Lingotek admin pages
438
  *
439
  * @since 0.2
440
  *
441
+ * @param string $class class name.
442
+ * @return string modified class 'PLL_Model' | 'PLL_Admin_Model'.
443
  */
444
+ public function pll_model( $class ) {
445
+ if ( PLL_ADMIN && ! empty( filter_input( INPUT_GET, 'page' ) ) && in_array( filter_input( INPUT_GET, 'page' ), array( 'lingotek-translation', 'lingotek-translation_manage', 'lingotek-translation_settings', 'lingotek-translation_network' ), true ) ) {
446
  return 'PLL_Admin_Model';
447
+ }
448
  return $class;
449
  }
450
 
451
+ /**
452
+ * Setups Lingotek model and callback
453
  * sets filters to call Lingotek child classes instead of Polylang classes
454
  *
455
  * @since 0.1
 
456
  */
457
  public function init() {
458
+ if ( ! defined( 'POLYLANG_VERSION' ) ) {
459
  return;
460
+ }
461
 
462
  add_rewrite_rule( 'lingotek/?$', 'index.php?lingotek=1&$matches[1]', 'top' );
463
 
464
+ if ( is_admin() ) {
465
  new Lingotek_Admin();
466
+ }
467
 
468
+ // admin side.
469
+ if ( PLL_ADMIN && ! PLL_SETTINGS ) {
470
  $this->model = new Lingotek_Model();
471
 
472
+ // overrides Polylang classes.
473
+ $classes = array( 'Filters_Post', 'Filters_Term', 'Filters_Media', 'Filters_Columns' );
474
+ foreach ( $classes as $class ) {
475
+ $method = function( $v ) use ( $class ) {
476
+ return "Lingotek_$class";
477
+ };
478
+ add_filter( 'pll_' . strtolower( $class ) , $method );
479
+ }
480
 
481
+ // add actions to posts, media and terms list.
482
+ // no need to load this if there is no language yet.
483
+ if ( $GLOBALS['polylang']->model->get_languages_list() ) {
484
  $this->post_actions = new Lingotek_Post_Actions();
485
  $this->term_actions = new Lingotek_Term_Actions();
486
  $this->string_actions = new Lingotek_String_actions();
487
+ new Lingotek_Workflow_Factory(); // autoloads class.
488
  }
489
 
490
  $this->utilities = new Lingotek_Utilities();
491
+ } // callback.
492
+ elseif ( ! PLL_ADMIN && ! PLL_AJAX_ON_FRONT ) {
493
+ $GLOBALS['wp']->add_query_var( 'lingotek' );
 
 
494
 
495
  $this->model = new Lingotek_Model();
496
+ $this->callback = new Lingotek_Callback( $this->model );
497
  }
498
  }
499
 
500
+ /**
501
+ * Some init
502
  *
503
  * @since 0.1
504
  */
505
  public function admin_init() {
506
+ // plugin i18n, only needed for backend.
507
+ load_plugin_textdomain( 'lingotek-translation', false, basename( LINGOTEK_DIR ) . '/languages' );
508
 
509
+ if ( ! defined( 'POLYLANG_VERSION' ) ) {
510
+ add_action( 'all_admin_notices', array( &$this, 'pll_inactive_notice' ) );
511
 
512
+ } elseif ( version_compare( POLYLANG_VERSION, LINGOTEK_MIN_PLL_VERSION, '<' ) ) {
513
+ add_action( 'all_admin_notices', array( &$this, 'pll_old_notice' ) );
514
 
515
+ } elseif ( isset( $GLOBALS['polylang'] ) && ! count( $GLOBALS['polylang']->model->get_languages_list() ) ) {
516
  self::create_first_language();
517
+ }
518
 
519
+ wp_enqueue_style( 'lingotek_admin', LINGOTEK_URL . '/css/admin.css', array(), LINGOTEK_VERSION );
520
  }
521
 
522
+ /**
523
+ * Displays a notice if Polylang is inactive
524
  *
525
  * @since 0.1
526
  */
531
  add_query_arg(
532
  array(
533
  'action' => $action,
534
+ 'plugin' => $slug,
535
  ),
536
  admin_url( 'update.php' )
537
  ),
538
+ $action . '_' . $slug
539
  );
540
  printf(
541
  '<div class="error" style="height:55px"><p style="font-size:1.5em">%s<a href="%s">%s</a></p></div>',
542
+ esc_html( __( 'Lingotek Translation requires Polylang to work. ', 'lingotek-translation' ) ), esc_url( $url ), esc_html( __( 'Install Polylang', 'lingotek-translation' ) )
543
  );
544
  }
545
 
546
+ /**
547
+ * Displays a notice if Polylang is obsolete
548
  *
549
  * @since 0.1
550
  */
551
  public function pll_old_notice() {
552
+ $allowed_html = [
553
+ 'strong' => [],
554
+ ];
555
  printf(
556
  '<div class="error"><p>%s</p></div>',
557
  sprintf(
558
+ esc_html( __( 'Lingotek Translation requires Polylang %s to work. Please upgrade Polylang.', 'lingotek-translation' ) ),
559
+ wp_kses( '<strong>' . LINGOTEK_MIN_PLL_VERSION . '</strong>' , $allowed_html )
560
  )
561
  );
562
  }
563
 
564
+ /**
565
+ * Creates at least on language to avoid breaking the Lingotek Dashboard
566
  *
567
  * @since 0.2
568
  */
569
  static protected function create_first_language() {
570
  global $polylang;
571
 
572
+ include( PLL_ADMIN_INC . '/languages.php' );
573
  $locale = get_locale();
574
 
575
+ // attempts to set the default language from the current locale.
576
+ foreach ( $languages as $lang ) {
577
+ if ( get_locale() === $lang[1] ) {
578
  $language = $lang;
579
+ }
580
  }
581
 
582
+ // defaults to en_US.
583
+ if ( empty( $language ) ) {
584
+ $language = array( 'en', 'en_US', 'English' );
585
+ }
586
 
587
+ $pll_model = new PLL_Admin_Model( $polylang->options ); // need admin model.
588
  $pll_model->add_language(array(
589
  'slug' => $language[0],
590
  'locale' => $language[1],
591
  'name' => $language[2],
592
+ 'rtl' => isset( $language[3] ) ? 1 : 0,
593
+ 'term_group' => 0,
594
  ));
595
  }
596
 
597
+ /**
598
+ * Adds Lingotek locale to the PLL_Language objects
599
  * uses the map otherwise uses a stupid fallback
600
  *
601
  * @since 0.1
602
  *
603
+ * @param array $languages list of language objects.
604
  * @return array
605
  */
606
+ public function pre_set_languages_list( $languages ) {
607
+ foreach ( $languages as $key => $language ) {
608
+ if ( is_object( $language ) ) {
609
+ $languages[ $key ]->lingotek_locale = self::map_to_lingotek_locale( $language->locale ); // backward compatibility with Polylang < 1.7.3.
610
+ } else { $languages[ $key ]['lingotek_locale'] = self::map_to_lingotek_locale( $language['locale'] );
611
+ }
612
  }
613
 
614
  return $languages;
615
  }
616
 
617
+ /**
618
+ * Maps a Lingotek locale to a WordPress locale
619
  *
620
  * @since 0.3
621
  *
622
+ * @param string $lingotek_locale Lingotek locale.
623
+ * @return string WordPress locale.
624
  */
625
+ public static function map_to_wp_locale( $lingotek_locale ) {
626
+ // look for the locale in the map (take care that Lingotek sends locales with either '_' or '-'.
627
+ // if not found just replace '-' by '_'.
628
+ $wp_locale = array_search( str_replace( '_', '-', $lingotek_locale ), self::$lingotek_locales, true );
629
+ return $wp_locale ? $wp_locale : str_replace( '-', '_', $lingotek_locale );
630
  }
631
 
632
+ /**
633
+ * Converts the class name to the appropriate file name for class loading.
634
+ *
635
+ * @param string $class the class name.
636
+ */
637
+ public static function convert_class_to_file( $class ) {
638
+ return str_replace( '_', '-', strtolower( substr( $class, 9 ) ) );
639
+ }
640
+
641
+ /**
642
+ * Maps a WordPres locale to a Lingotek locale
643
  *
644
  * @since 0.3
645
  *
646
+ * @param string $wp_locale WordPress locale.
647
  * @return string Lingotek locale
648
  */
649
+ public static function map_to_lingotek_locale( $wp_locale ) {
650
+ // look for the locale in the map.
651
+ // if not found just replace '_ 'by '-'.
652
+ return isset( self::$lingotek_locales[ $wp_locale ] ) ? self::$lingotek_locales[ $wp_locale ] : str_replace( '_', '-', $wp_locale );
653
  }
654
 
655
+ /**
656
+ * Modifies the flag title to add the locale
657
  *
658
  * @since 0.3
659
  *
660
+ * @param string $name language name.
661
+ * @param string $slug language code.
662
+ * @param string $locale language locale.
663
  * @return string
664
  */
665
+ public function pll_flag_title( $name, $slug, $locale ) {
666
  return "$name ($locale)";
667
  }
668
 
669
+ /**
670
+ * Writes data to a log.
671
+ *
672
+ * @param multiple $data the data to be written.
673
+ * @param string $label the label to identify the data.
674
+ */
675
+ public static function log( $data, $label = null ) {
676
+ if ( self::$logging ) {
677
+ $log_string = '';
678
+ if ( is_string( $label ) ) {
679
  $log_string .= $label . "\n";
 
 
680
  }
681
+ if ( is_string( $data ) ) {
682
+ $log_string .= $data;
683
+ } else {
684
+ $log_string .= print_r( $data, true );
685
  }
686
+ error_log( $log_string );
687
  }
688
  }
689
 
690
+ /**
691
  * Creates a pointer to draw attention to the new Lingotek menu item upon plugin activation
692
  * code borrowed from Polylang
693
+ *
694
  * @since 1.0.1
695
  */
696
  public function lingotek_activation_pointer() {
697
+ $content = __( 'You’ve just installed Lingotek Translation! Click below to activate your account and automatically translate your website for free!', 'lingotek-translation' );
698
 
699
  $buttons = array(
700
  array(
701
+ 'label' => __( 'Close' ),
702
  ),
703
  array(
704
+ 'label' => __( 'Activate Account', 'lingotek-translation' ),
705
+ 'link' => admin_url( 'admin.php?page=' . $this->plugin_slug . '_settings&connect=new' ),
706
+ ),
707
  );
708
 
709
  $args = array(
714
  'align' => 'left',
715
  ),
716
  'width' => 380,
717
+ 'title' => __( 'Congratulations!', 'lingotek-translation' ),
718
  'content' => $content,
719
+ 'buttons' => $buttons,
720
  );
721
 
722
+ new Lingotek_Pointer( $args );
723
  }
724
  }
725
 
readme.txt CHANGED
@@ -4,7 +4,7 @@ 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: 4.7
7
- Stable tag: 1.2.6
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -122,6 +122,14 @@ For more, visit the [Lingotek documentation site](https://lingotek.atlassian.net
122
 
123
  == Changelog ==
124
 
 
 
 
 
 
 
 
 
125
  = 1.2.6 (2017-3-3) =
126
 
127
  * Increased API timeout
4
  Tags: automation, bilingual, international, language, Lingotek, localization, multilanguage, multilingual, translate, translation
5
  Requires at least: 3.8
6
  Tested up to: 4.7
7
+ Stable tag: 1.2.7
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
122
 
123
  == Changelog ==
124
 
125
+ = 1.2.7 (2017-4-14) =
126
+
127
+ * Added Lingotek bulk actions to custom content types
128
+ * Fixed incorrect number display on the Translation Dashboard when content was disabled for translation
129
+ * Fixed a bug that created empty content if trying to download translations before they were finished
130
+ * Fixed the String Groups page
131
+ * Code refactoring to meet WordPress coding standards
132
+
133
  = 1.2.6 (2017-3-3) =
134
 
135
  * Increased API timeout