Completed
Pull Request — 2.x (#4569)
by Scott Kingsley
04:56
created

PodsField_DateTime::setup()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * @package Pods\Fields
5
 */
6
class PodsField_DateTime extends PodsField {
7
8
	/**
9
	 * {@inheritdoc}
10
	 */
11
	public static $group = 'Date / Time';
12
13
	/**
14
	 * {@inheritdoc}
15
	 */
16
	public static $type = 'datetime';
17
18
	/**
19
	 * {@inheritdoc}
20
	 */
21
	public static $label = 'Date / Time';
22
23
	/**
24
	 * {@inheritdoc}
25
	 */
26
	public static $prepare = '%s';
27
28
	/**
29
	 * Storage format.
30
	 *
31
	 * @var string
32
	 * @since 2.7
33
	 */
34
	public static $storage_format = 'Y-m-d H:i:s';
35
36
	/**
37
	 * The default empty value (database)
38
	 *
39
	 * @var string
40
	 * @since 2.7
41
	 */
42
	public static $empty_value = '0000-00-00 00:00:00';
43
44
	/**
45
	 * {@inheritdoc}
46
	 */
47
	public function setup() {
48
49
		static::$label = __( 'Date / Time', 'pods' );
50
	}
51
52
	/**
53
	 * {@inheritdoc}
54
	 */
55
	public function options() {
56
57
		$options = array(
58
			static::$type . '_repeatable'            => array(
59
				'label'             => __( 'Repeatable Field', 'pods' ),
60
				'default'           => 0,
61
				'type'              => 'boolean',
62
				'help'              => __( 'Making a field repeatable will add controls next to the field which allows users to Add/Remove/Reorder additional values. These values are saved in the database as an array, so searching and filtering by them may require further adjustments".', 'pods' ),
63
				'boolean_yes_label' => '',
64
				'dependency'        => true,
65
				'developer_mode'    => true,
66
			),
67
			static::$type . '_type'                  => array(
68
				'label'                        => __( 'Date Format Type', 'pods' ),
69
				'default'                      => 'format',
70
				// Backwards compatibility
71
										'type' => 'pick',
72
				'help'                         => __( 'WordPress Default is the format used in Settings, General under "Date Format".', 'pods' ) . '<br>' . __( 'Predefined Format will allow you to select from a list of commonly used date formats.', 'pods' ) . '<br>' . __( 'Custom will allow you to enter your own using PHP Date/Time Strings.', 'pods' ),
73
				'data'                         => array(
74
					'wp'     => __( 'WordPress default', 'pods' ) . ': ' . date_i18n( get_option( 'date_format' ) ),
75
					'format' => __( 'Predefined format', 'pods' ),
76
					'custom' => __( 'Custom format', 'pods' ),
77
				),
78
				'dependency'                   => true,
79
			),
80
			static::$type . '_format_custom'         => array(
81
				'label'      => __( 'Date format for display', 'pods' ),
82
				'depends-on' => array( static::$type . '_type' => 'custom' ),
83
				'default'    => '',
84
				'type'       => 'text',
85
				'help'       => sprintf(
86
					'<a href="http://php.net/manual/function.date.php" target="_blank">%s</a>',
87
					esc_html__( 'PHP date documentation', 'pods' )
88
				),
89
			),
90
			static::$type . '_format_custom_js'      => array(
91
				'label'      => __( 'Date format for input', 'pods' ),
92
				'depends-on' => array( static::$type . '_type' => 'custom' ),
93
				'default'    => '',
94
				'type'       => 'text',
95
				'help'       => sprintf(
96
					'<a href="https://api.jqueryui.com/datepicker/" target="_blank">%1$s</a><br />%2$s',
97
					esc_html__( 'jQuery UI datepicker documentation', 'pods' ),
98
					esc_html__( 'Leave empty to auto-generate from PHP format.', 'pods' )
99
				),
100
			),
101
			static::$type . '_format'                => array(
102
				'label'      => __( 'Date Format', 'pods' ),
103
				'depends-on' => array( static::$type . '_type' => 'format' ),
104
				'default'    => 'mdy',
105
				'type'       => 'pick',
106
				'data'       => array(
107
					'mdy'       => date_i18n( 'm/d/Y' ),
108
					'mdy_dash'  => date_i18n( 'm-d-Y' ),
109
					'mdy_dot'   => date_i18n( 'm.d.Y' ),
110
					'ymd_slash' => date_i18n( 'Y/m/d' ),
111
					'ymd_dash'  => date_i18n( 'Y-m-d' ),
112
					'ymd_dot'   => date_i18n( 'Y.m.d' ),
113
					'fjy'       => date_i18n( 'F j, Y' ),
114
					'fjsy'      => date_i18n( 'F jS, Y' ),
115
					'c'         => date_i18n( 'c' ),
116
				),
117
				'dependency' => true,
118
			),
119
			static::$type . '_time_type'             => array(
120
				'label'                        => __( 'Time Format Type', 'pods' ),
121
				'excludes-on'                  => array( static::$type . '_format' => 'c' ),
122
				'default'                      => '12',
123
				// Backwards compatibility
124
										'type' => 'pick',
125
				'help'                         => __( 'WordPress Default is the format used in Settings, General under "Time Format".', 'pods' ) . '<br>' . __( '12/24 hour will allow you to select from a list of commonly used time formats.', 'pods' ) . '<br>' . __( 'Custom will allow you to enter your own using PHP Date/Time Strings.', 'pods' ),
126
				'data'                         => array(
127
					'wp'     => __( 'WordPress default', 'pods' ) . ': ' . date_i18n( get_option( 'time_format' ) ),
128
					'12'     => __( '12 hour', 'pods' ),
129
					'24'     => __( '24 hour', 'pods' ),
130
					'custom' => __( 'Custom', 'pods' ),
131
				),
132
				'dependency'                   => true,
133
			),
134
			static::$type . '_time_format_custom'    => array(
135
				'label'       => __( 'Time format', 'pods' ),
136
				'depends-on'  => array( static::$type . '_time_type' => 'custom' ),
137
				'excludes-on' => array( static::$type . '_format' => 'c' ),
138
				'default'     => '',
139
				'type'        => 'text',
140
				'help'        => '<a href="http://php.net/manual/function.date.php" target="_blank">' . __( 'PHP date documentation', 'pods' ) . '</a>',
141
			),
142
			static::$type . '_time_format_custom_js' => array(
143
				'label'       => __( 'Time format field input', 'pods' ),
144
				'depends-on'  => array( static::$type . '_time_type' => 'custom' ),
145
				'excludes-on' => array( static::$type . '_format' => 'c' ),
146
				'default'     => '',
147
				'type'        => 'text',
148
				'help'        => sprintf(
149
					'<a href="http://trentrichardson.com/examples/timepicker/#tp-formatting" target="_blank">%1$s</a><br />%2$s',
150
					esc_html__( 'jQuery UI timepicker documentation', 'pods' ),
151
					esc_html__( 'Leave empty to auto-generate from PHP format.', 'pods' )
152
				),
153
			),
154
			static::$type . '_time_format'           => array(
155
				'label'       => __( 'Time Format', 'pods' ),
156
				'depends-on'  => array( static::$type . '_time_type' => '12' ),
157
				'excludes-on' => array( static::$type . '_format' => 'c' ),
158
				'default'     => 'h_mma',
159
				'type'        => 'pick',
160
				'data'        => array(
161
					'h_mm_A'     => date_i18n( 'g:i A' ),
162
					'h_mm_ss_A'  => date_i18n( 'g:i:s A' ),
163
					'hh_mm_A'    => date_i18n( 'h:i A' ),
164
					'hh_mm_ss_A' => date_i18n( 'h:i:s A' ),
165
					'h_mma'      => date_i18n( 'g:ia' ),
166
					'hh_mma'     => date_i18n( 'h:ia' ),
167
					'h_mm'       => date_i18n( 'g:i' ),
168
					'h_mm_ss'    => date_i18n( 'g:i:s' ),
169
					'hh_mm'      => date_i18n( 'h:i' ),
170
					'hh_mm_ss'   => date_i18n( 'h:i:s' ),
171
				),
172
			),
173
			static::$type . '_time_format_24'        => array(
174
				'label'       => __( 'Time Format', 'pods' ),
175
				'depends-on'  => array( static::$type . '_time_type' => '24' ),
176
				'excludes-on' => array( static::$type . '_format' => 'c' ),
177
				'default'     => 'hh_mm',
178
				'type'        => 'pick',
179
				'data'        => array(
180
					'hh_mm'    => date_i18n( 'H:i' ),
181
					'hh_mm_ss' => date_i18n( 'H:i:s' ),
182
				),
183
			),
184
			static::$type . '_allow_empty'           => array(
185
				'label'   => __( 'Allow empty value?', 'pods' ),
186
				'default' => 1,
187
				'type'    => 'boolean',
188
			),
189
			static::$type . '_html5'                 => array(
190
				'label'   => __( 'Enable HTML5 Input Field?', 'pods' ),
191
				'default' => apply_filters( 'pods_form_ui_field_html5', 0, static::$type ),
192
				'type'    => 'boolean',
193
			),
194
		);
195
196
		// Check if PHP DateTime::createFromFormat exists for additional supported formats
197 View Code Duplication
		if ( method_exists( 'DateTime', 'createFromFormat' ) || apply_filters( 'pods_form_ui_field_datetime_custom_formatter', false ) ) {
198
			$options[ static::$type . '_format' ]['data'] = array_merge(
199
				$options[ static::$type . '_format' ]['data'], array(
200
					'dmy'      => date_i18n( 'd/m/Y' ),
201
					'dmy_dash' => date_i18n( 'd-m-Y' ),
202
					'dmy_dot'  => date_i18n( 'd.m.Y' ),
203
					'dMy'      => date_i18n( 'd/M/Y' ),
204
					'dMy_dash' => date_i18n( 'd-M-Y' ),
205
				)
206
			);
207
		}
208
209
		$options[ static::$type . '_format' ]['data']    = apply_filters( 'pods_form_ui_field_date_format_options', $options[ static::$type . '_format' ]['data'] );
210
		$options[ static::$type . '_format' ]['default'] = apply_filters( 'pods_form_ui_field_date_format_default', $options[ static::$type . '_format' ]['default'] );
211
212
		$options[ static::$type . '_time_type' ]['default']      = apply_filters( 'pods_form_ui_field_time_format_type_default', $options[ static::$type . '_time_type' ]['default'] );
213
		$options[ static::$type . '_time_format' ]['data']       = apply_filters( 'pods_form_ui_field_time_format_options', $options[ static::$type . '_time_format' ]['data'] );
214
		$options[ static::$type . '_time_format' ]['default']    = apply_filters( 'pods_form_ui_field_time_format_default', $options[ static::$type . '_time_format' ]['default'] );
215
		$options[ static::$type . '_time_format_24' ]['data']    = apply_filters( 'pods_form_ui_field_time_format_24_options', $options[ static::$type . '_time_format_24' ]['data'] );
216
		$options[ static::$type . '_time_format_24' ]['default'] = apply_filters( 'pods_form_ui_field_time_format_24_default', $options[ static::$type . '_time_format_24' ]['default'] );
217
218
		return $options;
219
	}
220
221
	/**
222
	 * {@inheritdoc}
223
	 */
224
	public function schema( $options = null ) {
225
226
		$schema = 'DATETIME NOT NULL default "0000-00-00 00:00:00"';
227
228
		return $schema;
229
	}
230
231
	/**
232
	 * {@inheritdoc}
233
	 */
234
	public function is_empty( $value = null ) {
235
236
		$is_empty = false;
237
238
		$value = trim( $value );
239
240
		if ( empty( $value ) || in_array( $value, array( '0000-00-00', '0000-00-00 00:00:00', '00:00:00' ), true ) ) {
241
			$is_empty = true;
242
		}
243
244
		return $is_empty;
245
246
	}
247
248
	/**
249
	 * {@inheritdoc}
250
	 */
251
	public function display( $value = null, $name = null, $options = null, $pod = null, $id = null ) {
252
253
		$value = $this->format_value_display( $value, $options, false );
254
255
		return $value;
256
	}
257
258
	/**
259
	 * {@inheritdoc}
260
	 */
261
	public function input( $name, $value = null, $options = null, $pod = null, $id = null ) {
262
263
		$options         = (array) $options;
264
		$form_field_type = PodsForm::$field_type;
265
266
		if ( is_array( $value ) ) {
267
			$value = implode( ' ', $value );
268
		}
269
270
		// Format Value
271
		$value = $this->format_value_display( $value, $options, true );
272
273
		$field_type = static::$type;
274
275
		if ( isset( $options['name'] ) && false === PodsForm::permission( static::$type, $options['name'], $options, null, $pod, $id ) ) {
276
			if ( pods_v( 'read_only', $options, false ) ) {
277
				$options['readonly'] = true;
278
279
				$field_type = 'text';
280
			} else {
281
				return;
282
			}
283
		} elseif ( ! pods_has_permissions( $options ) && pods_v( 'read_only', $options, false ) ) {
284
			$options['readonly'] = true;
285
286
			$field_type = 'text';
287
		}
288
289
		pods_view( PODS_DIR . 'ui/fields/' . $field_type . '.php', compact( array_keys( get_defined_vars() ) ) );
290
	}
291
292
	/**
293
	 * {@inheritdoc}
294
	 */
295
	public function validate( $value, $name = null, $options = null, $fields = null, $pod = null, $id = null, $params = null ) {
296
297
		if ( ! empty( $value ) && ( 0 === (int) pods_v( static::$type . '_allow_empty', $options, 1 ) || ! in_array(
298
			$value, array(
299
				'0000-00-00',
300
				'0000-00-00 00:00:00',
301
				'00:00:00',
302
			), true
303
		) ) ) {
304
			$js = true;
305
306
			if ( 'custom' !== pods_v( static::$type . '_type', $options, 'format' ) ) {
307
				$js = false;
308
			}
309
310
			$format = $this->format( $options, $js );
311
312
			if ( $js ) {
313
				$format = $this->convert_format( $format, array( 'source' => 'jquery_ui' ) );
314
			}
315
316
			$check = $this->convert_date( $value, static::$storage_format, $format, true );
317
318
			if ( false === $check ) {
319
				$label = pods_v( 'label', $options, ucwords( str_replace( '_', ' ', $name ) ) );
320
321
				return sprintf( esc_html__( '%1$s was not provided in a recognizable format: "%2$s"', 'pods' ), $label, $value );
322
			}
323
		}//end if
324
325
		return true;
326
327
	}
328
329
	/**
330
	 * {@inheritdoc}
331
	 */
332
	public function pre_save( $value, $id = null, $name = null, $options = null, $fields = null, $pod = null, $params = null ) {
333
334
		$js = true;
335
		if ( 'custom' !== pods_v( static::$type . '_type', $options, 'format' ) ) {
336
			$js = false;
337
		}
338
		$format = $this->format( $options, $js );
339
		if ( $js ) {
340
			$format = $this->convert_format( $format, array( 'source' => 'jquery_ui' ) );
341
		}
342
343
		if ( ! empty( $value ) && ( 0 === (int) pods_v( static::$type . '_allow_empty', $options, 1 ) || ! in_array(
344
			$value, array(
345
				'0000-00-00',
346
				'0000-00-00 00:00:00',
347
				'00:00:00',
348
			), true
349
		) ) ) {
350
			$value = $this->convert_date( $value, static::$storage_format, $format );
351 View Code Duplication
		} elseif ( 1 === (int) pods_v( static::$type . '_allow_empty', $options, 1 ) ) {
352
			$value = static::$empty_value;
353
		} else {
354
			$value = date_i18n( static::$storage_format );
355
		}
356
357
		return $value;
358
	}
359
360
	/**
361
	 * {@inheritdoc}
362
	 */
363
	public function ui( $id, $value, $name = null, $options = null, $fields = null, $pod = null ) {
364
365
		$value = $this->display( $value, $name, $options, $pod, $id );
366
367
		if ( 1 === (int) pods_v( static::$type . '_allow_empty', $options, 1 ) && ( empty( $value ) || in_array(
368
			$value, array(
369
				'0000-00-00',
370
				'0000-00-00 00:00:00',
371
				'00:00:00',
372
			), true
373
		) ) ) {
374
			$value = false;
375
		}
376
377
		return $value;
378
	}
379
380
	/**
381
	 * Convert value to the correct format for display.
382
	 *
383
	 * @param string $value   Field value.
384
	 * @param array  $options Field options.
385
	 * @param bool   $js      Return formatted from jQuery UI format? (only for custom formats).
386
	 *
387
	 * @return string
388
	 * @since 2.7
389
	 */
390
	public function format_value_display( $value, $options, $js = false ) {
391
392
		if ( 'custom' !== pods_v( static::$type . '_type', $options, 'format' ) ) {
393
			$js = false;
394
		}
395
		$format = $this->format( $options, $js );
396
		if ( $js ) {
397
			$format = $this->convert_format( $format, array( 'source' => 'jquery_ui' ) );
398
		}
399
400
		if ( ! empty( $value ) && ! in_array( $value, array( '0000-00-00', '0000-00-00 00:00:00', '00:00:00' ), true ) ) {
401
			// Try default storage format.
402
			$date = $this->createFromFormat( static::$storage_format, (string) $value );
403
			// Try field format.
404
			$date_local = $this->createFromFormat( $format, (string) $value );
405
406 View Code Duplication
			if ( $date instanceof DateTime ) {
407
				$value = $date->format( $format );
408
			} elseif ( $date_local instanceof DateTime ) {
409
				$value = $date_local->format( $format );
410
			} else {
411
				$value = date_i18n( $format, strtotime( (string) $value ) );
412
			}
413 View Code Duplication
		} elseif ( 0 === (int) pods_v( static::$type . '_allow_empty', $options, 1 ) ) {
414
			$value = date_i18n( $format );
415
		} else {
416
			$value = '';
417
		}
418
419
		return $value;
420
	}
421
422
	/**
423
	 * {@inheritdoc}
424
	 */
425
	public function format( $options, $js = false ) {
426
427
		$format = $this->format_date( $options, $js );
428
429
		$type = pods_v( static::$type . '_type', $options, 'format' );
430
431
		if ( 'format' !== $type || 'c' !== pods_v( static::$type . '_format', $options, '' ) ) {
432
			$format .= ' ' . $this->format_time( $options, $js );
433
		}
434
435
		return $format;
436
	}
437
438
	/**
439
	 * Build date format string based on options
440
	 *
441
	 * @since  2.7
442
	 *
443
	 * @param  array $options Field options.
444
	 * @param  bool  $js      Whether to return format for jQuery UI.
445
	 *
446
	 * @return string
447
	 */
448
	public function format_date( $options, $js = false ) {
449
450
		switch ( (string) pods_v( static::$type . '_type', $options, 'format', true ) ) {
451
			case 'wp':
452
				$format = get_option( 'date_format' );
453
				if ( $js ) {
454
					$format = $this->convert_format( $format, array( 'source' => 'php' ) );
455
				}
456
				break;
457
			case 'custom':
458
				if ( ! $js ) {
459
					$format = pods_v( static::$type . '_format_custom', $options, '' );
460
				} else {
461
					$format = pods_v( static::$type . '_format_custom_js', $options, '' );
462
					if ( empty( $format ) ) {
463
						$format = pods_v( static::$type . '_format_custom', $options, '' );
464
						$format = $this->convert_format( $format, array( 'source' => 'php' ) );
465
					}
466
				}
467
				break;
468
			default:
469
				$date_format = $this->get_date_formats( $js );
470
				$format      = $date_format[ pods_v( static::$type . '_format', $options, 'ymd_dash', true ) ];
471
				break;
472
		}//end switch
473
474
		return $format;
475
	}
476
477
	/**
478
	 * Build time format string based on options
479
	 *
480
	 * @since  2.7
481
	 *
482
	 * @param  array $options Field options.
483
	 * @param  bool  $js      Whether to return format for jQuery UI.
484
	 *
485
	 * @return string
486
	 */
487 View Code Duplication
	public function format_time( $options, $js = false ) {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
488
489
		switch ( (string) pods_v( static::$type . '_time_type', $options, '12', true ) ) {
490
			case '12':
491
				$time_format = $this->get_time_formats( $js );
492
				$format      = $time_format[ pods_v( static::$type . '_time_format', $options, 'hh_mm', true ) ];
493
				break;
494
			case '24':
495
				$time_format_24 = $this->get_time_formats_24( $js );
496
				$format         = $time_format_24[ pods_v( static::$type . '_time_format_24', $options, 'hh_mm', true ) ];
497
				break;
498
			case 'custom':
499
				if ( ! $js ) {
500
					$format = pods_v( static::$type . '_time_format_custom', $options, '' );
501
				} else {
502
					$format = pods_v( static::$type . '_time_format_custom_js', $options, '' );
503
					if ( empty( $format ) ) {
504
						$format = pods_v( static::$type . '_time_format_custom', $options, '' );
505
						$format = $this->convert_format( $format, array( 'source' => 'php' ) );
506
					}
507
				}
508
				break;
509
			default:
510
				$format = get_option( 'time_format' );
511
				if ( $js ) {
512
					$format = $this->convert_format( $format, array( 'source' => 'php' ) );
513
				}
514
				break;
515
		}//end switch
516
517
		return $format;
518
	}
519
520
	/**
521
	 * Get the date formats.
522
	 *
523
	 * @since  2.7
524
	 *
525
	 * @param  bool $js Whether to return format for jQuery UI.
526
	 *
527
	 * @return array
528
	 */
529
	public function get_date_formats( $js = false ) {
530
531
		$date_format = array(
532
			'mdy'       => 'm/d/Y',
533
			'mdy_dash'  => 'm-d-Y',
534
			'mdy_dot'   => 'm.d.Y',
535
			'dmy'       => 'd/m/Y',
536
			'dmy_dash'  => 'd-m-Y',
537
			'dmy_dot'   => 'd.m.Y',
538
			'ymd_slash' => 'Y/m/d',
539
			'ymd_dash'  => 'Y-m-d',
540
			'ymd_dot'   => 'Y.m.d',
541
			'dMy'       => 'd/M/Y',
542
			'dMy_dash'  => 'd-M-Y',
543
			'fjy'       => 'F j, Y',
544
			'fjsy'      => 'F jS, Y',
545
			'y'         => 'Y',
546
		);
547
		$filter      = 'pods_form_ui_field_date_formats';
548
		if ( $js ) {
549
			// @todo Method parameters? (Not supported by array_map)
550
			$date_format = array_map( array( $this, 'convert_format' ), $date_format );
551
			$filter      = 'pods_form_ui_field_date_js_formats';
552
		}
553
554
		return apply_filters( $filter, $date_format );
555
	}
556
557
	/**
558
	 * Get the time formats.
559
	 *
560
	 * @since  2.7
561
	 *
562
	 * @param  bool $js Whether to return format for jQuery UI.
563
	 *
564
	 * @return array
565
	 */
566
	public function get_time_formats( $js = false ) {
567
568
		$time_format = array(
569
			'h_mm_A'     => 'g:i A',
570
			'h_mm_ss_A'  => 'g:i:s A',
571
			'hh_mm_A'    => 'h:i A',
572
			'hh_mm_ss_A' => 'h:i:s A',
573
			'h_mma'      => 'g:ia',
574
			'hh_mma'     => 'h:ia',
575
			'h_mm'       => 'g:i',
576
			'h_mm_ss'    => 'g:i:s',
577
			'hh_mm'      => 'h:i',
578
			'hh_mm_ss'   => 'h:i:s',
579
		);
580
		$filter      = 'pods_form_ui_field_time_formats';
581
		if ( $js ) {
582
			// @todo Method parameters? (Not supported by array_map)
583
			$time_format = array_map( array( $this, 'convert_format' ), $time_format );
584
			$filter      = 'pods_form_ui_field_time_js_formats';
585
		}
586
587
		return apply_filters( $filter, $time_format );
588
	}
589
590
	/**
591
	 * Get the time formats.
592
	 *
593
	 * @since  2.7
594
	 *
595
	 * @param  bool $js Whether to return format for jQuery UI.
596
	 *
597
	 * @return array
598
	 */
599
	public function get_time_formats_24( $js = false ) {
600
601
		$time_format_24 = array(
602
			'hh_mm'    => 'H:i',
603
			'hh_mm_ss' => 'H:i:s',
604
		);
605
		$filter         = 'pods_form_ui_field_time_formats_24';
606
		if ( $js ) {
607
			// @todo Method parameters? (Not supported by array_map)
608
			$time_format_24 = array_map( array( $this, 'convert_format' ), $time_format_24 );
609
			$filter         = 'pods_form_ui_field_time_js_formats_24';
610
		}
611
612
		return apply_filters( $filter, $time_format_24 );
613
	}
614
615
	/**
616
	 * PHP backwards compatibility for createFromFormat.
617
	 *
618
	 * @param string  $format           Format string.
619
	 * @param string  $date             Defaults to time() if empty.
620
	 * @param boolean $return_timestamp Whether to return the strtotime() or createFromFormat result or not.
621
	 *
622
	 * @return DateTime|null|int|false
623
	 */
624
	public function createFromFormat( $format, $date, $return_timestamp = false ) {
625
626
		$datetime = null;
627
628
		if ( method_exists( 'DateTime', 'createFromFormat' ) ) {
629
			$timezone = get_option( 'timezone_string' );
630
631
			if ( empty( $timezone ) ) {
632
				$timezone = timezone_name_from_abbr( '', get_option( 'gmt_offset' ) * HOUR_IN_SECONDS, 0 );
633
			}
634
635
			if ( ! empty( $timezone ) ) {
636
				$datetimezone = new DateTimeZone( $timezone );
637
638
				$datetime = DateTime::createFromFormat( $format, (string) $date, $datetimezone );
0 ignored issues
show
Bug introduced by
The method createFromFormat() does not exist on DateTime. Did you maybe mean format()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
639
640
				if ( false === $datetime ) {
641
					$datetime = DateTime::createFromFormat( static::$storage_format, (string) $date, $datetimezone );
0 ignored issues
show
Bug introduced by
The method createFromFormat() does not exist on DateTime. Did you maybe mean format()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
642
				}
643
644
				if ( false !== $datetime && $return_timestamp ) {
645
					return $datetime;
646
				}
647
			}
648
		}//end if
649
650
		if ( in_array( $datetime, array( null, false ), true ) ) {
651
			if ( empty( $date ) ) {
652
				$timestamp = time();
653
			} else {
654
				$timestamp = strtotime( (string) $date );
655
656
				if ( $return_timestamp ) {
657
					return $timestamp;
658
				}
659
			}
660
			if ( $timestamp ) {
661
				$datetime = new DateTime( date_i18n( static::$storage_format, $timestamp ) );
662
			}
663
		}
664
665
		return apply_filters( 'pods_form_ui_field_datetime_formatter', $datetime, $format, $date );
666
	}
667
668
	/**
669
	 * Convert a date from one format to another.
670
	 *
671
	 * @param string  $value            Field value.
672
	 * @param string  $new_format       New format string.
673
	 * @param string  $original_format  Original format string (if known).
674
	 * @param boolean $return_timestamp Whether to return the strtotime() or createFromFormat result or not.
675
	 *
676
	 * @return string|int|boolean|DateTime
677
	 */
678
	public function convert_date( $value, $new_format, $original_format = '', $return_timestamp = false ) {
679
680
		if ( empty( $original_format ) ) {
681
			$original_format = static::$storage_format;
682
		}
683
684
		$date = '';
685
686
		if ( ! empty( $value ) && ! in_array( $value, array( '0000-00-00', '0000-00-00 00:00:00', '00:00:00' ), true ) ) {
687
			$date = $this->createFromFormat( $original_format, (string) $value, $return_timestamp );
688
689 View Code Duplication
			if ( $date instanceof DateTime ) {
690
				$value = $date->format( $new_format );
691
			} elseif ( false !== $date ) {
692
				$date = strtotime( (string) $value );
693
694
				$value = date_i18n( $new_format, $date );
695
			}
696
		} else {
697
			$value = date_i18n( $new_format );
698
		}
699
700
		// Return timestamp conversion result instead
701
		if ( $return_timestamp ) {
702
			return $date;
703
		}
704
705
		return $value;
706
	}
707
708
	/**
709
	 * Matches each symbol of PHP date format standard with jQuery equivalent codeword.
710
	 *
711
	 * @link   http://stackoverflow.com/questions/16702398/convert-a-php-date-format-to-a-jqueryui-datepicker-date-format
712
	 * @link   https://api.jqueryui.com/datepicker/
713
	 * @link   http://trentrichardson.com/examples/timepicker/
714
	 *
715
	 * @since  2.7
716
	 *
717
	 * @param  string $source_format Source format string.
718
	 * @param  array  $args          Format arguments.
719
	 *
720
	 * @return string
721
	 */
722
	public function convert_format( $source_format, $args = array() ) {
723
724
		// @todo Improve source/target logic.
725
		$args = array_merge(
726
			array(
727
				'source' => 'php',
728
			// 'jquery_ui' for reverse.
729
			), $args
730
		);
731
732
		// Keep keys and values sorted by string length.
733
		$symbols = array(
734
			// Day
735
			'd' => 'dd',
736
			'l' => 'DD',
737
			'D' => 'D',
738
			'j' => 'd',
739
			'N' => '',
740
			'S' => '',
741
			'w' => '',
742
			'z' => 'o',
743
			// Week
744
			'W' => '',
745
			// Month
746
			'F' => 'MM',
747
			'm' => 'mm',
748
			'M' => 'M',
749
			'n' => 'm',
750
			't' => '',
751
			// Year
752
			'L' => '',
753
			'o' => '',
754
			'Y' => 'yy',
755
			'y' => 'y',
756
			// AM/PM
757
			'a' => 'tt',
758
			'A' => 'TT',
759
			// Swatch internet time (not supported)
760
			'B' => '',
761
			// Hour
762
			'h' => 'hh',
763
			'H' => 'HH',
764
			'g' => 'h',
765
			'G' => 'H',
766
			// Minute
767
			'i' => 'mm',
768
			// Second
769
			's' => 'ss',
770
			// Microsecond
771
			'u' => 'c',
772
		);
773
774
		if ( version_compare( PHP_VERSION, '7.0.0' ) >= 0 ) {
775
			// Millisecond
776
			$symbols['v'] = 'l';
777
		}
778
779
		if ( 'jquery_ui' === $args['source'] ) {
780
			// Remove empty values.
781
			$symbols = array_filter( $symbols );
782
			$symbols = array_flip( $symbols );
783
		}
784
785
		$new_format = '';
786
		$escaping   = false;
787
788
		$source_format_length = strlen( $source_format );
789
790
		for ( $i = 0; $i < $source_format_length; $i ++ ) {
791
			$char = $source_format[ $i ];
792
793
			// PHP date format escaping character
794
			// @todo Do we want to support non-format characters?
795
			if ( '\\' === $char ) {
796
				$i ++;
797
798
				if ( $escaping ) {
799
					$new_format .= $source_format[ $i ];
800
				} else {
801
					$new_format .= '\'' . $source_format[ $i ];
802
				}
803
804
				$escaping = true;
805
			} else {
806
				if ( $escaping ) {
807
					$new_format .= "'";
808
					$escaping    = false;
809
				}
810
811
				$symbol_key = false;
812
813
				if ( isset( $source_format[ $i + 1 ] ) ) {
814
					$symbol_key = $char . $source_format[ $i + 1 ];
815
				}
816
817
				// Support 2 characters.
818
				if ( $symbol_key && isset( $symbols[ $symbol_key ] ) ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $symbol_key of type string|false is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
819
					$new_format .= $symbols[ $symbol_key ];
820
821
					$i ++;
822
				} elseif ( isset( $symbols[ $char ] ) ) {
823
					$new_format .= $symbols[ $char ];
824
				} else {
825
					$new_format .= $char;
826
				}
827
			}//end if
828
		}//end for
829
830
		return $new_format;
831
	}
832
833
	/**
834
	 * Enqueue the i18n files for jquery date/timepicker
835
	 *
836
	 * @since  2.7
837
	 */
838
	public function enqueue_jquery_ui_i18n() {
839
840
		static $done = array();
841
842
		$types = array();
843
844
		switch ( static::$type ) {
845
			case 'time':
846
				$types[] = 'time';
847
848
				break;
849
			case 'date':
850
				$types[] = 'date';
851
852
				break;
853
			case 'datetime':
854
				$types[] = 'time';
855
				$types[] = 'date';
856
857
				break;
858
		}
859
860
		if ( in_array( 'date', $types, true ) && ! in_array( 'date', $done, true ) ) {
861
			if ( function_exists( 'wp_localize_jquery_ui_datepicker' ) ) {
862
				wp_localize_jquery_ui_datepicker();
863
			}
864
865
			$done[] = 'date';
866
		}
867
868
		if ( in_array( 'time', $types, true ) && ! in_array( 'time', $done, true ) ) {
869
			$locale = str_replace( '_', '-', get_locale() );
870
871
			// Local files.
872
			if ( ! file_exists( PODS_DIR . 'ui/js/timepicker/i18n/jquery-ui-timepicker-' . $locale . '.js' ) ) {
873
				// Fallback to the base language (non-region specific).
874
				$locale = substr( $locale, 0, strpos( $locale, '-' ) );
875
			}
876
877
			if ( ! wp_script_is( 'jquery-ui-timepicker-i18n-' . $locale, 'registered' ) && file_exists( PODS_DIR . 'ui/js/timepicker/i18n/jquery-ui-timepicker-' . $locale . '.js' ) ) {
878
				wp_enqueue_script( 'jquery-ui-timepicker-i18n-' . $locale, PODS_URL . 'ui/js/timepicker/i18n/jquery-ui-timepicker-' . $locale . '.js', array( 'jquery-ui-timepicker' ), '1.6.3' );
879
			}
880
881
			$done[] = 'time';
882
		}
883
	}
884
}
885