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

PodsField_DateTime::pre_save()   C

Complexity

Conditions 7
Paths 12

Size

Total Lines 27
Code Lines 19

Duplication

Lines 3
Ratio 11.11 %

Importance

Changes 0
Metric Value
cc 7
eloc 19
nc 12
nop 7
dl 3
loc 27
rs 6.7272
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 __construct() {
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'       => '<a href="http://php.net/manual/function.date.php" target="_blank">' . __( 'PHP date documentation', 'pods' ) . '</a>',
86
			),
87
			static::$type . '_format_custom_js'      => array(
88
				'label'      => __( 'Date format for input', 'pods' ),
89
				'depends-on' => array( static::$type . '_type' => 'custom' ),
90
				'default'    => '',
91
				'type'       => 'text',
92
				'help'       => '<a href="https://api.jqueryui.com/datepicker/" target="_blank">' . __( 'jQuery UI datepicker documentation', 'pods' ) . '</a>' . '<br>' . __( 'Leave empty to auto-generate from PHP format.', 'pods' ),
93
			),
94
			static::$type . '_format'                => array(
95
				'label'      => __( 'Date Format', 'pods' ),
96
				'depends-on' => array( static::$type . '_type' => 'format' ),
97
				'default'    => 'mdy',
98
				'type'       => 'pick',
99
				'data'       => array(
100
					'mdy'       => date_i18n( 'm/d/Y' ),
101
					'mdy_dash'  => date_i18n( 'm-d-Y' ),
102
					'mdy_dot'   => date_i18n( 'm.d.Y' ),
103
					'ymd_slash' => date_i18n( 'Y/m/d' ),
104
					'ymd_dash'  => date_i18n( 'Y-m-d' ),
105
					'ymd_dot'   => date_i18n( 'Y.m.d' ),
106
					'fjy'       => date_i18n( 'F j, Y' ),
107
					'fjsy'      => date_i18n( 'F jS, Y' ),
108
					'c'         => date_i18n( 'c' ),
109
				),
110
				'dependency' => true,
111
			),
112
			static::$type . '_time_type'             => array(
113
				'label'                        => __( 'Time Format Type', 'pods' ),
114
				'excludes-on'                  => array( static::$type . '_format' => 'c' ),
115
				'default'                      => '12',
116
				// Backwards compatibility
117
										'type' => 'pick',
118
				'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' ),
119
				'data'                         => array(
120
					'wp'     => __( 'WordPress default', 'pods' ) . ': ' . date_i18n( get_option( 'time_format' ) ),
121
					'12'     => __( '12 hour', 'pods' ),
122
					'24'     => __( '24 hour', 'pods' ),
123
					'custom' => __( 'Custom', 'pods' ),
124
				),
125
				'dependency'                   => true,
126
			),
127
			static::$type . '_time_format_custom'    => array(
128
				'label'       => __( 'Time format', 'pods' ),
129
				'depends-on'  => array( static::$type . '_time_type' => 'custom' ),
130
				'excludes-on' => array( static::$type . '_format' => 'c' ),
131
				'default'     => '',
132
				'type'        => 'text',
133
				'help'        => '<a href="http://php.net/manual/function.date.php" target="_blank">' . __( 'PHP date documentation', 'pods' ) . '</a>',
134
			),
135
			static::$type . '_time_format_custom_js' => array(
136
				'label'       => __( 'Time format field input', 'pods' ),
137
				'depends-on'  => array( static::$type . '_time_type' => 'custom' ),
138
				'excludes-on' => array( static::$type . '_format' => 'c' ),
139
				'default'     => '',
140
				'type'        => 'text',
141
				'help'        => '<a href="http://trentrichardson.com/examples/timepicker/#tp-formatting" target="_blank">' . __( 'jQuery UI timepicker documentation', 'pods' ) . '</a>' . '<br>' . __( 'Leave empty to auto-generate from PHP format.', 'pods' ),
142
			),
