Completed
Pull Request — 2.x (#4187)
by Scott Kingsley
06:00
created

Pods_Component_I18n::admin_assets()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 19
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 13
nc 2
nop 0
dl 0
loc 19
rs 9.2
c 0
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 24 and the first side effect is on line 19.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * Name: Polylang / WPML admin label integration
4
 *
5
 * Menu Name: Supported Admin Languages
6
 *
7
 * Description: Allow UI of Pods and fields to be translated, with support for Polylang and WPML plugins.
8
 *
9
 * Version: 0.1
10
 *
11
 * Category: I18n
12
 *
13
 * Class: Pods_Component_I18n
14
 *
15
 * @package Pods\Components
16
 * @subpackage i18n
17
 */
18
19
! defined( 'ABSPATH' ) and die();
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
20
21
if ( class_exists( 'Pods_Component_I18n' ) )
22
	return;
23
24
class Pods_Component_I18n extends PodsComponent {
25
26
	public $settings = array();
27
	public $locale = null;
28
	public $languages = array();
29
	public $languages_available = array();
30
	public $languages_translated = array();
31
	public $cur_pod = null;
32
	public $option_key = 'pods_component_i18n_settings';
33
	public $admin_page = 'pods-component-polylang-wpml-admin-label-integration';
34
	public $capability = 'pods_i18n_activate_lanuages';
35
	public $nonce = 'pods_i18n_activate_lanuages';
36
37
	public $translatable_fields = array(
38
		'label',
39
		'description',
40
		'placeholder',
41
		'menu_name',
42
		'name_admin_bar',
43
		'pick_select_text',
44
		'file_add_button',
45
		'file_modal_title',
46
		'file_modal_add_button',
47
	);
48
49
	/**
50
	 * Get mandatory data and add actions
51
	 *
52
	 * @since 0.1
53
	 */
54
	public function __construct () {
55
		$this->init();
56
	}
57
58
	/**
59
	 * Init function to register data, hooks and resources
60
	 * @since 0.1
61
	 */
62
	public function init() {
63
		$this->settings = get_option( $this->option_key, array() );
64
65
		// Polylang
66
		if ( function_exists( 'PLL' ) && file_exists( plugin_dir_path( __FILE__ ) . 'I18n-polylang.php' ) ) {
67
			include_once( plugin_dir_path( __FILE__ ) . 'I18n-polylang.php' );
68
		}
69
		// WPML
70
		if ( did_action( 'wpml_loaded' ) && file_exists( plugin_dir_path( __FILE__ ) . 'I18n-wpml.php' ) ) {
71
			include_once( plugin_dir_path( __FILE__ ) . 'I18n-wpml.php' );
72
		}
73
74
		$active = false;
75
		// Are there active languages?
76
		if ( ! empty( $this->settings['enabled_languages'] ) ) {
77
			$this->languages = $this->settings['enabled_languages'];
78
			$this->locale = get_locale();
79
			$active = true;
80
		}
81
82
		$is_component_page = false;
83
		$is_pods_edit_page = false;
84
		if ( is_admin() && isset( $_GET['page'] ) ) {
85
86
			// Is the current page the admin page of this component or a Pods edit page?
87
			if ( $_GET['page'] === $this->admin_page ) {
88
				$is_component_page = true;
89
			} elseif ( $_GET['page'] === 'pods' ) {
90
				$is_pods_edit_page = true;
91
			}
92
93
			if ( $is_component_page || ( $is_pods_edit_page && $active ) ) {
94
				add_action( 'admin_enqueue_scripts', array( $this, 'admin_assets' ) );
95
			}
96
		}
97
98
		if ( $is_component_page ) {
99
			// Do save action here because otherwise the loading of post_types get done first and labels aren't translated
100
			if ( pods_is_admin( $this->capability )
101
			    && isset( $_POST['_nonce_i18n'] )
102
			    && wp_verify_nonce( $_POST['_nonce_i18n'], $this->nonce )
103
			) {
104
				$this->admin_save();
105
			}
106
		}
107
108
		if ( $active ) {
109
			// WP Object filters (post_type and taxonomy)
110
			add_filter( 'pods_register_post_type', array( $this, 'pods_register_wp_object_i18n' ), 10, 2 );
111
			add_filter( 'pods_register_taxonomy', array( $this, 'pods_register_wp_object_i18n' ), 10, 2 );
112
113
			// ACT's
114
			add_filter( 'pods_advanced_content_type_pod_data', array( $this, 'pods_filter_object_strings_i18n' ), 10, 2 );
115
116
			// Setting pages
117
			add_filter( 'pods_admin_menu_page_title', array( $this, 'admin_menu_page_title_i18n' ), 10, 2 );
118
			add_filter( 'pods_admin_menu_label', array( $this, 'admin_menu_label_i18n' ), 10, 2 );
119
120
			// Default filters for all fields
121
			add_filter( 'pods_form_ui_label_text', array( $this, 'fields_ui_label_text_i18n' ), 10, 4 );
122
			add_filter( 'pods_form_ui_comment_text', array( $this, 'fields_ui_comment_text_i18n' ), 10, 3 );
123
124
			foreach ( pods_form()->field_types() as $type => $data ) {
125
				add_filter( 'pods_form_ui_field_' . $type . '_options', array( $this, 'form_ui_field_options_i18n' ), 10, 5 );
126
			}
127
128
			// Field specific
129
			//add_filter( 'pods_field_pick_data', array( $this, 'field_pick_data_i18n' ), 10, 6 );
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
130
131
			// Date field
132
			// @todo  Maybe move this to the Date field in core?
133
			global $wp_version;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
134
			if ( version_compare( $wp_version, '4.6', '<' ) ) {
135
				add_filter( 'pods_form_ui_field_date_args', array( $this, 'field_date_args_i18n' ), 10, 6 );
136
				add_filter( 'pods_form_ui_field_datetime_args', array( $this, 'field_date_args_i18n' ), 10, 6 );
137
			}
138
139
			if ( $is_pods_edit_page ) {
140
141
				$pod = null;
142
				// Get the pod if available
143
				if ( isset( $_GET['id'] ) && is_numeric( $_GET['id'] ) ) {
144
					$pod = pods_api()->load_pod( array( 'id' => $_GET['id'] ) );
145
					// Append options to root array for pods_v function to work
146
					foreach ( $pod[ 'options' ] as $_option => $_value ) {
147
						$pod[ $_option ] = $_value;
148
					}
149
				}
150
				$this->cur_pod = $pod;
151
152
				//Add option tab for post types
153
				//add_filter( 'pods_admin_setup_edit_tabs_post_type', array( $this, 'pod_tab' ), 11, 3 );
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
154
155
				//Add the same tab for taxonomies
156
				//add_filter( 'pods_admin_setup_edit_tabs_taxonomy', array( $this, 'pod_tab' ), 11, 3 );
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
157
158
				//Add options to the new tab
159
				//add_filter( 'pods_admin_setup_edit_options', array( $this, 'pod_options' ), 12, 2 );
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
160
161
				//Add options metabox to the pod edit screens
162
				add_action( 'pods_add_meta_boxes', array( $this, 'admin_meta_box' ) );
163
164
				//Add the i18n input fields based on existing fields
165
				add_filter( 'pods_form_ui_field_text', array( $this, 'add_i18n_inputs' ), 10, 6 );
166
			}
167
168
		}
169
	}
170
171
	/**
172
	 * Load assets for this component
173
	 * @since 0.1
174
	 */
175
	public function admin_assets() {
176
		wp_enqueue_script( 'pods-admin-i18n', PODS_URL . 'components/I18n/pods-admin-i18n.js', array( 'jquery', 'pods-i18n' ), '1.0', true );
177
		$localize_script = array();
178
		if ( ! empty( $this->languages ) ) {
179
			foreach ( $this->languages as $lang => $lang_data ) {
180
				$lang_label = $this->create_lang_label( $lang_data );
181
				if ( ! empty( $lang_label ) ) {
182
					$lang_label = $lang . ' ('. $lang_label .')';
183
				} else {
184
					$lang_label = $lang;
185
				}
186
				$localize_script[ $lang ] = $lang_label;
187
			}
188
		}
189
		wp_localize_script( 'pods-admin-i18n', 'pods_admin_i18n_strings', $localize_script );
190
191
		// Add strings to the i18n js object
192
		add_filter( 'pods_localized_strings', array( $this, 'localize_assets' ) );
193
	}
194
195
	/**
196
	 * Localize the assets
197
	 * @param  array  $str  Existing strings
198
	 * @return array
199
	 */
200
	public function localize_assets( $str ) {
201
		$str['Add translation'] = __( 'Add translation', 'pods' );
202
		$str['Toggle translations'] = __( 'Toggle translations', 'pods' );
203
		$str['Show translations'] = __( 'Show translations', 'pods' );
204
		$str['Hide translations'] = __( 'Hide translations', 'pods' );
205
		$str['Select'] = __( 'Select', 'pods' );
206
		return $str;
207
	}
208
209
	/**
210
	 * Check is a field name is set for translation
211
	 *
212
	 * @since 0.1
213
	 * @param string $name
214
	 * @return bool
215
	 */
216
	public function is_translatable_field( $name ) {
217
218
		$translatable_fields = $this->get_translatable_fields();
219
220
		// All fields that start with "label"
221
		if ( strpos( $name, 'label' ) === 0 ) {
222
			return true;
223
		}
224
		// All translatable fields
225
		if ( in_array( $name, $translatable_fields ) ) {
226
			return true;
227
		}
228
		// Custom fields data, the name must begin with field_data[
229
		if ( strpos( $name, 'field_data[' ) === 0 ) {
230
			$name = str_replace( 'field_data[', '', $name );
231
			$name = rtrim( $name, ']' );
232
			$name = explode( '][', $name );
233
			$name = end( $name );
234
			// All translatable fields from field_data[ (int) ][ $name ]
235
			if ( in_array( $name, $translatable_fields ) ) {
236
				return true;
237
			}
238
		}
239
		return false;
240
	}
241
242
	/**
243
	 * Get a translated option for a field key (if available)
244
	 *
245
	 * @since  0.1
246
	 * @param  string $current Current value
247
	 * @param  string $key     The key / opion name to search for
248
	 * @param  array  $data    Pod data (can also be an options array of a pod or field)
249
	 * @return string
250
	 */
251
	public function get_value_translation( $current, $key, $data ) {
252
		$locale = $this->locale;
253
		// Validate locale and pod
254
		if ( is_array( $data ) && array_key_exists( $locale, $this->languages ) && $this->obj_is_language_enabled( $locale, $data ) ) {
255
			// Add option keys to $data array
256
			if ( ! empty( $data['options'] ) ) {
257
				$data = array_merge( $data, $data['options'] );
258
			}
259
			// Check if the i18n option exists and isn't empty
260
			if ( ! empty( $data[ $key . '_' . $locale ] ) ) {
261
				return (string) $data[ $key . '_' . $locale ];
262
			}
263
		}
264
		return $current;
265
	}
266
267
	/**
268
	 * Page title for setting pages
269
	 *
270
	 * @since  0.1
271
	 * @see    PodsAdmin.php >> admin_menu()
272
	 * @see    PodsAdmin.php >> admin_content_settings()
273
	 * @param  string $page_title Current page title
274
	 * @param  array  $pod        Pod data
275
	 * @return string
276
	 */
277
	public function admin_menu_page_title_i18n( $page_title, $pod ) {
278
		return (string) $this->get_value_translation( $page_title, 'label', $pod );
279
	}
280
281
	/**
282
	 * Menu title for setting pages
283
	 *
284
	 * @since  0.1
285
	 * @see    PodsAdmin.php >> admin_menu()
286
	 * @param  string $menu_label Current menu label
287
	 * @param  array  $pod        Pod data
288
	 * @return string
289
	 */
290
	public function admin_menu_label_i18n( $menu_label, $pod ) {
291
		return (string) $this->get_value_translation( $menu_label, 'menu_name', $pod );
292
	}
293
294
	/**
295
	 * Returns the translated label if available
296
	 *
297
	 * @since  0.1
298
	 * @see    PodsForm.php >> 'pods_form_ui_label_text' (filter)
299
	 * @param  string $label   The default label
300
	 * @param  string $name    The field name
301
	 * @param  string $help    The help text
302
	 * @param  array  $options The field options
303
	 * @return string
304
	 */
305
	public function fields_ui_label_text_i18n( $label, $name, $help, $options ) {
306
		return (string) $this->get_value_translation( $label, 'label', $options );
307
	}
308
309
	/**
310
	 * Returns the translated description if available
311
	 *
312
	 * @since  0.1
313
	 * @see    PodsForm.php >> 'pods_form_ui_comment_text' (filter)
314
	 * @param  string $message The default description
315
	 * @param  string $name    The field name
316
	 * @param  array  $options The field options
317
	 * @return string
318
	 */
319
	public function fields_ui_comment_text_i18n( $message, $name, $options ) {
320
		return (string) $this->get_value_translation( $message, 'description', $options );
321
	}
322
323
	/**
324
	 * Replaces the default selected text with a translation if available
325
	 *
326
	 * @since  0.1
327
	 * @see    pick.php >> 'pods_field_pick_data' (filter)
328
	 * @param  array  $data    The default data of the field
329
	 * @param  string $name    The field name
330
	 * @param  string $value   The field value
331
	 * @param  array  $options The field options
332
	 * @param  array  $pod     The Pod
333
	 * @param  int    $id      The field ID
334
	 * @return array
335
	 */
336
	public function field_pick_data_i18n( $data, $name, $value, $options, $pod, $id ) {
337
		if ( isset( $data[''] ) && isset( $options['pick_select_text'] ) ) {
338
			$locale = $this->locale;
339
			if (   isset( $options['pick_select_text_' . $locale ] )
340
				&& array_key_exists( $locale, $this->languages )
341
				&& $this->obj_is_language_enabled( $locale, $pod )
342
			) {
343
				$data[''] = $options['pick_select_text_' . $locale ];
344
			}
345
		}
346
		return $data;
347
	}
348
349
	/**
350
	 * Replaces the default values with a translation if available
351
	 *
352
	 * @since  0.1
353
	 * @see    PodsForm.php >> 'pods_form_ui_field_' . $type . '_options' (filter)
354
	 * @param  array  $options The field options
355
	 * @param  string $name    The field name
356
	 * @param  string $value   The field value
357
	 * @param  array  $pod     The Pod
358
	 * @param  int    $id      The field ID
359
	 * @return array
360
	 */
361
	public function form_ui_field_options_i18n( $options, $name, $value, $pod, $id ) {
362
		foreach ( $this->get_translatable_fields() as $field ) {
363
			$locale = $this->locale;
364
			if (   isset( $options[ $field . '_' . $locale ] )
365
				&& array_key_exists( $locale, $this->languages )
366
				&& $this->obj_is_language_enabled( $locale, $pod )
367
			) {
368
				$options[ $field ] = $options[ $field . '_' . $locale ];
369
			}
370
		}
371
		return $options;
372
	}
373
374
	/**
375
	 * Get the i18n files for jquery datepicker from the github repository
376
	 *
377
	 * @since  0.1
378
	 * @link   https://jqueryui.com/datepicker/#localization
379
	 * @link   https://github.com/jquery/jquery-ui/tree/master/ui/i18n
380
	 * @param  array  $args            datepicker arguments
381
	 * @param  string $type            datepicker type
382
	 * @param  array  $options         field options
383
	 * @param  array  $attributes      field attibutes
384
	 * @param  string $name            field name
385
	 * @param  string $form_field_type field type
386
	 * @return array
387
	 */
388
	public function field_date_args_i18n( $args, $type, $options, $attributes, $name, $form_field_type ) {
389
		$locale = $this->get_locale_jquery_ui_i18n();
390
		if ( ! empty( $locale ) ) {
391
			// URL to the raw file on github
392
			$url_base = 'https://rawgit.com/jquery/jquery-ui/master/ui/i18n/';
393
			// Filename prefix
394
			$file_prefix = 'datepicker-';
395
			// Full URL
396
			$i18n_file = $url_base.$file_prefix . $locale . '.js';
397
			// Enqueue script
398
			wp_enqueue_script( 'jquery-ui-i18n-' . $locale, $i18n_file, array( 'jquery-ui-datepicker' ) );
399
			// Add i18n argument to the datepicker
400
			$args['regional'] = $locale;
401
		}
402
		return $args;
403
	}
404
405
	/**
406
	 * Get the locale according to the format available in the jquery ui i18n file list
407
	 *
408
	 * @url    https://github.com/jquery/jquery-ui/tree/master/ui/i18n
409
	 * @return string ex: "fr" or "en-GB"
410
	 */
411
	public function get_locale_jquery_ui_i18n() {
412
		//replace _ by - in "en_GB" for example
413
		$locale = str_replace( '_', '-', get_locale() );
414
		switch ( $locale ) {
415
			case 'ar-DZ':
416
			case 'cy-GB':
417
			case 'en-AU':
418
			case 'en-GB':
419
			case 'en-NZ':
420
			case 'fr-CH':
421
			case 'nl-BE':
422
			case 'pt-BR':
423
			case 'sr-SR':
424
			case 'zh-CN':
425
			case 'zh-HK':
426
			case 'zh-TW':
427
				//For all this locale do nothing the file already exist
428
				break;
429
			default:
430
				//for other locale keep the first part of the locale (ex: "fr-FR" -> "fr")
431
				$locale = substr( $locale, 0, strpos( $locale, '-' ) );
432
				//English is the default locale
433
				$locale = ( $locale == 'en' ) ? '' : $locale;
434
				break;
435
		}
436
		return $locale;
437
	}
438
439
	/**
440
	 * Filter hook function to overwrite the labels and description with translations (if available)
441
	 *
442
	 * @since  0.1
443
	 * @see    PodsInit.php >> setup_content_types()
444
	 * @param  array   $options  The array of object options
445
	 * @param  string  $object   The object type name/slug
446
	 * @return array
447
	 */
448
	public function pods_register_wp_object_i18n( $options, $object ) {
449
450
		$locale = $this->locale;
451
452
		$pod = pods_api()->load_pod( $object );
453
454
		if ( ! $this->obj_is_language_enabled( $locale, $pod ) ) {
455
			return $options;
456
		}
457
458
		// Load the pod
459
		foreach ( $pod[ 'options' ] as $_option => $_value ) {
460
			$pod[ $_option ] = $_value;
461
		}
462
463
		// Default
464
		$locale_labels                          = array();
465
		$locale_labels['name']                  = esc_html( pods_v( 'label_'.$locale, $pod, '', true ) );
466
		$locale_labels['singular_name']         = esc_html( pods_v( 'label_singular_'.$locale, $pod, '', true ) );
467
		$locale_labels['menu_name']             = pods_v( 'menu_name_' . $locale, $pod, '', true );
468
		$locale_labels['add_new_item']          = pods_v( 'label_add_new_item_' . $locale, $pod, '', true );
469
		$locale_labels['edit_item']             = pods_v( 'label_edit_item_' . $locale, $pod, '', true );
470
		$locale_labels['view_item']             = pods_v( 'label_view_item_' . $locale, $pod, '', true );
471
		$locale_labels['all_items']             = pods_v( 'label_all_items_' . $locale, $pod, '', true );
472
		$locale_labels['search_items']          = pods_v( 'label_search_items_' . $locale, $pod, '', true );
473
		$locale_labels['parent_item_colon']     = pods_v( 'label_parent_item_colon_' . $locale, $pod, '', true );
474
		$locale_labels['not_found']             = pods_v( 'label_not_found_' . $locale, $pod, '', true );
475
		$locale_labels['items_list_navigation'] = pods_v( 'label_items_list_navigation_' . $locale, $pod, '', true );
476
		$locale_labels['items_list']            = pods_v( 'label_items_list_' . $locale, $pod, '', true );
477
478
		// Post Types
479
		$locale_labels['name_admin_bar']        = pods_v( 'name_admin_bar_' . $locale, $pod, '', true );
480
		$locale_labels['add_new']               = pods_v( 'label_add_new_' . $locale, $pod, '', true );
481
		$locale_labels['new_item']              = pods_v( 'label_new_item_' . $locale, $pod, '', true );
482
		$locale_labels['edit']                  = pods_v( 'label_edit_' . $locale, $pod, '', true );
483
		$locale_labels['view']                  = pods_v( 'label_view_' . $locale, $pod, '', true );
484
		$locale_labels['view_items']            = pods_v( 'label_view_items_' . $locale, $pod, '', true );
485
		$locale_labels['parent']                = pods_v( 'label_parent_' . $locale, $pod, '', true );
486
		$locale_labels['not_found_in_trash']    = pods_v( 'label_not_found_in_trash_' . $locale, $pod, '', true );
487
		$locale_labels['archives']              = pods_v( 'label_archives_' . $locale, $pod, '', true );
488
		$locale_labels['attributes']            = pods_v( 'label_attributes_' . $locale, $pod, '', true );
489
		$locale_labels['insert_into_item']      = pods_v( 'label_insert_into_item_' . $locale, $pod, '', true );
490
		$locale_labels['uploaded_to_this_item'] = pods_v( 'label_uploaded_to_this_item_' . $locale, $pod, '', true );
491
		$locale_labels['featured_image']        = pods_v( 'label_featured_image_' . $locale, $pod, '', true );
492
		$locale_labels['set_featured_image']    = pods_v( 'label_set_featured_image_' . $locale, $pod, '', true );
493
		$locale_labels['remove_featured_image'] = pods_v( 'label_remove_featured_image_' . $locale, $pod, '', true );
494
		$locale_labels['use_featured_image']    = pods_v( 'label_use_featured_image_' . $locale, $pod, '', true );
495
		$locale_labels['filter_items_list']     = pods_v( 'label_filter_items_list_' . $locale, $pod, '', true );
496
497
		// Taxonomies
498
		$locale_labels['update_item']                = pods_v( 'label_update_item_' . $locale, $pod, '', true );
499
		$locale_labels['popular_items']              = pods_v( 'label_popular_items_' . $locale, $pod, '', true );
500
		$locale_labels['parent_item']                = pods_v( 'label_parent_item_' . $locale, $pod, '', true );
501
		$locale_labels['new_item_name']              = pods_v( 'label_new_item_name_' . $locale, $pod, '', true );
502
		$locale_labels['separate_items_with_commas'] = pods_v( 'label_separate_items_with_commas_' . $locale, $pod, '', true );
503
		$locale_labels['add_or_remove_items']        = pods_v( 'label_add_or_remove_items_' . $locale, $pod, '', true );
504
		$locale_labels['choose_from_most_used']      = pods_v( 'label_choose_from_the_most_used_' . $locale, $pod, '', true );
505
		$locale_labels['no_terms']                   = pods_v( 'label_no_terms_' . $locale, $pod, '', true );
506
507
		// Assign to label array
508
		if ( isset( $options['labels'] ) && is_array( $options['labels'] ) ) {
509
			foreach( $options['labels'] as $key => $value ) {
510
				// @todo Currently I only overwrite, maybe also append even if the default locale isn't set?
511
				if ( isset( $locale_labels[ $key ] ) && ! empty( $locale_labels[ $key ] ) ) {
512
					$options['labels'][ $key ] = $locale_labels[ $key ];
513
				}
514
			}
515
		}
516
517
		return $options;
518
	}
519
520
	/**
521
	 * Filter hook function to overwrite the labels and description with translations (if available)
522
	 *
523
	 * @since  0.1
524
	 * @see    PodsInit.php >> admin_menu()
525
	 * @param  array   $options  The array of object options
526
	 * @param  string  $object   The object type name/slug
527
	 * @return array
528
	 */
529
	function pods_filter_object_strings_i18n( $options, $object ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
530
531
		/**
532
		 * @todo allow labels to be set even if the default language isn't
533
		 *
534
		 * - Find all keys that end with the current locale
535
		 * - Assign them to the keys without that locale
536
		 */
537
538
		foreach( $options as $key => $option ) {
539 View Code Duplication
			if ( is_string( $option ) && $this->is_translatable_field( $key ) ) {
540
				$options[ $key ] = $this->get_value_translation( $option, $key, $options );
541
			}
542
		}
543
544
		if ( ! empty( $options['options'] ) ) {
545
			foreach( $options['options'] as $key => $option ) {
546 View Code Duplication
				if ( is_string( $option ) && $this->is_translatable_field( $key ) ) {
547
					$options['options'][ $key ] = $this->get_value_translation( $option, $key, $options['options'] );
548
				}
549
			}
550
		}
551
552
		return $options;
553
	}
554
555
	/**
556
	 * Save component settings
557
	 *
558
	 * @since 0.1
559
	 */
560
	public function admin_save() {
561
562
		$this->languages_available = get_available_languages();
563
564
		/**
565
		 * format: array( language, version, updated, english_name, native_name, package, iso, strings )
566
		 */
567
		require_once( ABSPATH . 'wp-admin/includes/translation-install.php' );
568
		$this->languages_translated = wp_get_available_translations();
569
570
		$new_languages = array();
571
572
		if ( isset( $_POST['pods_i18n_enabled_languages'] ) && is_array( $_POST['pods_i18n_enabled_languages'] ) ) {
573
			foreach ( $_POST['pods_i18n_enabled_languages'] as $locale ) {
574
				$locale = sanitize_text_field( $locale );
575
576
				if ( in_array( $locale, $this->languages_available ) ) {
577
					$new_languages[ $locale ] = array();
578
579 View Code Duplication
					if ( isset( $this->languages_translated[ $locale ]['language'] ) ) {
580
						$new_languages[ $locale ]['language'] = $this->languages_translated[ $locale ]['language'];
581
					}
582
583 View Code Duplication
					if ( isset( $this->languages_translated[ $locale ]['english_name'] ) ) {
584
						$new_languages[ $locale ]['english_name'] = $this->languages_translated[ $locale ]['english_name'];
585
					}
586
587 View Code Duplication
					if ( isset( $this->languages_translated[ $locale ]['native_name'] ) ) {
588
						$new_languages[ $locale ]['native_name'] = $this->languages_translated[ $locale ]['native_name'];
589
					}
590
				}
591
			}
592
		}
593
594
		$this->languages = $new_languages;
595
		$this->settings['enabled_languages'] = $new_languages;
596
597
		update_option( $this->option_key, $this->settings );
598
599
	}
600
601
	/**
602
	 * Build admin area
603
	 *
604
	 * @since  0.1
605
	 * @param  $options
606
	 * @param  $component
607
	 * @return void
608
	 */
609
	public function admin ( $options, $component ) {
610
611
		$this->languages_available = get_available_languages();
612
613
		/**
614
		 * format: array( language, version, updated, english_name, native_name, package, iso, strings )
615
		 */
616
		require_once( ABSPATH . 'wp-admin/includes/translation-install.php' );
617
618
		$this->languages_translated = wp_get_available_translations();
619
620
		// en_US is always installed (default locale of WP)
621
		$data = array(
622
			'en_US' => array(
623
				'id'          => 'en_US',
624
				'locale'      => 'en_US',
625
				'lang'        => 'English',
626
				'lang_native' => 'English',
627
				'enabled'     => 'Default',
628
			)
629
		);
630
631
		foreach ( $this->languages_available as $locale ) {
632
			$checked = checked( isset( $this->languages[ $locale ] ), true, false );
633
634
			$enabled = sprintf(
635
				'<input type="checkbox" name="pods_i18n_enabled_languages[%s]" value="%s"%s />',
636
				esc_attr( $locale ),
637
				esc_attr( $locale ),
638
				$checked
639
			);
640
641
			$data[ $locale ] = array(
642
				'id'          => $locale,
643
				'locale'      => $locale,
644
				'lang'        => $this->languages_translated[ $locale ]['english_name'],
645
				'lang_native' => $this->languages_translated[ $locale ]['native_name'],
646
				'enabled'     => $enabled,
647
			);
648
		}
649
650
		$ui = array(
651
			'component' => $component,
652
			//'data' => $data,
0 ignored issues
show
Unused Code Comprehensibility introduced by
67% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
653
			//'total' => count( $data ),
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
654
			//'total_found' => count( $data ),
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
655
			'items' => __('Languages', 'pods'),
656
			'item' => __('Language', 'pods'),
657
			'fields' => array(
658
				'manage' => array(
659
					'enabled' => array(
660
						'label' => __( 'Active', 'pods' ),
661
						'type' => 'raw',
662
					),
663
					'locale' => array( 'label' => __( 'Locale', 'pods' ), 'classes' => array( 'column-secondary' ) ),
664
					'lang' => array( 'label' => __( 'Language', 'pods' ) ),
665
					'lang_native' => array( 'label' => __( 'Native name', 'pods' ) ),
666
					/*'fields' => array(
0 ignored issues
show
Unused Code Comprehensibility introduced by
53% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
667
						'label' => __( 'Fields', 'pods' ),
668
						'type' => 'text',
669
						'options' => array(
670
							'text_allow_html' => 1,
671
							'text_allowed_html_tags' => 'br code'
672
						)
673
					),*/
674
				)
675
			),
676
			'actions_disabled' => array( 'edit', 'add', 'delete', 'duplicate', 'view', 'export' ),
677
			'actions_custom' => array(
678
				//'add' => array( $this, 'admin_add' ),
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
679
				//'edit' => array( $this, 'admin_edit' ),
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
680
				//'delete' => array( $this, 'admin_delete' )
0 ignored issues
show
Unused Code Comprehensibility introduced by
54% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
681
			),
682
			'search' => false,
683
			'searchable' => false,
684
			'sortable' => false,
685
			'pagination' => false
686
		);
687
688
		/**
689
		 * Filter the language data
690
		 * @since 0.1
691
		 * @param array
692
		 */
693
		$data = apply_filters( 'pods_component_i18n_admin_data', $data );
694
695
		/**
696
		 * Filter the UI fields
697
		 * @since 0.1
698
		 * @param array
699
		 */
700
		$ui['fields'] = apply_filters( 'pods_component_i18n_admin_ui_fields', $ui['fields'], $data );
701
702
		$ui['data'] = $data;
703
		$ui['total'] = count( $data );
704
		$ui['total_found'] = count( $data );
705
706
		/*if ( !pods_is_admin( array( 'pods_i18n_activate_lanuages' ) ) )
0 ignored issues
show
Unused Code Comprehensibility introduced by
57% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
707
			$ui[ 'actions_disabled' ][] = 'edit';*/
708
709
		echo '<div id="pods_admin_i18n" class="pods-submittable-fields">';
710
711
		// Do save action here because otherwise the loading of post_types get done first and labels aren't translated
712
		if ( pods_is_admin( $this->capability )
713
			&& isset( $_POST['_nonce_i18n'] )
714
			&& wp_verify_nonce( $_POST['_nonce_i18n'], $this->nonce )
715
		) {
716
			pods_message( __( 'Updated active languages.', 'pods' ) );
717
		}
718
719
		pods_ui( $ui );
720
721
		// @todo Do this in pods_ui so we don't rely on javascript
722
		echo '<div id="pods_i18n_settings_save">';
723
		wp_nonce_field( $this->nonce, '_nonce_i18n', false );
724
		submit_button();
725
		echo '</div>';
726
727
		echo '</div>';
728
	}
729
730
	/**
731
	 * The i18n option tab.
732
	 *
733
	 * @todo  Remove if not used in final version
734
	 *
735
	 * @since  0.1
736
	 * @param  array $tabs
737
	 * @param  array $pod
738
	 * @param  array $args
739
	 * @return array
740
	 */
741
	public function pod_tab( $tabs, $pod, $args ) {
742
		$tabs[ 'pods-i18n' ] = __( 'Translation Options', 'pods' );
743
		return $tabs;
744
	}
745
746
	/**
747
	 * The i18n options
748
	 *
749
	 * @todo  Remove if not used in final version
750
	 *
751
	 * @since  0.1
752
	 * @param  array $options
753
	 * @param  array $pod
754
	 * @return array
755
	 */
756
	public function pod_options( $options, $pod ) {
757
758
		//if ( $pod['type'] === '' )
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
759
		/*$options[ 'pods-i18n' ] = array(
0 ignored issues
show
Unused Code Comprehensibility introduced by
55% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
760
			'enabled_languages' => array(
761
				'label' => __( 'Enable/Disable languages for this Pod', 'pods' ),
762
				'help' => __( 'This overwrites the defaults set in the component admin.', 'pods' ),
763
				'group' => array(),
764
			),
765
		);
766
767
		foreach ( $this->languages as $locale => $lang_data ) {
768
			$options['pods-i18n']['enabled_languages']['group']['enable_i18n'][ $locale ] = array(
769
				'label'      => $locale . ' (' . $this->create_lang_label( $lang_data ) . ')',
770
				'default'    => 1,
771
				'type'       => 'boolean',
772
			);
773
		}*/
774
775
		return $options;
776
777
	}
778
779
	/**
780
	 * Add the i18n metabox.
781
	 *
782
	 * @since 0.1
783
	 */
784
	public function admin_meta_box() {
785
		add_meta_box(
786
			'pods_i18n', // ID
787
			__( 'Translation options', 'pods' ), // Label
788
			array( $this, 'meta_box' ), // Callback
789
			'_pods_pod', // Screen
790
			'side', // Context (side)
791
			'default' // Priority
792
		);
793
	}
794
795
	/**
796
	 * The i18n metabox.
797
	 *
798
	 * @todo Store enabled languages serialized instead of separate inputs
799
	 *
800
	 * @since  0.1
801
	 * @param  array $pod
802
	 */
803
	public function meta_box( $pod ) {
804
805
		if ( ! empty( $this->languages ) ) {
806
		?>
807
			<p><?php _e( 'Enable/Disable languages for this Pod', 'pods' ); ?></p>
808
			<p><small class="description"><?php _e( 'This overwrites the defaults set in the component admin.', 'pods' ); ?></small></p>
809
			<div class="pods-field-enable-disable-language">
810
		<?php
811
			foreach ( $this->languages as $locale => $lang_data ) {
812
813
				if ( ! isset( $pod['options']['enable_i18n'][ $locale ] ) ) {
814
					// Enabled by default
815
					$pod['options']['enable_i18n'][ $locale ] = 1;
816
				}
817
		?>
818
				<div class="pods-field-option pods-enable-disable-language" data-locale="<?php echo esc_attr( $locale ) ?>">
819
		<?php
820
					echo PodsForm::field( 'enable_i18n[' . $locale . ']', $pod['options']['enable_i18n'][ $locale ], 'boolean', array(
821
						'boolean_yes_label' =>  '<code>' . $locale . '</code> ' . $this->create_lang_label( $lang_data ),
822
						'boolean_no_label' =>  '',
823
					) );
824
		?>
825
				</div>
826
		<?php
827
			}
828
		?>
829
			</div>
830
			<hr>
831
			<p><button id="toggle_i18n" class="button-secondary"><?php _e( 'Toggle translation visibility', 'pods' ); ?></button></p>
832
		<?php
833
		}
834
	}
835
836
	/**
837
	 * Adds translation inputs to fields
838
	 *
839
	 * @since  0.1
840
	 * @see    PodsForm.php >> 'pods_form_ui_field_' . $type (filter)
841
	 * @param  string $output The default output of the field
842
	 * @param  string $name The field name
843
	 * @param  string $value The field value
844
	 * @param  array $options The field options
845
	 * @param  array $pod The Pod
846
	 * @param  int $id The field ID
847
	 * @return string
848
	 */
849
	public function add_i18n_inputs( $output, $name, $value, $options, $pod, $id ) {
850
851
		if ( ! empty( $pod ) || empty( $name ) || ! $this->is_translatable_field( $name ) ) {
852
			return $output;
853
		}
854
855
856
		$pod = $this->cur_pod;
857
		//print_r( $pod );
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
858
		if ( empty( $pod ) ) {
859
			// Setting the $pod var to a non-empty value is mandatory to prevent a loop
860
			$pod = true;
861
		}
862
863
		$output .= '<br clear="both" />';
864
		$output .= '<div class="pods-i18n-field">';
865
		foreach ( $this->languages as $locale => $lang_data ) {
866
867
			if ( ! $this->obj_is_language_enabled( $locale, (array) $pod ) ) {
868
				continue;
869
			}
870
			// Our own shiny label with language information
871
			$lang_code = '<code style="font-size: 1em;">' . $locale . '</code>';
872
			/*$lang_label = $this->create_lang_label( $lang_data );
0 ignored issues
show
Unused Code Comprehensibility introduced by
48% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
873
			if ( ! empty( $lang_label ) ) {
874
				$lang_label = $lang_code . ' ('. $lang_label .')';
875
			} else {*/
876
				$lang_label = $lang_code;
877
			//}
878
			$lang_label = '<small>' . $lang_label . '</small>';
879
880
			$style = '';
881
882
			// Add language data to name for normal strings and array formatted strings
883
			if ( strpos( $name, ']' ) !== false ) {
884
				// Hide the i18n options for fields by default if they are empty
885
				$field_value = pods_v( $name, $pod );
886
887
				if ( strpos( $name, 'field_data' ) !== false && empty( $field_value ) ) {
888
					$style = ' style="display: none;"';
889
				}
890
891
				$field_name = rtrim( $name, ']' );
892
				$field_name .= '_'.$locale.']';
893
			} else {
894
				$field_name = $name.'_'.$locale;
895
			}
896
897
			// Add the translation fields
898
			$output .= '<div class="pods-i18n-input pods-i18n-input-' . $locale . '" data-locale="' . $locale . '" ' . $style . '>';
899
			$output .= PodsForm::label( $field_name, $lang_label );
900
			$output .= PodsForm::field( $field_name, pods_v( $field_name, $pod ), 'text', null, $pod );
901
			$output .= '</div>';
902
		}
903
		$output .= '</div>';
904
		return $output;
905
	}
906
907
	/**
908
	 * Check if a language is get to enabled for an object
909
	 *
910
	 * @since  0.1
911
	 * @param  string $locale The locale to validate
912
	 * @param  array  $data   Object data
913
	 * @return bool
914
	 */
915
	public function obj_is_language_enabled( $locale, $data ) {
916
		// If the locale isn't enabled in the global scope from the component it's always disabled
917
		if ( ! array_key_exists( $locale, $this->languages ) ) {
918
			return false;
919
		}
920
		$data = (array) $data;
921
		$options = ( isset( $data['options'] ) ) ? $data['options'] : $data;
922
		// If it doesn't exist in the object data then use the default (enabled)
923
		if ( isset( $options['enable_i18n'][ $locale ] ) && false === (bool) $options['enable_i18n'][ $locale ] ) {
924
			return false;
925
		}
926
		return true;
927
	}
928
929
	/**
930
	 * Create a label with the english and native name combined
931
	 *
932
	 * @since  0.1
933
	 * @param  array $lang_data
934
	 * @return string
935
	 */
936
	public function create_lang_label( $lang_data ) {
937
938
		$english_name = '';
939
		$native_name = '';
940
941
		if ( isset( $lang_data['english_name'] ) ) {
942
			$english_name = $lang_data['english_name'];
943
		}
944
		if ( isset( $lang_data['native_name'] ) ) {
945
			$native_name = $lang_data['native_name'];
946
		}
947
948
		if ( ! empty( $native_name ) && ! empty( $english_name ) ) {
949
			if ( $native_name == $english_name ) {
950
				return $english_name;
951
			} else {
952
				return $english_name . ' / ' . $native_name;
953
			}
954
		} else {
955
			if ( ! empty( $english_name ) ) {
956
				return $english_name;
957
			}
958
			if ( ! empty( $native_name ) ) {
959
				return $native_name;
960
			}
961
		}
962
		return '';
963
	}
964
965
	public function get_translatable_fields() {
966
		return apply_filters( 'pods_translatable_fields', $this->translatable_fields );
967
	}
968
969
}
970