PluginProbe ʕ •ᴥ•ʔ
Pods – Custom Content Types and Fields / 2.7.31.4
Pods – Custom Content Types and Fields v2.7.31.4
2.7.31.4 2.8.23.5 2.9.19.5 3.0.10.5 3.1.4.3 3.2.8.4 3.3.9.2 2.8.23.4 2.9.19.4 3.0.10.4 3.1.4.2 3.2.8.3 3.3.9.1 trunk 1.14.8 2.7.31.3 2.8.23.3 2.9.19.3 3.0.10.3 3.1.4.1 3.2.0 3.2.1 3.2.1.1 3.2.2 3.2.4 3.2.5 3.2.6 3.2.7 3.2.7.1 3.2.8 3.2.8.1 3.2.8.2 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9
pods / classes / fields / datetime.php
pods / classes / fields Last commit date
avatar.php 2 days ago boolean.php 2 days ago code.php 2 days ago color.php 2 days ago comment.php 2 days ago currency.php 2 days ago date.php 2 days ago datetime.php 2 days ago email.php 2 days ago file.php 2 days ago html.php 2 days ago link.php 2 days ago number.php 2 days ago oembed.php 2 days ago paragraph.php 2 days ago password.php 2 days ago phone.php 2 days ago pick.php 2 days ago slug.php 2 days ago taxonomy.php 2 days ago text.php 2 days ago time.php 2 days ago website.php 2 days ago wysiwyg.php 2 days ago
datetime.php
997 lines
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.0
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.0
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" rel="noopener noreferrer">%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" rel="noopener noreferrer">%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" rel="noopener noreferrer">' . __( '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" rel="noopener noreferrer">%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 . '_year_range_custom' => array(
185 'label' => __( 'Year range', 'pods' ),
186 'default' => '',
187 'type' => 'text',
188 'help' => sprintf(
189 '%1$s<br /><a href="https://api.jqueryui.com/datepicker/#option-yearRange" target="_blank" rel="noopener noreferrer">%2$s</a>',
190 sprintf(
191 esc_html__( 'Example: %1$s for specifying a hard coded year range or %2$s for the last and next 10 years.', 'pods' ),
192 '<code>2010:2030</code>',
193 '<code>-10:+10</code>'
194 ),
195 esc_html__( 'jQuery UI datepicker documentation', 'pods' )
196 ),
197 ),
198 static::$type . '_allow_empty' => array(
199 'label' => __( 'Allow empty value?', 'pods' ),
200 'default' => 1,
201 'type' => 'boolean',
202 ),
203 static::$type . '_html5' => array(
204 'label' => __( 'Enable HTML5 Input Field?', 'pods' ),
205 'default' => apply_filters( 'pods_form_ui_field_html5', 0, static::$type ),
206 'type' => 'boolean',
207 ),
208 );
209
210 // Check if PHP DateTime::createFromFormat exists for additional supported formats
211 if ( method_exists( 'DateTime', 'createFromFormat' ) || apply_filters( 'pods_form_ui_field_datetime_custom_formatter', false ) ) {
212 $options[ static::$type . '_format' ]['data'] = array_merge(
213 $options[ static::$type . '_format' ]['data'], array(
214 'dmy' => date_i18n( 'd/m/Y' ),
215 'dmy_dash' => date_i18n( 'd-m-Y' ),
216 'dmy_dot' => date_i18n( 'd.m.Y' ),
217 'dMy' => date_i18n( 'd/M/Y' ),
218 'dMy_dash' => date_i18n( 'd-M-Y' ),
219 )
220 );
221 }
222
223 $options[ static::$type . '_format' ]['data'] = apply_filters( 'pods_form_ui_field_date_format_options', $options[ static::$type . '_format' ]['data'] );
224 $options[ static::$type . '_format' ]['default'] = apply_filters( 'pods_form_ui_field_date_format_default', $options[ static::$type . '_format' ]['default'] );
225
226 $options[ static::$type . '_time_type' ]['default'] = apply_filters( 'pods_form_ui_field_time_format_type_default', $options[ static::$type . '_time_type' ]['default'] );
227 $options[ static::$type . '_time_format' ]['data'] = apply_filters( 'pods_form_ui_field_time_format_options', $options[ static::$type . '_time_format' ]['data'] );
228 $options[ static::$type . '_time_format' ]['default'] = apply_filters( 'pods_form_ui_field_time_format_default', $options[ static::$type . '_time_format' ]['default'] );
229 $options[ static::$type . '_time_format_24' ]['data'] = apply_filters( 'pods_form_ui_field_time_format_24_options', $options[ static::$type . '_time_format_24' ]['data'] );
230 $options[ static::$type . '_time_format_24' ]['default'] = apply_filters( 'pods_form_ui_field_time_format_24_default', $options[ static::$type . '_time_format_24' ]['default'] );
231
232 return $options;
233 }
234
235 /**
236 * {@inheritdoc}
237 */
238 public function schema( $options = null ) {
239
240 $schema = 'DATETIME NOT NULL default "0000-00-00 00:00:00"';
241
242 return $schema;
243 }
244
245 /**
246 * {@inheritdoc}
247 */
248 public function is_empty( $value = null ) {
249
250 $is_empty = false;
251
252 $value = trim( $value );
253
254 if ( empty( $value ) || in_array( $value, array( '0000-00-00', '0000-00-00 00:00:00' ), true ) ) {
255 $is_empty = true;
256 }
257
258 return $is_empty;
259
260 }
261
262 /**
263 * {@inheritdoc}
264 */
265 public function display( $value = null, $name = null, $options = null, $pod = null, $id = null ) {
266 return $this->format_value_display( $value, $options, false );
267 }
268
269 /**
270 * {@inheritdoc}
271 */
272 public function input( $name, $value = null, $options = null, $pod = null, $id = null ) {
273
274 $options = (array) $options;
275 $form_field_type = PodsForm::$field_type;
276
277 if ( is_array( $value ) ) {
278 $value = implode( ' ', $value );
279 }
280
281 // @todo Remove? Format Value (done in field template).
282 //$value = $this->format_value_display( $value, $options, true );
283
284 $field_type = static::$type;
285
286 if ( isset( $options['name'] ) && false === PodsForm::permission( static::$type, $options['name'], $options, null, $pod, $id ) ) {
287 if ( pods_v( 'read_only', $options, false ) ) {
288 $options['readonly'] = true;
289
290 $field_type = 'text';
291 } else {
292 return;
293 }
294 } elseif ( ! pods_has_permissions( $options ) && pods_v( 'read_only', $options, false ) ) {
295 $options['readonly'] = true;
296
297 $field_type = 'text';
298 }
299
300 pods_view( PODS_DIR . 'ui/fields/' . $field_type . '.php', compact( array_keys( get_defined_vars() ) ) );
301 }
302
303 /**
304 * {@inheritdoc}
305 */
306 public function validate( $value, $name = null, $options = null, $fields = null, $pod = null, $id = null, $params = null ) {
307 $validate = parent::validate( $value, $name, $options, $fields, $pod, $id, $params );
308
309 $errors = array();
310
311 if ( is_array( $validate ) ) {
312 $errors = $validate;
313 }
314
315 if ( ! $this->is_empty( $value ) ) {
316
317 // Value should always be passed as storage format since 2.7.15.
318 $format = static::$storage_format;
319
320 if ( ! $this->is_storage_format( $value ) ) {
321 // Allow input values compatible with the display format.
322 $format = $this->format_display( $options, false );
323 }
324
325 $check = $this->convert_date( $value, static::$storage_format, $format, true );
326
327 if ( false === $check ) {
328 $label = pods_v( 'label', $options, ucwords( str_replace( '_', ' ', $name ) ) );
329
330 // Translators: %1$s is the field label and %2$s is the input value.
331 $errors[] = sprintf( esc_html__( '%1$s was not provided in a recognizable format: "%2$s"', 'pods' ), $label, $value );
332 }
333 }
334
335 if ( ! empty( $errors ) ) {
336 return $errors;
337 }
338
339 return $validate;
340 }
341
342 /**
343 * {@inheritdoc}
344 */
345 public function pre_save( $value, $id = null, $name = null, $options = null, $fields = null, $pod = null, $params = null ) {
346
347 // Value should always be passed as storage format since 2.7.15.
348 $format = static::$storage_format;
349
350 if ( ! $this->is_empty( $value ) ) {
351 if ( ! $this->is_storage_format( $value ) ) {
352 // Allow input values compatible with the display format.
353 $format = $this->format_display( $options, false );
354 }
355 $value = $this->convert_date( $value, static::$storage_format, $format );
356 } elseif ( pods_v( static::$type . '_allow_empty', $options, 1 ) ) {
357 $value = static::$empty_value;
358 } else {
359 $value = date_i18n( static::$storage_format );
360 }
361
362 return $value;
363 }
364
365 /**
366 * {@inheritdoc}
367 */
368 public function ui( $id, $value, $name = null, $options = null, $fields = null, $pod = null ) {
369
370 $value = $this->display( $value, $name, $options, $pod, $id );
371
372 if ( $this->is_empty( $value ) && pods_v( static::$type . '_allow_empty', $options, 1 ) ) {
373 $value = false;
374 }
375
376 return $value;
377 }
378
379 /**
380 * Convert value to the correct format for display.
381 *
382 * @param string $value Field value.
383 * @param array $options Field options.
384 * @param bool $js Return formatted from jQuery UI format? (only for custom formats).
385 *
386 * @return string
387 * @since 2.7.0
388 */
389 public function format_value_display( $value, $options, $js = false ) {
390
391 $format = $this->format_display( $options, $js );
392
393 if ( ! $this->is_empty( $value ) ) {
394 // Try default storage format.
395 $date = $this->createFromFormat( static::$storage_format, (string) $value );
396
397 // Convert to timestamp.
398 if ( $date instanceof DateTime ) {
399 $timestamp = $date->getTimestamp();
400 } else {
401 // Try field format.
402 $date_local = $this->createFromFormat( $format, (string) $value );
403
404 if ( $date_local instanceof DateTime ) {
405 $timestamp = $date_local->getTimestamp();
406 } else {
407 // Fallback.
408 $timestamp = strtotime( (string) $value );
409 }
410 }
411
412 $value = date_i18n( $format, $timestamp );
413 } elseif ( ! 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 * Build date and/or time display format string based on options
424 *
425 * @since 2.7.13
426 *
427 * @param array $options Field options.
428 * @param bool $js Whether to return format for jQuery UI.
429 *
430 * @return string
431 */
432 public function format_display( $options, $js = false ) {
433
434 if ( 'custom' === pods_v( static::$type . '_type', $options, 'format' ) ) {
435 if ( $js ) {
436
437 // Gets format strings in jQuery UI format.
438 $date = $this->format_date( $options, $js );
439 $time = $this->format_time( $options, $js );
440
441 // Convert them to PHP date format.
442 $date = $this->convert_format( $date, array( 'source' => 'jquery_ui', 'type' => 'date' ) );
443 $time = $this->convert_format( $time, array( 'source' => 'jquery_ui', 'type' => 'time' ) );
444
445 return $date . ' ' . $time;
446
447 } else {
448 $format = $this->format_datetime( $options, $js );
449 }
450 } else {
451 $js = false;
452 $format = $this->format_datetime( $options, $js );
453 }
454
455 return $format;
456 }
457
458 /**
459 * Build date and/or time format string based on options
460 *
461 * @since 2.7.0
462 *
463 * @param array $options Field options.
464 * @param bool $js Whether to return format for jQuery UI.
465 *
466 * @return string
467 */
468 public function format_datetime( $options, $js = false ) {
469
470 $format = $this->format_date( $options, $js );
471
472 $type = pods_v( static::$type . '_type', $options, 'format' );
473
474 if ( 'format' !== $type || 'c' !== pods_v( static::$type . '_format', $options, '' ) ) {
475 $format .= ' ' . $this->format_time( $options, $js );
476 }
477
478 return $format;
479 }
480
481 /**
482 * Build date format string based on options
483 *
484 * @since 2.7.0
485 *
486 * @param array $options Field options.
487 * @param bool $js Whether to return format for jQuery UI.
488 *
489 * @return string
490 */
491 public function format_date( $options, $js = false ) {
492
493 switch ( (string) pods_v( static::$type . '_type', $options, 'format', true ) ) {
494 case 'wp':
495 $format = get_option( 'date_format' );
496
497 if ( $js ) {
498 $format = $this->convert_format( $format, array( 'source' => 'php', 'type' => 'date' ) );
499 }
500
501 break;
502 case 'custom':
503 if ( ! $js ) {
504 $format = pods_v( static::$type . '_format_custom', $options, '' );
505 } else {
506 $format = pods_v( static::$type . '_format_custom_js', $options, '' );
507
508 if ( empty( $format ) ) {
509 $format = pods_v( static::$type . '_format_custom', $options, '' );
510
511 if ( $js ) {
512 $format = $this->convert_format( $format, array( 'source' => 'php', 'type' => 'date' ) );
513 }
514 }
515 }
516
517 break;
518 default:
519 $date_format = $this->get_date_formats( $js );
520
521 $format = $date_format[ pods_v( static::$type . '_format', $options, 'ymd_dash', true ) ];
522
523 break;
524 }//end switch
525
526 return $format;
527 }
528
529 /**
530 * Build time format string based on options
531 *
532 * @since 2.7.0
533 *
534 * @param array $options Field options.
535 * @param bool $js Whether to return format for jQuery UI.
536 *
537 * @return string
538 */
539 public function format_time( $options, $js = false ) {
540
541 switch ( (string) pods_v( static::$type . '_time_type', $options, '12', true ) ) {
542 case '12':
543 $time_format = $this->get_time_formats( $js );
544
545 $format = $time_format[ pods_v( static::$type . '_time_format', $options, 'hh_mm', true ) ];
546
547 break;
548 case '24':
549 $time_format_24 = $this->get_time_formats_24( $js );
550
551 $format = $time_format_24[ pods_v( static::$type . '_time_format_24', $options, 'hh_mm', true ) ];
552
553 break;
554 case 'custom':
555 if ( ! $js ) {
556 $format = pods_v( static::$type . '_time_format_custom', $options, '' );
557 } else {
558 $format = pods_v( static::$type . '_time_format_custom_js', $options, '' );
559 $js = false; // Already in JS format.
560
561 if ( empty( $format ) ) {
562 $format = pods_v( static::$type . '_time_format_custom', $options, '' );
563 $js = true;
564 }
565 }
566
567 break;
568 default:
569 $format = get_option( 'time_format' );
570
571 break;
572 }//end switch
573
574 return $format;
575 }
576
577 /**
578 * Get the date formats.
579 *
580 * @since 2.7.0
581 *
582 * @param bool $js Whether to return format for jQuery UI.
583 *
584 * @return array
585 */
586 public function get_date_formats( $js = false ) {
587
588 $date_format = array(
589 'mdy' => 'm/d/Y',
590 'mdy_dash' => 'm-d-Y',
591 'mdy_dot' => 'm.d.Y',
592 'dmy' => 'd/m/Y',
593 'dmy_dash' => 'd-m-Y',
594 'dmy_dot' => 'd.m.Y',
595 'ymd_slash' => 'Y/m/d',
596 'ymd_dash' => 'Y-m-d',
597 'ymd_dot' => 'Y.m.d',
598 'dMy' => 'd/M/Y',
599 'dMy_dash' => 'd-M-Y',
600 'fjy' => 'F j, Y',
601 'fjsy' => 'F jS, Y',
602 'y' => 'Y',
603 );
604
605 $filter = 'pods_form_ui_field_date_formats';
606
607 if ( $js ) {
608 foreach ( $date_format as $key => $value ) {
609 $date_format[ $key ] = $this->convert_format( $value, array( 'type' => 'date' ) );
610 }
611
612 $filter = 'pods_form_ui_field_date_js_formats';
613 }
614
615 return apply_filters( $filter, $date_format );
616 }
617
618 /**
619 * Get the time formats.
620 *
621 * @since 2.7.0
622 *
623 * @param bool $js Whether to return format for jQuery UI.
624 *
625 * @return array
626 */
627 public function get_time_formats( $js = false ) {
628
629 $time_format = array(
630 'h_mm_A' => 'g:i A',
631 'h_mm_ss_A' => 'g:i:s A',
632 'hh_mm_A' => 'h:i A',
633 'hh_mm_ss_A' => 'h:i:s A',
634 'h_mma' => 'g:ia',
635 'hh_mma' => 'h:ia',
636 'h_mm' => 'g:i',
637 'h_mm_ss' => 'g:i:s',
638 'hh_mm' => 'h:i',
639 'hh_mm_ss' => 'h:i:s',
640 );
641
642 $filter = 'pods_form_ui_field_time_formats';
643
644 if ( $js ) {
645 foreach ( $time_format as $key => $value ) {
646 $time_format[ $key ] = $this->convert_format( $value, array( 'type' => 'time' ) );
647 }
648
649 $filter = 'pods_form_ui_field_time_js_formats';
650 }
651
652 return apply_filters( $filter, $time_format );
653 }
654
655 /**
656 * Get the time formats.
657 *
658 * @since 2.7.0
659 *
660 * @param bool $js Whether to return format for jQuery UI.
661 *
662 * @return array
663 */
664 public function get_time_formats_24( $js = false ) {
665
666 $time_format_24 = array(
667 'hh_mm' => 'H:i',
668 'hh_mm_ss' => 'H:i:s',
669 );
670
671 $filter = 'pods_form_ui_field_time_formats_24';
672
673 if ( $js ) {
674 foreach ( $time_format_24 as $key => $value ) {
675 $time_format_24[ $key ] = $this->convert_format( $value, array( 'type' => 'time' ) );
676 }
677
678 $filter = 'pods_form_ui_field_time_js_formats_24';
679 }
680
681 return apply_filters( $filter, $time_format_24 );
682 }
683
684 /**
685 * PHP backwards compatibility for createFromFormat.
686 *
687 * @param string $format Format string.
688 * @param string $date Defaults to time() if empty.
689 * @param boolean $return_timestamp Whether to return the strtotime() or createFromFormat result or not.
690 *
691 * @return DateTime|null|int|false
692 */
693 public function createFromFormat( $format, $date, $return_timestamp = false ) {
694
695 $datetime = null;
696
697 try {
698 if ( method_exists( 'DateTime', 'createFromFormat' ) ) {
699
700 $datetime = DateTime::createFromFormat( $format, (string) $date );
701
702 if ( false === $datetime ) {
703 $datetime = DateTime::createFromFormat( static::$storage_format, (string) $date );
704 }
705
706 if ( false !== $datetime && $return_timestamp ) {
707 return $datetime;
708 }
709
710 }//end if
711
712 if ( in_array( $datetime, array( null, false ), true ) ) {
713 if ( empty( $date ) ) {
714 $timestamp = time();
715 } else {
716 $timestamp = strtotime( (string) $date );
717
718 if ( $return_timestamp ) {
719 return $timestamp;
720 }
721 }
722
723 if ( $timestamp ) {
724 $datetime = new DateTime( date_i18n( static::$storage_format, $timestamp ) );
725 }
726 }
727 } catch ( Exception $e ) {
728 // There is no saving this time value, it's an exception to the rule.
729 }
730
731 return apply_filters( 'pods_form_ui_field_datetime_formatter', $datetime, $format, $date );
732 }
733
734 /**
735 * Check if a value is compatible with the storage format.
736 *
737 * Valid:
738 * - 0000-00-00 00:00:00
739 * - 0000-00-00 00:00
740 * - 0000-00-00
741 * - 0000-00
742 * - etc.
743 *
744 * @param string $value The date value.
745 * @return bool
746 */
747 public function is_storage_format( $value ) {
748 $value_parts = str_split( $value );
749 $format_parts = str_split( gmdate( static::$storage_format ) );
750
751 $valid = true;
752 foreach ( $value_parts as $i => $part ) {
753 if ( isset( $format_parts[ $i ] ) ) {
754 if ( is_numeric( $format_parts[ $i ] ) ) {
755 if ( ! is_numeric( $part ) ) {
756 $valid = false;
757 break;
758 }
759 } elseif ( $format_parts[ $i ] !== $part ) {
760 $valid = false;
761 break;
762 }
763 }
764 }
765 return $valid;
766 }
767
768 /**
769 * Convert a date from one format to another.
770 *
771 * @param string $value Field value.
772 * @param string $new_format New format string.
773 * @param string $original_format Original format string (if known).
774 * @param boolean $return_timestamp Whether to return the strtotime() or createFromFormat result or not.
775 *
776 * @return string|int|boolean|DateTime
777 */
778 public function convert_date( $value, $new_format, $original_format = '', $return_timestamp = false ) {
779
780 if ( empty( $original_format ) ) {
781 $original_format = static::$storage_format;
782 }
783
784 $date = '';
785
786 if ( ! $this->is_empty( $value ) ) {
787 $date = $this->createFromFormat( $original_format, (string) $value, $return_timestamp );
788
789 if ( $date instanceof DateTime ) {
790 $value = $date->format( $new_format );
791 } elseif ( false !== $date ) {
792 $date = strtotime( (string) $value );
793
794 $value = date_i18n( $new_format, $date );
795 }
796 } else {
797 $value = date_i18n( $new_format );
798 }
799
800 // Return timestamp conversion result instead
801 if ( $return_timestamp ) {
802 return $date;
803 }
804
805 return $value;
806 }
807
808 /**
809 * Matches each symbol of PHP date format standard with jQuery equivalent codeword.
810 *
811 * @link http://stackoverflow.com/questions/16702398/convert-a-php-date-format-to-a-jqueryui-datepicker-date-format
812 * @link https://api.jqueryui.com/datepicker/
813 * @link http://trentrichardson.com/examples/timepicker/
814 *
815 * @since 2.7.0
816 *
817 * @param string $source_format Source format string.
818 * @param array $args Format arguments.
819 *
820 * @return string
821 */
822 public function convert_format( $source_format, $args = array() ) {
823
824 // @todo Improve source/target logic.
825 $args = array_merge(
826 array(
827 'source' => 'php',
828 'type' => 'date',
829 // 'jquery_ui' for reverse.
830 ), $args
831 );
832
833 // Keep keys and values sorted by string length.
834 if ( 'time' === $args['type'] || 'time' === static::$type ) {
835
836 $symbols = array(
837 // AM/PM.
838 'a' => 'tt',
839 'A' => 'TT',
840 // Swatch internet time (not supported).
841 'B' => '',
842 // Hour.
843 'h' => 'hh',
844 'H' => 'HH',
845 'g' => 'h',
846 'G' => 'H',
847 // Minute.
848 'i' => 'mm',
849 // Second.
850 's' => 'ss',
851 // Microsecond.
852 'u' => 'c',
853 // Timezone.
854 'O' => 'z',
855 'P' => 'Z',
856 );
857
858 if ( version_compare( PHP_VERSION, '7.0.0' ) >= 0 ) {
859 // Millisecond.
860 $symbols['v'] = 'l';
861 }
862
863 } else {
864
865 $symbols = array(
866 // Day.
867 'd' => 'dd',
868 'l' => 'DD',
869 'D' => 'D',
870 'j' => 'd',
871 'N' => '',
872 'S' => '',
873 'w' => '',
874 'z' => 'o',
875 // Week.
876 'W' => '',
877 // Month.
878 'F' => 'MM',
879 'm' => 'mm',
880 'M' => 'M',
881 'n' => 'm',
882 't' => '',
883 // Year.
884 'L' => '',
885 'o' => '',
886 'Y' => 'yy',
887 'y' => 'y',
888 );
889 }
890
891 if ( 'jquery_ui' === $args['source'] ) {
892 // Remove empty values.
893 $symbols = array_filter( $symbols );
894 $symbols = array_flip( $symbols );
895 }
896
897 $new_format = '';
898 $escaping = false;
899
900 $source_format_length = strlen( $source_format );
901
902 for ( $i = 0; $i < $source_format_length; $i ++ ) {
903 $char = $source_format[ $i ];
904
905 // PHP date format escaping character
906 // @todo Do we want to support non-format characters?
907 if ( '\\' === $char ) {
908 $i ++;
909
910 if ( $escaping ) {
911 $new_format .= $source_format[ $i ];
912 } else {
913 $new_format .= '\'' . $source_format[ $i ];
914 }
915
916 $escaping = true;
917 } else {
918 if ( $escaping ) {
919 $new_format .= "'";
920 $escaping = false;
921 }
922
923 $symbol_key = false;
924
925 if ( isset( $source_format[ $i + 1 ] ) ) {
926 $symbol_key = $char . $source_format[ $i + 1 ];
927 }
928
929 // Support 2 characters.
930 if ( $symbol_key && isset( $symbols[ $symbol_key ] ) ) {
931 $new_format .= $symbols[ $symbol_key ];
932
933 $i ++;
934 } elseif ( isset( $symbols[ $char ] ) ) {
935 $new_format .= $symbols[ $char ];
936 } else {
937 $new_format .= $char;
938 }
939 }//end if
940 }//end for
941
942 return $new_format;
943 }
944
945 /**
946 * Enqueue the i18n files for jquery date/timepicker
947 *
948 * @since 2.7.0
949 */
950 public function enqueue_jquery_ui_i18n() {
951
952 static $done = array();
953
954 $types = array();
955
956 switch ( static::$type ) {
957 case 'time':
958 $types[] = 'time';
959
960 break;
961 case 'date':
962 $types[] = 'date';
963
964 break;
965 case 'datetime':
966 $types[] = 'time';
967 $types[] = 'date';
968
969 break;
970 }
971
972 if ( in_array( 'date', $types, true ) && ! in_array( 'date', $done, true ) ) {
973 if ( function_exists( 'wp_localize_jquery_ui_datepicker' ) ) {
974 wp_localize_jquery_ui_datepicker();
975 }
976
977 $done[] = 'date';
978 }
979
980 if ( in_array( 'time', $types, true ) && ! in_array( 'time', $done, true ) ) {
981 $locale = str_replace( '_', '-', get_locale() );
982
983 // Local files.
984 if ( ! file_exists( PODS_DIR . 'ui/js/timepicker/i18n/jquery-ui-timepicker-' . $locale . '.js' ) ) {
985 // Fallback to the base language (non-region specific).
986 $locale = substr( $locale, 0, strpos( $locale, '-' ) );
987 }
988
989 if ( ! wp_script_is( 'jquery-ui-timepicker-i18n-' . $locale, 'registered' ) && file_exists( PODS_DIR . 'ui/js/timepicker/i18n/jquery-ui-timepicker-' . $locale . '.js' ) ) {
990 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' );
991 }
992
993 $done[] = 'time';
994 }
995 }
996 }
997