143
			static::$type . '_time_format'           => array(
144
				'label'       => __( 'Time Format', 'pods' ),
145
				'depends-on'  => array( static::$type . '_time_type' => '12' ),
146
				'excludes-on' => array( static::$type . '_format' => 'c' ),
147
				'default'     => 'h_mma',
148
				'type'        => 'pick',
149
				'data'        => array(
150
					'h_mm_A'     => date_i18n( 'g:i A' ),
151
					'h_mm_ss_A'  => date_i18n( 'g:i:s A' ),
152
					'hh_mm_A'    => date_i18n( 'h:i A' ),
153
					'hh_mm_ss_A' => date_i18n( 'h:i:s A' ),
154
					'h_mma'      => date_i18n( 'g:ia' ),
155
					'hh_mma'     => date_i18n( 'h:ia' ),
156
					'h_mm'       => date_i18n( 'g:i' ),
157
					'h_mm_ss'    => date_i18n( 'g:i:s' ),
158
					'hh_mm'      => date_i18n( 'h:i' ),
159
					'hh_mm_ss'   => date_i18n( 'h:i:s' ),
160
				),
161
			),
162
			static::$type . '_time_format_24'        => array(
163
				'label'       => __( 'Time Format', 'pods' ),
164
				'depends-on'  => array( static::$type . '_time_type' => '24' ),
165
				'excludes-on' => array( static::$type . '_format' => 'c' ),
166
				'default'     => 'hh_mm',
167
				'type'        => 'pick',
168
				'data'        => array(
169
					'hh_mm'    => date_i18n( 'H:i' ),
170
					'hh_mm_ss' => date_i18n( 'H:i:s' ),
171
				),
172
			),
173
			static::$type . '_allow_empty'           => array(
174
				'label'   => __( 'Allow empty value?', 'pods' ),
175
				'default' => 1,
176
				'type'    => 'boolean',
177
			),
178
			static::$type . '_html5'                 => array(
179
				'label'   => __( 'Enable HTML5 Input Field?', 'pods' ),
180
				'default' => apply_filters( 'pods_form_ui_field_html5', 0, static::$type ),
181
				'type'    => 'boolean',
182
			),
183
		);
184
185
		// Check if PHP DateTime::createFromFormat exists for additional supported formats
186 View Code Duplication
		if ( method_exists( 'DateTime', 'createFromFormat' ) || apply_filters( 'pods_form_ui_field_datetime_custom_formatter', false ) ) {
187
			$options[ static::$type . '_format' ]['data'] = array_merge(
188
				$options[ static::$type . '_format' ]['data'], array(
189
					'dmy'      => date_i18n( 'd/m/Y' ),
190
					'dmy_dash' => date_i18n( 'd-m-Y' ),
191
					'dmy_dot'  => date_i18n( 'd.m.Y' ),
192
					'dMy'      => date_i18n( 'd/M/Y' ),
193
					'dMy_dash' => date_i18n( 'd-M-Y' ),
194
				)
195
			);
196
		}
197
198
		$options[ static::$type . '_format' ]['data']    = apply_filters( 'pods_form_ui_field_date_format_options', $options[ static::$type . '_format' ]['data'] );
199
		$options[ static::$type . '_format' ]['default'] = apply_filters( 'pods_form_ui_field_date_format_default', $options[ static::$type . '_format' ]['default'] );
200
201
		$options[ static::$type . '_time_type' ]['default']      = apply_filters( 'pods_form_ui_field_time_format_type_default', $options[ static::$type . '_time_type' ]['default'] );
202
		$options[ static::$type . '_time_format' ]['data']       = apply_filters( 'pods_form_ui_field_time_format_options', $options[ static::$type . '_time_format' ]['data'] );
203
		$options[ static::$type . '_time_format' ]['default']    = apply_filters( 'pods_form_ui_field_time_format_default', $options[ static::$type . '_time_format' ]['default'] );
204
		$options[ static::$type . '_time_format_24' ]['data']    = apply_filters( 'pods_form_ui_field_time_format_24_options', $options[ static::$type . '_time_format_24' ]['data'] );
205
		$options[ static::$type . '_time_format_24' ]['default'] = apply_filters( 'pods_form_ui_field_time_format_24_default', $options[ static::$type . '_time_format_24' ]['default'] );
206
207
		return $options;
208
	}
209
210
	/**
211
	 * {@inheritdoc}
212
	 */
213
	public function schema( $options = null ) {
214
215
		$schema = 'DATETIME NOT NULL default "0000-00-00 00:00:00"';
216
217
		return $schema;
218
	}
219
220
	/**
221
	 * {@inheritdoc}
222
	 */
223
	public function is_empty( $value = null ) {
224
225
		$is_empty = false;
226
227
		$value = trim( $value );
228
229
		if ( empty( $value ) || in_array( $value, array( '0000-00-00', '0000-00-00 00:00:00', '00:00:00' ), true ) ) {
230
			$is_empty = true;
231
		}
232
233
		return $is_empty;
234
235
	}
236
237
	/**
238
	 * {@inheritdoc}
239
	 */
240
	public function display( $value = null, $name = null, $options = null, $pod = null, $id = null ) {
241
242
		$value = $this->format_value_display( $value, $options, false );
243
244
		return $value;
245
	}
246
247
	/**
248
	 * {@inheritdoc}
249
	 */
250
	public function input( $name, $value = null, $options = null, $pod = null, $id = null ) {
251
252
		$options         = (array) $options;
253
		$form_field_type = PodsForm::$field_type;
254
255
		if ( is_array( $value ) ) {
256
			$value = implode( ' ', $value );
257
		}
258
259
		// Format Value
260
		$value = $this->format_value_display( $value, $options, true );
261
262
		$field_type = static::$type;
263
264
		if ( isset( $options['name'] ) && false === PodsForm::permission( static::$type, $options['name'], $options, null, $pod, $id ) ) {
265
			if ( pods_v( 'read_only', $options, false ) ) {
266
				$options['readonly'] = true;
267
268
				$field_type = 'text';
269
			} else {
270
				return;
271
			}
272
		} elseif ( ! pods_has_permissions( $options ) && pods_v( 'read_only', $options, false ) ) {
273
			$options['readonly'] = true;
274
275
			$field_type = 'text';
276
		}
277
278
		pods_view( PODS_DIR . 'ui/fields/' . $field_type . '.php', compact( array_keys( get_defined_vars() ) ) );
279
	}
280
281
	/**
282
	 * {@inheritdoc}
283
	 */
284
	public function validate( $value, $name = null, $options = null, $fields = null, $pod = null, $id = null, $params = null ) {
285
286
		if ( ! empty( $value ) && ( 0 === (int) pods_v( static::$type . '_allow_empty', $options, 1 ) || ! in_array(
287
			$value, array(
288
				'0000-00-00',
289
				'0000-00-00 00:00:00',
290
				'00:00:00',
291
			), true
292
		) ) ) {
293
			$js = true;
294
295
			if ( 'custom' !== pods_v( static::$type . '_type', $options, 'format' ) ) {
296
				$js = false;
297
			}
298
299
			$format = $this->format( $options, $js );
300
301
			if ( $js ) {
302
				$format = $this->convert_format( $format, array( 'source' => 'jquery_ui' ) );
303
			}
304
305
			$check = $this->convert_date( $value, static::$storage_format, $format, true );
306
307
			if ( false === $check ) {
308
				$label = pods_v( 'label', $options, ucwords( str_replace( '_', ' ', $name ) ) );
309
310
				return sprintf( esc_html__( '%1$s was not provided in a recognizable format: "%2$s"', 'pods' ), $label, $value );
311
			}
312
		}//end if
313
314
		return true;
315
316
	}
317
318
	/**
319
	 * {@inheritdoc}
320
	 */
321
	public function pre_save( $value, $id = null, $name = null, $options = null, $fields = null, $pod = null, $params = null ) {
322
323
		$js = true;
324
		if ( 'custom' !== pods_v( static::$type . '_type', $options, 'format' ) ) {
325
			$js = false;
326
		}
327
		$format = $this->format( $options, $js );
328
		if ( $js ) {
329
			$format = $this->convert_format( $format, array( 'source' => 'jquery_ui' ) );
330
		}
331
332
		if ( ! empty( $value ) && ( 0 === (int) pods_v( static::$type . '_allow_empty', $options, 1 ) || ! in_array(
333
			$value, array(
334
				'0000-00-00',
335
				'0000-00-00 00:00:00',
336
				'00:00:00',
337
			), true
338
		) ) ) {
339
			$value = $this->convert_date( $value, static::$storage_format, $format );
340 View Code Duplication
		} elseif ( 1 === (int) pods_v( static::$type . '_allow_empty', $options, 1 ) ) {
341
			$value = static::$empty_value;
342
		} else {
343
			$value = date_i18n( static::$storage_format );
344
		}
345
346
		return $value;
347
	}
348
349
	/**
350
	 * {@inheritdoc}
351
	 */
352
	public function ui( $id, $value, $name = null, $options = null, $fields = null, $pod = null ) {
353
354
		$value = $this->display( $value, $name, $options, $pod, $id );
355
356
		if ( 1 === (int) pods_v( static::$type . '_allow_empty', $options, 1 ) && ( empty( $value ) || in_array(
357
			$value, array(
358
				'0000-00-00',
359
				'0000-00-00 00:00:00',
360
				'00:00:00',
361
			), true
362
		) ) ) {
363
			$value = false;
364
		}
365
366
		return $value;
367
	}
368
369
	/**
370
	 * Convert value to the correct format for display.
371
	 *
372
	 * @param string $value
373
	 * @param array  $options
374
	 * @param bool   $js Return formatted from jQuery UI format? (only for custom formats).
375
	 *
376
	 * @return string
377
	 * @since 2.7
378
	 */
379
	public function format_value_display( $value, $options, $js = false ) {
380
381
		if ( 'custom' !== pods_v( static::$type . '_type', $options, 'format' ) ) {
382
			$js = false;
383
		}
384
		$format = $this->format( $options, $js );
385
		if ( $js ) {
386
			$format = $this->convert_format( $format, array( 'source' => 'jquery_ui' ) );
387
		}
388
389
		if ( ! empty( $value ) && ! in_array( $value, array( '0000-00-00', '0000-00-00 00:00:00', '00:00:00' ), true ) ) {
390
			// Try default storage format.
391
			$date = $this->createFromFormat( static::$storage_format, (string) $value );
392
			// Try field format.
393
			$date_local = $this->createFromFormat( $format, (string) $value );
394
395 View Code Duplication
			if ( $date instanceof DateTime ) {
396
				$value = $date->format( $format );
397
			} elseif ( $date_local instanceof DateTime ) {
398
				$value = $date_local->format( $format );
399
			} else {
400
				$value = date_i18n( $format, strtotime( (string) $value ) );
401
			}
402 View Code Duplication
		} elseif ( 0 === (int) pods_v( static::$type . '_allow_empty', $options, 1 ) ) {
403
			$value = date_i18n( $format );
404
		} else {
405
			$value = '';
406
		}
407
408
		return $value;
409
	}
410
411
	/**
412
	 * {@inheritdoc}
413
	 */
414
	public function format( $options, $js = false ) {
415
416
		$format = $this->format_date( $options, $js );
417
418
		$type = pods_v( static::$type . '_type', $options, 'format' );
419
420
		if ( 'format' !== $type || 'c' !== pods_v( static::$type . '_format', $options, '' ) ) {
421
			$format .= ' ' . $this->format_time( $options, $js );
422
		}
423
424
		return $format;
425
	}
426
427
	/**
428
	 * Build date format string based on options
429
	 *
430
	 * @since  2.7
431
	 *
432
	 * @param  array $options
433
	 * @param  bool  $js Return format for jQuery UI?
434
	 *
435
	 * @return string
436
	 */
437
	public function format_date( $options, $js = false ) {
438
439
		switch ( (string) pods_v( static::$type . '_type', $options, 'format', true ) ) {
440
			case 'wp':
441
				$format = get_option( 'date_format' );
442
				if ( $js ) {
443
					$format = $this->convert_format( $format, array( 'source' => 'php' ) );
444
				}
445
				break;
446
			case 'custom':
447
				if ( ! $js ) {
448
					$format = pods_v( static::$type . '_format_custom', $options, '' );
449
				} else {
450
					$format = pods_v( static::$type . '_format_custom_js', $options, '' );
451
					if ( empty( $format ) ) {
452
						$format = pods_v( static::$type . '_format_custom', $options, '' );
453
						$format = $this->convert_format( $format, array( 'source' => 'php' ) );
454
					}
455
				}
456
				break;
457
			default:
458
				$date_format = $this->get_date_formats( $js );
459
				$format      = $date_format[ pods_v( static::$type . '_format', $options, 'ymd_dash', true ) ];
460
				break;
461
		}//end switch
462
463
		return $format;
464
	}
465
466
	/**
467
	 * Build time format string based on options
468
	 *
469
	 * @since  2.7
470
	 *
471
	 * @param  array $options
472
	 * @param  bool  $js Return format for jQuery UI?
473
	 *
474
	 * @return string
475
	 */
476 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...
477
478
		switch ( (string) pods_v( static::$type . '_time_type', $options, '12', true ) ) {
479
			case '12':
480
				$time_format = $this->get_time_formats( $js );
481
				$format      = $time_format[ pods_v( static::$type . '_time_format', $options, 'hh_mm', true ) ];
482
				break;
483
			case '24':
484
				$time_format_24 = $this->get_time_formats_24( $js );
485
				$format         = $time_format_24[ pods_v( static::$type . '_time_format_24', $options, 'hh_mm', true ) ];
486
				break;
487
			case 'custom':
488
				if ( ! $js ) {
489
					$format = pods_v( static::$type . '_time_format_custom', $options, '' );
490
				} else {
491
					$format = pods_v( static::$type . '_time_format_custom_js', $options, '' );
492
					if ( empty( $format ) ) {
493
						$format = pods_v( static::$type . '_time_format_custom', $options, '' );
494
						$format = $this->convert_format( $format, array( 'source' => 'php' ) );
495
					}
496
				}
497
				break;
498
			default:
499
				$format = get_option( 'time_format' );
500
				if ( $js ) {
501
					$format = $this->convert_format( $format, array( 'source' => 'php' ) );
502
				}
503
				break;
504
		}//end switch
505
506
		return $format;
507
	}
508
509
	/**
510
	 * Get the date formats.
511
	 *
512
	 * @since  2.7
513
	 *
514
	 * @param  bool $js Return formats for jQuery UI?
515
	 *
516
	 * @return array
517
	 */
518
	public function get_date_formats( $js = false ) {
519
520
		$date_format = array(
521
			'mdy'       => 'm/d/Y',
522
			'mdy_dash'  => 'm-d-Y',
523
			'mdy_dot'   => 'm.d.Y',
524
			'dmy'       => 'd/m/Y',
525
			'dmy_dash'  => 'd-m-Y',
526
			'dmy_dot'   => 'd.m.Y',
527
			'ymd_slash' => 'Y/m/d',
528
			'ymd_dash'  => 'Y-m-d',
529
			'ymd_dot'   => 'Y.m.d',
530
			'dMy'       => 'd/M/Y',
531
			'dMy_dash'  => 'd-M-Y',
532
			'fjy'       => 'F j, Y',
533
			'fjsy'      => 'F jS, Y',
534
			'y'         => 'Y',
535
		);
536
		$filter      = 'pods_form_ui_field_date_formats';
537
		if ( $js ) {
538
			// @todo Method parameters? (Not supported by array_map)
539
			$date_format = array_map( array( $this, 'convert_format' ), $date_format );
540
			$filter      = 'pods_form_ui_field_date_js_formats';
541
		}
542
543
		return apply_filters( $filter, $date_format );
544
	}
545
546
	/**
547
	 * Get the time formats.
548
	 *
549
	 * @since  2.7
550
	 *
551
	 * @param  bool $js Return formats for jQuery UI?
552
	 *
553
	 * @return array
554
	 */
555
	public function get_time_formats( $js = false ) {
556
557
		$time_format = array(
558
			'h_mm_A'     => 'g:i A',
559
			'h_mm_ss_A'  => 'g:i:s A',
560
			'hh_mm_A'    => 'h:i A',
561
			'hh_mm_ss_A' => 'h:i:s A',
562
			'h_mma'      => 'g:ia',
563
			'hh_mma'     => 'h:ia',
564
			'h_mm'       => 'g:i',
565
			'h_mm_ss'    => 'g:i:s',
566
			'hh_mm'      => 'h:i',
567
			'hh_mm_ss'   => 'h:i:s',
568
		);
569
		$filter      = 'pods_form_ui_field_time_formats';
570
		if ( $js ) {
571
			// @todo Method parameters? (Not supported by array_map)
572
			$time_format = array_map( array( $this, 'convert_format' ), $time_format );
573
			$filter      = 'pods_form_ui_field_time_js_formats';
574
		}
575
576
		return apply_filters( $filter, $time_format );
577
	}
578
579
	/**
580
	 * Get the time formats.
581
	 *
582
	 * @since  2.7
583
	 *
584
	 * @param  bool $js Return formats for jQuery UI?
585
	 *
586
	 * @return array
587
	 */
588
	public function get_time_formats_24( $js = false ) {
589
590
		$time_format_24 = array(
591
			'hh_mm'    => 'H:i',
592
			'hh_mm_ss' => 'H:i:s',
593
		);
594
		$filter         = 'pods_form_ui_field_time_formats_24';
595
		if ( $js ) {
596
			// @todo Method parameters? (Not supported by array_map)
597
			$time_format_24 = array_map( array( $this, 'convert_format' ), $time_format_24 );
598
			$filter         = 'pods_form_ui_field_time_js_formats_24';
599
		}
600
601
		return apply_filters( $filter, $time_format_24 );
602
	}
603
604
	/**
605
	 * @param string  $format
606
	 * @param string  $date             Defaults to time() if empty.
607
	 * @param boolean $return_timestamp Whether to return the strtotime() or createFromFormat result or not
608
	 *
609
	 * @return DateTime|null|int|false
610
	 */
611
	public function createFromFormat( $format, $date, $return_timestamp = false ) {
612
613
		$datetime = null;
614
615
		if ( method_exists( 'DateTime', 'createFromFormat' ) ) {
616
			$timezone = get_option( 'timezone_string' );
617
618
			if ( empty( $timezone ) ) {
619
				$timezone = timezone_name_from_abbr( '', get_option( 'gmt_offset' ) * HOUR_IN_SECONDS, 0 );
620
			}
621
622
			if ( ! empty( $timezone ) ) {
623
				$datetimezone = new DateTimeZone( $timezone );
624
625
				$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...
626
627
				if ( false === $datetime ) {
628
					$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...
629
				}
630
631
				if ( false !== $datetime && $return_timestamp ) {
632
					return $datetime;
633
				}
634
			}
635
		}//end if
636
637
		if ( in_array( $datetime, array( null, false ), true ) ) {
638
			if ( empty( $date ) ) {
639
				$timestamp = time();
640
			} else {
641
				$timestamp = strtotime( (string) $date );
642
643
				if ( $return_timestamp ) {
644
					return $timestamp;
645
				}
646
			}
647
			if ( $timestamp ) {
648
				$datetime = new DateTime( date_i18n( static::$storage_format, $timestamp ) );
649
			}
650
		}
651
652
		return apply_filters( 'pods_form_ui_field_datetime_formatter', $datetime, $format, $date );
653
	}
654
655
	/**
656
	 * Convert a date from one format to another
657
	 *
658
	 * @param         $value
659
	 * @param         $new_format
660
	 * @param string     $original_format
661
	 * @param boolean    $return_timestamp Whether to return the strtotime() or createFromFormat result or not
662
	 *
663
	 * @return string|int|boolean|DateTime
664
	 */
665
	public function convert_date( $value, $new_format, $original_format = '', $return_timestamp = false ) {
666
667
		if ( empty( $original_format ) ) {
668
			$original_format = static::$storage_format;
669
		}
670
671
		$date = '';
672
673
		if ( ! empty( $value ) && ! in_array( $value, array( '0000-00-00', '0000-00-00 00:00:00', '00:00:00' ), true ) ) {
674
			$date = $this->createFromFormat( $original_format, (string) $value, $return_timestamp );
675
676 View Code Duplication
			if ( $date instanceof DateTime ) {
677
				$value = $date->format( $new_format );
678
			} elseif ( false !== $date ) {
679
				$date = strtotime( (string) $value );
680
681
				$value = date_i18n( $new_format, $date );
682
			}
683
		} else {
684
			$value = date_i18n( $new_format );
685
		}
686
687
		// Return timestamp conversion result instead
688
		if ( $return_timestamp ) {
689
			return $date;
690
		}
691
692
		return $value;
693
	}
694
695
	/**
696
	 * Matches each symbol of PHP date format standard with jQuery equivalent codeword.
697
	 *
698
	 * @link   http://stackoverflow.com/questions/16702398/convert-a-php-date-format-to-a-jqueryui-datepicker-date-format
699
	 * @link   https://api.jqueryui.com/datepicker/
700
	 * @link   http://trentrichardson.com/examples/timepicker/
701
	 *
702
	 * @since  2.7
703
	 *
704
	 * @param  string $source_format
705
	 * @param  array  $args
706
	 *
707
	 * @return string
708
	 */
709
	public function convert_format( $source_format, $args = array() ) {
710
711
		// @todo Improve source/target logic.
712
		$args = array_merge(
713
			array(
714
				'source' => 'php',
715
			// 'jquery_ui' for reverse.
716
			), $args
717
		);
718
719
		// Keep keys and values sorted by string length.
720
		$symbols = array(
721
			// Day
722
			'd' => 'dd',
723
			'l' => 'DD',
724
			'D' => 'D',
725
			'j' => 'd',
726
			'N' => '',
727
			'S' => '',
728
			'w' => '',
729
			'z' => 'o',
730
			// Week
731
			'W' => '',
732
			// Month
733
			'F' => 'MM',
734
			'm' => 'mm',
735
			'M' => 'M',
736
			'n' => 'm',
737
			't' => '',
738
			// Year
739
			'L' => '',
740
			'o' => '',
741
			'Y' => 'yy',
742
			'y' => 'y',
743
			// AM/PM
744
			'a' => 'tt',
745
			'A' => 'TT',
746
			// Swatch internet time (not supported)
747
			'B' => '',
748
			// Hour
749
			'h' => 'hh',
750
			'H' => 'HH',
751
			'g' => 'h',
752
			'G' => 'H',
753
			// Minute
754
			'i' => 'mm',
755
			// Second
756
			's' => 'ss',
757
			// Microsecond
758
			'u' => 'c',
759
		);
760
		if ( version_compare( PHP_VERSION, '7.0.0' ) >= 0 ) {
761
			// Millisecond
762
			$symbols['v'] = 'l';
763
		}
764
		if ( 'jquery_ui' === $args['source'] ) {
765
			// Remove empty values.
766
			$symbols = array_filter( $symbols );
767
			$symbols = array_flip( $symbols );
768
		}
769
		$new_format = '';
770
		$escaping   = false;
771
		for ( $i = 0; $i < strlen( $source_format ); $i ++ ) {
772
			$char = $source_format[ $i ];
773
			// PHP date format escaping character
774
			// @todo Do we want to support non-format characters?
775
			if ( $char === '\\' ) {
776
				$i ++;
777
				if ( $escaping ) {
778
					$new_format .= $source_format[ $i ];
779
				} else {
780
					$new_format .= '\'' . $source_format[ $i ];
781
				}
782
				$escaping = true;
783
			} else {
784
				if ( $escaping ) {
785
					$new_format .= "'";
786
					$escaping    = false;
787
				}
788
				// Support 2 characters.
789
				if ( isset( $source_format[ $i + 1 ] ) && isset( $symbols[ $char . $source_format[ $i + 1 ] ] ) ) {
790
					$new_format .= $symbols[ $char . $source_format[ $i + 1 ] ];
791
					$i ++;
792
				} elseif ( isset( $symbols[ $char ] ) ) {
793
					$new_format .= $symbols[ $char ];
794
				} else {
795
					$new_format .= $char;
796
				}
797
			}//end if
798
		}//end for
799
800
		return $new_format;
801
	}
802
803
	/**
804
	 * Enqueue the i18n files for jquery date/timepicker
805
	 *
806
	 * @since  2.7
807
	 */
808
	public function enqueue_jquery_ui_i18n() {
809
810
		static $done = array();
811
812
		$types = array();
813
		switch ( static::$type ) {
814
			case 'time':
815
				$types[] = 'time';
816
				break;
817
			case 'date':
818
				$types[] = 'date';
819
				break;
820
			case 'datetime':
821
				$types[] = 'time';
822
				$types[] = 'date';
823
				break;
824
		}
825
826
		if ( in_array( 'date', $types, true ) && ! in_array( 'date', $done, true ) ) {
827
828
			if ( function_exists( 'wp_localize_jquery_ui_datepicker' ) ) {
829
				wp_localize_jquery_ui_datepicker();
830
			}
831
832
			$done[] = 'date';
833
		}
834
835
		if ( in_array( 'time', $types, true ) && ! in_array( 'time', $done, true ) ) {
836
837
			$locale = str_replace( '_', '-', get_locale() );
838
839
			// Local files.
840
			if ( ! file_exists( PODS_DIR . 'ui/js/timepicker/i18n/jquery-ui-timepicker-' . $locale . '.js' ) ) {
841
				// Fallback to the base language (non-region specific).
842
				$locale = substr( $locale, 0, strpos( $locale, '-' ) );
843
			}
844
845
			if ( ! wp_script_is( 'jquery-ui-timepicker-i18n-' . $locale, 'registered' ) && file_exists( PODS_DIR . 'ui/js/timepicker/i18n/jquery-ui-timepicker-' . $locale . '.js' ) ) {
846
				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' );
847
			}
848
849
			$done[] = 'time';
850
		}
851
	}
852
}
853