avatar.php
23 hours ago
boolean.php
23 hours ago
code.php
23 hours ago
color.php
23 hours ago
comment.php
23 hours ago
currency.php
23 hours ago
date.php
23 hours ago
datetime.php
23 hours ago
email.php
23 hours ago
file.php
23 hours ago
heading.php
23 hours ago
html.php
23 hours ago
link.php
23 hours ago
number.php
23 hours ago
oembed.php
23 hours ago
paragraph.php
23 hours ago
password.php
23 hours ago
phone.php
23 hours ago
pick.php
23 hours ago
slug.php
23 hours ago
taxonomy.php
23 hours ago
text.php
23 hours ago
time.php
23 hours ago
website.php
23 hours ago
wysiwyg.php
23 hours ago
datetime.php
1317 lines
| 1 | <?php |
| 2 | |
| 3 | use Pods\Static_Cache; |
| 4 | use Pods\Whatsit\Field; |
| 5 | |
| 6 | /** |
| 7 | * @package Pods\Fields |
| 8 | */ |
| 9 | class PodsField_DateTime extends PodsField { |
| 10 | |
| 11 | /** |
| 12 | * {@inheritdoc} |
| 13 | */ |
| 14 | public static $group = 'Date / Time'; |
| 15 | |
| 16 | /** |
| 17 | * {@inheritdoc} |
| 18 | */ |
| 19 | public static $type = 'datetime'; |
| 20 | |
| 21 | /** |
| 22 | * {@inheritdoc} |
| 23 | */ |
| 24 | public static $label = 'Date / Time'; |
| 25 | |
| 26 | /** |
| 27 | * {@inheritdoc} |
| 28 | */ |
| 29 | public static $prepare = '%s'; |
| 30 | |
| 31 | /** |
| 32 | * Storage format. |
| 33 | * |
| 34 | * @var string |
| 35 | * @since 2.7.0 |
| 36 | */ |
| 37 | public static $storage_format = 'Y-m-d H:i:s'; |
| 38 | |
| 39 | /** |
| 40 | * The default empty value (database) |
| 41 | * |
| 42 | * @var string |
| 43 | * @since 2.7.0 |
| 44 | */ |
| 45 | public static $empty_value = '0000-00-00 00:00:00'; |
| 46 | |
| 47 | /** |
| 48 | * {@inheritdoc} |
| 49 | */ |
| 50 | public function setup() { |
| 51 | |
| 52 | static::$group = __( 'Date / Time', 'pods' ); |
| 53 | static::$label = __( 'Date / Time', 'pods' ); |
| 54 | } |
| 55 | |
| 56 | /** |
| 57 | * {@inheritdoc} |
| 58 | */ |
| 59 | public function options() { |
| 60 | |
| 61 | $options = array( |
| 62 | static::$type . '_type' => array( |
| 63 | 'label' => __( 'Date Format Type', 'pods' ), |
| 64 | 'default' => 'format', |
| 65 | // Backwards compatibility |
| 66 | 'type' => 'pick', |
| 67 | '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' ), |
| 68 | 'data' => array( |
| 69 | 'wp' => __( 'WordPress default', 'pods' ) . ': ' . date_i18n( get_option( 'date_format' ) ), |
| 70 | 'format' => __( 'Predefined format', 'pods' ), |
| 71 | 'custom' => __( 'Custom format', 'pods' ), |
| 72 | ), |
| 73 | 'pick_format_single' => 'dropdown', |
| 74 | 'pick_show_select_text' => 0, |
| 75 | 'dependency' => true, |
| 76 | ), |
| 77 | static::$type . '_format_custom' => array( |
| 78 | 'label' => __( 'Date Format for Display', 'pods' ), |
| 79 | 'depends-on' => array( static::$type . '_type' => 'custom' ), |
| 80 | 'default' => '', |
| 81 | 'type' => 'text', |
| 82 | 'help' => sprintf( |
| 83 | '<a href="https://docs.pods.io/fields/date-time-fields/datetime/" target="_blank" rel="noopener noreferrer">%1$s</a>', |
| 84 | esc_html__( 'Date / Time field documentation', 'pods' ) |
| 85 | ), |
| 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' => sprintf( |
| 93 | '<a href="https://docs.pods.io/fields/date-time-fields/datetime/" target="_blank" rel="noopener noreferrer">%1$s</a><br />%2$s', |
| 94 | esc_html__( 'Date / Time field documentation', 'pods' ), |
| 95 | esc_html__( 'Leave empty to auto-generate from PHP format.', 'pods' ) |
| 96 | ), |
| 97 | ), |
| 98 | static::$type . '_format' => array( |
| 99 | 'label' => __( 'Date Format (predefined)', 'pods' ), |
| 100 | 'depends-on' => array( static::$type . '_type' => 'format' ), |
| 101 | 'default' => 'mdy', |
| 102 | 'type' => 'pick', |
| 103 | 'data' => array( |
| 104 | 'mdy' => date_i18n( 'm/d/Y' ), |
| 105 | 'mdy_dash' => date_i18n( 'm-d-Y' ), |
| 106 | 'mdy_dot' => date_i18n( 'm.d.Y' ), |
| 107 | 'ymd_slash' => date_i18n( 'Y/m/d' ), |
| 108 | 'ymd_dash' => date_i18n( 'Y-m-d' ), |
| 109 | 'ymd_dot' => date_i18n( 'Y.m.d' ), |
| 110 | 'fjy' => date_i18n( 'F j, Y' ), |
| 111 | 'fjsy' => date_i18n( 'F jS, Y' ), |
| 112 | 'c' => date_i18n( 'c' ), |
| 113 | ), |
| 114 | 'pick_format_single' => 'dropdown', |
| 115 | 'pick_show_select_text' => 0, |
| 116 | 'dependency' => true, |
| 117 | ), |
| 118 | static::$type . '_time_type' => array( |
| 119 | 'label' => __( 'Time Format Type', 'pods' ), |
| 120 | 'excludes-on' => array( static::$type . '_format' => 'c' ), |
| 121 | 'default' => '12', |
| 122 | // Backwards compatibility |
| 123 | 'type' => 'pick', |
| 124 | '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' ), |
| 125 | 'data' => array( |
| 126 | 'wp' => __( 'WordPress default', 'pods' ) . ': ' . date_i18n( get_option( 'time_format' ) ), |
| 127 | '12' => __( '12 hour', 'pods' ), |
| 128 | '24' => __( '24 hour', 'pods' ), |
| 129 | 'custom' => __( 'Custom', 'pods' ), |
| 130 | ), |
| 131 | 'pick_format_single' => 'dropdown', |
| 132 | 'pick_show_select_text' => 0, |
| 133 | 'dependency' => true, |
| 134 | ), |
| 135 | static::$type . '_time_format_custom' => array( |
| 136 | 'label' => __( 'Time Format for Display', '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' => sprintf( |
| 142 | '<a href="https://docs.pods.io/fields/date-time-fields/datetime/" target="_blank" rel="noopener noreferrer">%1$s</a>', |
| 143 | esc_html__( 'Date / Time field documentation', 'pods' ) |
| 144 | ), |
| 145 | ), |
| 146 | static::$type . '_time_format_custom_js' => array( |
| 147 | 'label' => __( 'Time Format for Input', 'pods' ), |
| 148 | 'depends-on' => array( static::$type . '_time_type' => 'custom' ), |
| 149 | 'excludes-on' => array( static::$type . '_format' => 'c' ), |
| 150 | 'default' => '', |
| 151 | 'type' => 'text', |
| 152 | 'help' => sprintf( |
| 153 | '<a href="https://docs.pods.io/fields/date-time-fields/datetime/" target="_blank" rel="noopener noreferrer">%1$s</a><br />%2$s', |
| 154 | esc_html__( 'Date / Time field documentation', 'pods' ), |
| 155 | esc_html__( 'Leave empty to auto-generate from PHP format.', 'pods' ) |
| 156 | ), |
| 157 | ), |
| 158 | static::$type . '_time_format' => array( |
| 159 | 'label' => __( 'Time Format (12 hour)', 'pods' ), |
| 160 | 'depends-on' => array( static::$type . '_time_type' => '12' ), |
| 161 | 'excludes-on' => array( static::$type . '_format' => 'c' ), |
| 162 | 'default' => 'h_mma', |
| 163 | 'type' => 'pick', |
| 164 | 'data' => array( |
| 165 | 'h_mm_A' => date_i18n( 'g:i A' ), |
| 166 | 'h_mm_ss_A' => date_i18n( 'g:i:s A' ), |
| 167 | 'hh_mm_A' => date_i18n( 'h:i A' ), |
| 168 | 'hh_mm_ss_A' => date_i18n( 'h:i:s A' ), |
| 169 | 'h_mma' => date_i18n( 'g:ia' ), |
| 170 | 'hh_mma' => date_i18n( 'h:ia' ), |
| 171 | 'h_mm' => date_i18n( 'g:i' ), |
| 172 | 'h_mm_ss' => date_i18n( 'g:i:s' ), |
| 173 | 'hh_mm' => date_i18n( 'h:i' ), |
| 174 | 'hh_mm_ss' => date_i18n( 'h:i:s' ), |
| 175 | ), |
| 176 | 'pick_format_single' => 'dropdown', |
| 177 | 'pick_show_select_text' => 0, |
| 178 | ), |
| 179 | static::$type . '_time_format_24' => array( |
| 180 | 'label' => __( 'Time Format (24 hour)', 'pods' ), |
| 181 | 'depends-on' => array( static::$type . '_time_type' => '24' ), |
| 182 | 'excludes-on' => array( static::$type . '_format' => 'c' ), |
| 183 | 'default' => 'hh_mm', |
| 184 | 'type' => 'pick', |
| 185 | 'data' => array( |
| 186 | 'hh_mm' => date_i18n( 'H:i' ), |
| 187 | 'hh_mm_ss' => date_i18n( 'H:i:s' ), |
| 188 | ), |
| 189 | 'pick_format_single' => 'dropdown', |
| 190 | 'pick_show_select_text' => 0, |
| 191 | ), |
| 192 | static::$type . '_year_range_custom' => array( |
| 193 | 'label' => __( 'Year Range', 'pods' ), |
| 194 | 'default' => '', |
| 195 | 'type' => 'text', |
| 196 | 'help' => sprintf( |
| 197 | '%1$s<br /><a href="https://docs.pods.io/fields/date-time-fields/datetime/" target="_blank" rel="noopener noreferrer">%2$s</a>', |
| 198 | sprintf( |
| 199 | esc_html__( 'Example: %1$s for specifying a hard coded year range or %2$s for the last and next 10 years.', 'pods' ), |
| 200 | '<code>2010:2030</code>', |
| 201 | '<code>-10:+10</code>' |
| 202 | ), |
| 203 | esc_html__( 'Date / Time field documentation', 'pods' ) |
| 204 | ), |
| 205 | ), |
| 206 | static::$type . '_allow_empty' => array( |
| 207 | 'label' => __( 'Allow empty value', 'pods' ), |
| 208 | 'default' => 1, |
| 209 | 'type' => 'boolean', |
| 210 | ), |
| 211 | static::$type . '_html5' => array( |
| 212 | 'label' => __( 'Enable HTML5 Input Field', 'pods' ), |
| 213 | 'default' => apply_filters( 'pods_form_ui_field_html5', 0, static::$type ), |
| 214 | 'type' => 'boolean', |
| 215 | ), |
| 216 | ); |
| 217 | |
| 218 | // Check if PHP DateTime::createFromFormat exists for additional supported formats |
| 219 | if ( method_exists( 'DateTime', 'createFromFormat' ) || apply_filters( 'pods_form_ui_field_datetime_custom_formatter', false ) ) { |
| 220 | $options[ static::$type . '_format' ]['data'] = array_merge( |
| 221 | $options[ static::$type . '_format' ]['data'], array( |
| 222 | 'dmy' => date_i18n( 'd/m/Y' ), |
| 223 | 'dmy_dash' => date_i18n( 'd-m-Y' ), |
| 224 | 'dmy_dot' => date_i18n( 'd.m.Y' ), |
| 225 | 'dMy' => date_i18n( 'd/M/Y' ), |
| 226 | 'dMy_dash' => date_i18n( 'd-M-Y' ), |
| 227 | ) |
| 228 | ); |
| 229 | } |
| 230 | |
| 231 | $options[ static::$type . '_format' ]['data'] = apply_filters( 'pods_form_ui_field_date_format_options', $options[ static::$type . '_format' ]['data'] ); |
| 232 | $options[ static::$type . '_format' ]['default'] = apply_filters( 'pods_form_ui_field_date_format_default', $options[ static::$type . '_format' ]['default'] ); |
| 233 | |
| 234 | $options[ static::$type . '_time_type' ]['default'] = apply_filters( 'pods_form_ui_field_time_format_type_default', $options[ static::$type . '_time_type' ]['default'] ); |
| 235 | $options[ static::$type . '_time_format' ]['data'] = apply_filters( 'pods_form_ui_field_time_format_options', $options[ static::$type . '_time_format' ]['data'] ); |
| 236 | $options[ static::$type . '_time_format' ]['default'] = apply_filters( 'pods_form_ui_field_time_format_default', $options[ static::$type . '_time_format' ]['default'] ); |
| 237 | $options[ static::$type . '_time_format_24' ]['data'] = apply_filters( 'pods_form_ui_field_time_format_24_options', $options[ static::$type . '_time_format_24' ]['data'] ); |
| 238 | $options[ static::$type . '_time_format_24' ]['default'] = apply_filters( 'pods_form_ui_field_time_format_24_default', $options[ static::$type . '_time_format_24' ]['default'] ); |
| 239 | |
| 240 | return $options; |
| 241 | } |
| 242 | |
| 243 | /** |
| 244 | * {@inheritdoc} |
| 245 | */ |
| 246 | public function schema( $options = null ) { |
| 247 | |
| 248 | $schema = 'DATETIME NOT NULL default "0000-00-00 00:00:00"'; |
| 249 | |
| 250 | return $schema; |
| 251 | } |
| 252 | |
| 253 | /** |
| 254 | * {@inheritdoc} |
| 255 | */ |
| 256 | public function is_empty( $value = null ) { |
| 257 | |
| 258 | $is_empty = false; |
| 259 | |
| 260 | $value = trim( $value ); |
| 261 | |
| 262 | if ( empty( $value ) || in_array( $value, array( '0000-00-00', '0000-00-00 00:00:00' ), true ) ) { |
| 263 | $is_empty = true; |
| 264 | } |
| 265 | |
| 266 | return $is_empty; |
| 267 | |
| 268 | } |
| 269 | |
| 270 | /** |
| 271 | * {@inheritdoc} |
| 272 | */ |
| 273 | public function display( $value = null, $name = null, $options = null, $pod = null, $id = null ) { |
| 274 | return $this->format_value_display( $value, $options, false ); |
| 275 | } |
| 276 | |
| 277 | /** |
| 278 | * {@inheritdoc} |
| 279 | */ |
| 280 | public function input( $name, $value = null, $options = null, $pod = null, $id = null ) { |
| 281 | |
| 282 | $options = ( is_array( $options ) || is_object( $options ) ) ? $options : (array) $options; |
| 283 | $form_field_type = PodsForm::$field_type; |
| 284 | |
| 285 | $value = $this->normalize_value_for_input( $value, $options ); |
| 286 | |
| 287 | // @todo Remove? Format Value (done in field template). |
| 288 | //$value = $this->format_value_display( $value, $options, true ); |
| 289 | |
| 290 | $field_type = static::$type; |
| 291 | |
| 292 | $is_read_only = (boolean) pods_v( 'read_only', $options, false ); |
| 293 | |
| 294 | if ( isset( $options['name'] ) && ! pods_permission( $options ) ) { |
| 295 | if ( $is_read_only ) { |
| 296 | $options['readonly'] = true; |
| 297 | |
| 298 | $field_type = 'text'; |
| 299 | } else { |
| 300 | return; |
| 301 | } |
| 302 | } elseif ( ! pods_has_permissions( $options ) && $is_read_only ) { |
| 303 | $options['readonly'] = true; |
| 304 | |
| 305 | $field_type = 'text'; |
| 306 | } |
| 307 | |
| 308 | if ( ! empty( $options['disable_dfv'] ) ) { |
| 309 | return pods_view( PODS_DIR . 'ui/fields/' . $field_type . '.php', compact( array_keys( get_defined_vars() ) ) ); |
| 310 | } |
| 311 | |
| 312 | // Convert the date/time formats to MomentJS. |
| 313 | $options = $this->prepare_options_for_moment_js( $options ); |
| 314 | |
| 315 | $type = pods_v( 'type', $options, static::$type ); |
| 316 | |
| 317 | $args = compact( array_keys( get_defined_vars() ) ); |
| 318 | $args = (object) $args; |
| 319 | |
| 320 | $this->render_input_script( $args ); |
| 321 | } |
| 322 | |
| 323 | /** |
| 324 | * {@inheritdoc} |
| 325 | */ |
| 326 | public function validate( $value, $name = null, $options = null, $fields = null, $pod = null, $id = null, $params = null ) { |
| 327 | $validate = parent::validate( $value, $name, $options, $fields, $pod, $id, $params ); |
| 328 | |
| 329 | $errors = array(); |
| 330 | |
| 331 | if ( is_array( $validate ) ) { |
| 332 | $errors = $validate; |
| 333 | } |
| 334 | |
| 335 | if ( ! $this->is_empty( $value ) ) { |
| 336 | |
| 337 | // Value should always be passed as storage format since 2.7.15. |
| 338 | // This was broken since 2.8.x and restored in 2.9.2 (#6389). |
| 339 | $formats = [ |
| 340 | static::$storage_format, |
| 341 | ]; |
| 342 | |
| 343 | if ( ! $this->is_storage_format( $value ) ) { |
| 344 | // Allow input values compatible with the input (JS) or display (PHP) formats. |
| 345 | $formats = [ |
| 346 | $this->format_display( $options, true ), |
| 347 | $this->format_display( $options, false ), |
| 348 | ]; |
| 349 | |
| 350 | $formats = array_unique( array_filter( $formats ) ); |
| 351 | } |
| 352 | |
| 353 | $check = $this->convert_date( $value, static::$storage_format, $formats, true ); |
| 354 | |
| 355 | if ( false === $check ) { |
| 356 | $label = pods_v( 'label', $options, ucwords( str_replace( '_', ' ', $name ) ) ); |
| 357 | |
| 358 | // Translators: %1$s is the field label and %2$s is the input value. |
| 359 | $errors[] = sprintf( esc_html__( '%1$s was not provided in a recognizable format: "%2$s"', 'pods' ), $label, $value ); |
| 360 | } |
| 361 | } |
| 362 | |
| 363 | if ( ! empty( $errors ) ) { |
| 364 | return $errors; |
| 365 | } |
| 366 | |
| 367 | return $validate; |
| 368 | } |
| 369 | |
| 370 | /** |
| 371 | * {@inheritdoc} |
| 372 | */ |
| 373 | public function pre_save( $value, $id = null, $name = null, $options = null, $fields = null, $pod = null, $params = null ) { |
| 374 | |
| 375 | // Value should always be passed as storage format since 2.7.15. |
| 376 | $format = static::$storage_format; |
| 377 | |
| 378 | if ( ! $this->is_empty( $value ) ) { |
| 379 | if ( ! $this->is_storage_format( $value ) ) { |
| 380 | // Allow input values compatible with the display format. |
| 381 | $format = $this->format_display( $options, false ); |
| 382 | } |
| 383 | $value = $this->convert_date( $value, static::$storage_format, $format ); |
| 384 | } elseif ( pods_v( static::$type . '_allow_empty', $options, 1 ) ) { |
| 385 | $value = static::$empty_value; |
| 386 | } else { |
| 387 | $value = date_i18n( static::$storage_format ); |
| 388 | } |
| 389 | |
| 390 | return $value; |
| 391 | } |
| 392 | |
| 393 | /** |
| 394 | * {@inheritdoc} |
| 395 | */ |
| 396 | public function ui( $id, $value, $name = null, $options = null, $fields = null, $pod = null ) { |
| 397 | |
| 398 | $value = $this->display( $value, $name, $options, $pod, $id ); |
| 399 | |
| 400 | if ( $this->is_empty( $value ) && pods_v( static::$type . '_allow_empty', $options, 1 ) ) { |
| 401 | $value = false; |
| 402 | } |
| 403 | |
| 404 | return $value; |
| 405 | } |
| 406 | |
| 407 | /** |
| 408 | * Convert value to the correct format for display. |
| 409 | * |
| 410 | * @param string $value Field value. |
| 411 | * @param array $options Field options. |
| 412 | * @param bool $js Return formatted from jQuery UI format? (only for custom formats). |
| 413 | * |
| 414 | * @return string |
| 415 | * @since 2.7.0 |
| 416 | */ |
| 417 | public function format_value_display( $value, $options, $js = false ) { |
| 418 | |
| 419 | $format = $this->format_display( $options, $js ); |
| 420 | |
| 421 | if ( ! $this->is_empty( $value ) ) { |
| 422 | // Try default storage format. |
| 423 | $date = $this->createFromFormat( static::$storage_format, (string) $value ); |
| 424 | |
| 425 | // Convert to timestamp. |
| 426 | if ( $date instanceof DateTime ) { |
| 427 | $timestamp = $date->getTimestamp(); |
| 428 | } else { |
| 429 | // Try field format. |
| 430 | $date_local = $this->createFromFormat( $format, (string) $value ); |
| 431 | |
| 432 | if ( $date_local instanceof DateTime ) { |
| 433 | $timestamp = $date_local->getTimestamp(); |
| 434 | } else { |
| 435 | // Fallback. |
| 436 | $timestamp = strtotime( (string) $value ); |
| 437 | } |
| 438 | } |
| 439 | |
| 440 | $value = date_i18n( $format, $timestamp ); |
| 441 | } elseif ( ! pods_v( static::$type . '_allow_empty', $options, 1 ) ) { |
| 442 | $value = date_i18n( $format ); |
| 443 | } else { |
| 444 | $value = ''; |
| 445 | } |
| 446 | |
| 447 | return $value; |
| 448 | } |
| 449 | |
| 450 | /** |
| 451 | * Build date and/or time display format string based on options |
| 452 | * |
| 453 | * @since 2.7.13 |
| 454 | * |
| 455 | * @param array $options Field options. |
| 456 | * @param bool $js Whether to return format for jQuery UI. |
| 457 | * |
| 458 | * @return string |
| 459 | */ |
| 460 | public function format_display( $options, $js = false ) { |
| 461 | |
| 462 | if ( 'custom' === pods_v( static::$type . '_type', $options, 'format' ) ) { |
| 463 | if ( $js ) { |
| 464 | |
| 465 | // Gets format strings in jQuery UI format. |
| 466 | $date = $this->format_date( $options, $js ); |
| 467 | $time = $this->format_time( $options, $js ); |
| 468 | |
| 469 | // Convert them to PHP date format. |
| 470 | $date = $this->convert_format( $date, array( 'source' => 'jquery_ui', 'type' => 'date' ) ); |
| 471 | $time = $this->convert_format( $time, array( 'source' => 'jquery_ui', 'type' => 'time' ) ); |
| 472 | |
| 473 | return $date . ' ' . $time; |
| 474 | |
| 475 | } else { |
| 476 | $format = $this->format_datetime( $options, $js ); |
| 477 | } |
| 478 | } else { |
| 479 | $js = false; |
| 480 | $format = $this->format_datetime( $options, $js ); |
| 481 | } |
| 482 | |
| 483 | return $format; |
| 484 | } |
| 485 | |
| 486 | /** |
| 487 | * Build date and/or time format string based on options |
| 488 | * |
| 489 | * @since 2.7.0 |
| 490 | * |
| 491 | * @param array $options Field options. |
| 492 | * @param bool $js Whether to return format for jQuery UI. |
| 493 | * |
| 494 | * @return string |
| 495 | */ |
| 496 | public function format_datetime( $options, $js = false ) { |
| 497 | |
| 498 | $format = $this->format_date( $options, $js ); |
| 499 | |
| 500 | $type = pods_v( static::$type . '_type', $options, 'format' ); |
| 501 | |
| 502 | if ( 'format' !== $type || 'c' !== pods_v( static::$type . '_format', $options, '' ) ) { |
| 503 | $format .= ' ' . $this->format_time( $options, $js ); |
| 504 | } |
| 505 | |
| 506 | return $format; |
| 507 | } |
| 508 | |
| 509 | /** |
| 510 | * Build date format string based on options |
| 511 | * |
| 512 | * @since 2.7.0 |
| 513 | * |
| 514 | * @param array $options Field options. |
| 515 | * @param bool $js Whether to return format for jQuery UI. |
| 516 | * |
| 517 | * @return string |
| 518 | */ |
| 519 | public function format_date( $options, $js = false ) { |
| 520 | |
| 521 | switch ( (string) pods_v( static::$type . '_type', $options, 'format', true ) ) { |
| 522 | case 'wp': |
| 523 | $format = get_option( 'date_format' ); |
| 524 | |
| 525 | if ( $js ) { |
| 526 | $format = $this->convert_format( $format, array( 'source' => 'php', 'type' => 'date' ) ); |
| 527 | } |
| 528 | |
| 529 | break; |
| 530 | case 'custom': |
| 531 | if ( ! $js ) { |
| 532 | $format = pods_v( static::$type . '_format_custom', $options, '' ); |
| 533 | } else { |
| 534 | $format = pods_v( static::$type . '_format_custom_js', $options, '' ); |
| 535 | |
| 536 | if ( empty( $format ) ) { |
| 537 | $format = pods_v( static::$type . '_format_custom', $options, '' ); |
| 538 | |
| 539 | if ( $js ) { |
| 540 | $format = $this->convert_format( $format, array( 'source' => 'php', 'type' => 'date' ) ); |
| 541 | } |
| 542 | } |
| 543 | } |
| 544 | |
| 545 | break; |
| 546 | default: |
| 547 | $date_format = $this->get_date_formats( $js ); |
| 548 | |
| 549 | $format = $date_format[ pods_v( static::$type . '_format', $options, 'ymd_dash', true ) ]; |
| 550 | |
| 551 | break; |
| 552 | }//end switch |
| 553 | |
| 554 | return $format; |
| 555 | } |
| 556 | |
| 557 | /** |
| 558 | * Build time format string based on options |
| 559 | * |
| 560 | * @since 2.7.0 |
| 561 | * |
| 562 | * @param array $options Field options. |
| 563 | * @param bool $js Whether to return format for jQuery UI. |
| 564 | * |
| 565 | * @return string |
| 566 | */ |
| 567 | public function format_time( $options, $js = false ) { |
| 568 | |
| 569 | switch ( (string) pods_v( static::$type . '_time_type', $options, '12', true ) ) { |
| 570 | case '12': |
| 571 | $time_format = $this->get_time_formats( $js ); |
| 572 | |
| 573 | $format = $time_format[ pods_v( static::$type . '_time_format', $options, 'hh_mm', true ) ]; |
| 574 | |
| 575 | break; |
| 576 | case '24': |
| 577 | $time_format_24 = $this->get_time_formats_24( $js ); |
| 578 | |
| 579 | $format = $time_format_24[ pods_v( static::$type . '_time_format_24', $options, 'hh_mm', true ) ]; |
| 580 | |
| 581 | break; |
| 582 | case 'custom': |
| 583 | if ( ! $js ) { |
| 584 | $format = pods_v( static::$type . '_time_format_custom', $options, '' ); |
| 585 | } else { |
| 586 | $format = pods_v( static::$type . '_time_format_custom_js', $options, '' ); |
| 587 | $js = false; // Already in JS format. |
| 588 | |
| 589 | if ( empty( $format ) ) { |
| 590 | $format = pods_v( static::$type . '_time_format_custom', $options, '' ); |
| 591 | $js = true; |
| 592 | } |
| 593 | } |
| 594 | |
| 595 | break; |
| 596 | default: |
| 597 | $format = get_option( 'time_format' ); |
| 598 | |
| 599 | break; |
| 600 | }//end switch |
| 601 | |
| 602 | return $format; |
| 603 | } |
| 604 | |
| 605 | /** |
| 606 | * Get the date formats. |
| 607 | * |
| 608 | * @since 2.7.0 |
| 609 | * |
| 610 | * @param bool $js Whether to return format for jQuery UI. |
| 611 | * |
| 612 | * @return array |
| 613 | */ |
| 614 | public function get_date_formats( $js = false ) { |
| 615 | |
| 616 | $date_format = array( |
| 617 | 'mdy' => 'm/d/Y', |
| 618 | 'mdy_dash' => 'm-d-Y', |
| 619 | 'mdy_dot' => 'm.d.Y', |
| 620 | 'dmy' => 'd/m/Y', |
| 621 | 'dmy_dash' => 'd-m-Y', |
| 622 | 'dmy_dot' => 'd.m.Y', |
| 623 | 'ymd_slash' => 'Y/m/d', |
| 624 | 'ymd_dash' => 'Y-m-d', |
| 625 | 'ymd_dot' => 'Y.m.d', |
| 626 | 'dMy' => 'd/M/Y', |
| 627 | 'dMy_dash' => 'd-M-Y', |
| 628 | 'fjy' => 'F j, Y', |
| 629 | 'fjsy' => 'F jS, Y', |
| 630 | 'y' => 'Y', |
| 631 | 'c' => 'c', |
| 632 | ); |
| 633 | |
| 634 | $filter = 'pods_form_ui_field_date_formats'; |
| 635 | |
| 636 | if ( $js ) { |
| 637 | foreach ( $date_format as $key => $value ) { |
| 638 | $date_format[ $key ] = $this->convert_format( $value, array( 'type' => 'date' ) ); |
| 639 | } |
| 640 | |
| 641 | $filter = 'pods_form_ui_field_date_js_formats'; |
| 642 | } |
| 643 | |
| 644 | return apply_filters( $filter, $date_format ); |
| 645 | } |
| 646 | |
| 647 | /** |
| 648 | * Get the time formats. |
| 649 | * |
| 650 | * @since 2.7.0 |
| 651 | * |
| 652 | * @param bool $js Whether to return format for jQuery UI. |
| 653 | * |
| 654 | * @return array |
| 655 | */ |
| 656 | public function get_time_formats( $js = false ) { |
| 657 | |
| 658 | $time_format = array( |
| 659 | 'h_mm_A' => 'g:i A', |
| 660 | 'h_mm_ss_A' => 'g:i:s A', |
| 661 | 'hh_mm_A' => 'h:i A', |
| 662 | 'hh_mm_ss_A' => 'h:i:s A', |
| 663 | 'h_mma' => 'g:ia', |
| 664 | 'hh_mma' => 'h:ia', |
| 665 | 'h_mm' => 'g:i', |
| 666 | 'h_mm_ss' => 'g:i:s', |
| 667 | 'hh_mm' => 'h:i', |
| 668 | 'hh_mm_ss' => 'h:i:s', |
| 669 | ); |
| 670 | |
| 671 | $filter = 'pods_form_ui_field_time_formats'; |
| 672 | |
| 673 | if ( $js ) { |
| 674 | foreach ( $time_format as $key => $value ) { |
| 675 | $time_format[ $key ] = $this->convert_format( $value, array( 'type' => 'time' ) ); |
| 676 | } |
| 677 | |
| 678 | $filter = 'pods_form_ui_field_time_js_formats'; |
| 679 | } |
| 680 | |
| 681 | return apply_filters( $filter, $time_format ); |
| 682 | } |
| 683 | |
| 684 | /** |
| 685 | * Get the time formats. |
| 686 | * |
| 687 | * @since 2.7.0 |
| 688 | * |
| 689 | * @param bool $js Whether to return format for jQuery UI. |
| 690 | * |
| 691 | * @return array |
| 692 | */ |
| 693 | public function get_time_formats_24( $js = false ) { |
| 694 | |
| 695 | $time_format_24 = array( |
| 696 | 'hh_mm' => 'H:i', |
| 697 | 'hh_mm_ss' => 'H:i:s', |
| 698 | ); |
| 699 | |
| 700 | $filter = 'pods_form_ui_field_time_formats_24'; |
| 701 | |
| 702 | if ( $js ) { |
| 703 | foreach ( $time_format_24 as $key => $value ) { |
| 704 | $time_format_24[ $key ] = $this->convert_format( $value, array( 'type' => 'time' ) ); |
| 705 | } |
| 706 | |
| 707 | $filter = 'pods_form_ui_field_time_js_formats_24'; |
| 708 | } |
| 709 | |
| 710 | return apply_filters( $filter, $time_format_24 ); |
| 711 | } |
| 712 | |
| 713 | /** |
| 714 | * PHP backwards compatibility for createFromFormat. |
| 715 | * |
| 716 | * @param string $format Format string. |
| 717 | * @param string $date Defaults to time() if empty. |
| 718 | * @param boolean $return_timestamp Whether to return the strtotime() or createFromFormat result or not. |
| 719 | * |
| 720 | * @return DateTime|null|int|false |
| 721 | */ |
| 722 | public function createFromFormat( $format, $date, $return_timestamp = false ) { |
| 723 | |
| 724 | $datetime = null; |
| 725 | |
| 726 | try { |
| 727 | if ( method_exists( 'DateTime', 'createFromFormat' ) ) { |
| 728 | |
| 729 | $datetime = DateTime::createFromFormat( $format, (string) $date ); |
| 730 | |
| 731 | if ( false === $datetime ) { |
| 732 | $datetime = DateTime::createFromFormat( static::$storage_format, (string) $date ); |
| 733 | } |
| 734 | |
| 735 | if ( false !== $datetime && $return_timestamp ) { |
| 736 | return $datetime; |
| 737 | } |
| 738 | |
| 739 | }//end if |
| 740 | |
| 741 | if ( in_array( $datetime, array( null, false ), true ) ) { |
| 742 | if ( empty( $date ) ) { |
| 743 | $timestamp = time(); |
| 744 | } else { |
| 745 | $timestamp = strtotime( (string) $date ); |
| 746 | |
| 747 | if ( $return_timestamp ) { |
| 748 | return $timestamp; |
| 749 | } |
| 750 | } |
| 751 | |
| 752 | if ( $timestamp ) { |
| 753 | $datetime = new DateTime( date_i18n( static::$storage_format, $timestamp ) ); |
| 754 | } |
| 755 | } |
| 756 | } catch ( Exception $exception ) { |
| 757 | // There is no saving this time value, it's an exception to the rule. |
| 758 | pods_debug_log( $exception ); |
| 759 | } |
| 760 | |
| 761 | return apply_filters( 'pods_form_ui_field_datetime_formatter', $datetime, $format, $date ); |
| 762 | } |
| 763 | |
| 764 | /** |
| 765 | * Check if a value is compatible with the storage format. |
| 766 | * |
| 767 | * Valid: |
| 768 | * - 0000-00-00 00:00:00 |
| 769 | * - 0000-00-00 00:00 |
| 770 | * - 0000-00-00 |
| 771 | * - 0000-00 |
| 772 | * - etc. |
| 773 | * |
| 774 | * @param string $value The date value. |
| 775 | * @return bool |
| 776 | */ |
| 777 | public function is_storage_format( $value ) { |
| 778 | $value_parts = str_split( $value ); |
| 779 | $format_parts = str_split( gmdate( static::$storage_format ) ); |
| 780 | |
| 781 | $valid = true; |
| 782 | foreach ( $value_parts as $i => $part ) { |
| 783 | if ( isset( $format_parts[ $i ] ) ) { |
| 784 | if ( is_numeric( $format_parts[ $i ] ) ) { |
| 785 | if ( ! is_numeric( $part ) ) { |
| 786 | $valid = false; |
| 787 | break; |
| 788 | } |
| 789 | } elseif ( $format_parts[ $i ] !== $part ) { |
| 790 | $valid = false; |
| 791 | break; |
| 792 | } |
| 793 | } |
| 794 | } |
| 795 | return $valid; |
| 796 | } |
| 797 | |
| 798 | /** |
| 799 | * Convert a date from one format to another. |
| 800 | * |
| 801 | * @param string $value Field value. |
| 802 | * @param string $new_format New format string. |
| 803 | * @param string|array $original_format Original format string(s) (if known). |
| 804 | * @param boolean $return_timestamp Whether to return the strtotime() or createFromFormat result or not. |
| 805 | * |
| 806 | * @return string|int|boolean|DateTime |
| 807 | */ |
| 808 | public function convert_date( $value, $new_format, $original_format = '', $return_timestamp = false ) { |
| 809 | |
| 810 | if ( empty( $original_format ) ) { |
| 811 | $original_format = static::$storage_format; |
| 812 | } |
| 813 | |
| 814 | if ( is_array( $original_format ) ) { |
| 815 | foreach ( $original_format as $original_format_option ) { |
| 816 | $value = $this->convert_date( $value, $new_format, $original_format_option, $return_timestamp ); |
| 817 | |
| 818 | if ( false !== $value ) { |
| 819 | return $value; |
| 820 | } |
| 821 | } |
| 822 | |
| 823 | return false; |
| 824 | } |
| 825 | |
| 826 | $date = ''; |
| 827 | |
| 828 | if ( ! $this->is_empty( $value ) ) { |
| 829 | $date = $this->createFromFormat( $original_format, (string) $value, $return_timestamp ); |
| 830 | |
| 831 | if ( $date instanceof DateTime ) { |
| 832 | $value = $date->format( $new_format ); |
| 833 | } elseif ( false !== $date ) { |
| 834 | $date = strtotime( (string) $value ); |
| 835 | |
| 836 | $value = date_i18n( $new_format, $date ); |
| 837 | } |
| 838 | } else { |
| 839 | $value = date_i18n( $new_format ); |
| 840 | } |
| 841 | |
| 842 | // Return timestamp conversion result instead |
| 843 | if ( $return_timestamp ) { |
| 844 | return $date; |
| 845 | } |
| 846 | |
| 847 | return $value; |
| 848 | } |
| 849 | |
| 850 | /** |
| 851 | * Matches each symbol of PHP date format standard with jQuery equivalent codeword. |
| 852 | * |
| 853 | * @link http://stackoverflow.com/questions/16702398/convert-a-php-date-format-to-a-jqueryui-datepicker-date-format |
| 854 | * @link https://api.jqueryui.com/datepicker/ |
| 855 | * @link http://trentrichardson.com/examples/timepicker/ |
| 856 | * |
| 857 | * @since 2.7.0 |
| 858 | * |
| 859 | * @param string $source_format Source format string. |
| 860 | * @param array $args Format arguments. |
| 861 | * |
| 862 | * @return string |
| 863 | */ |
| 864 | public function convert_format( $source_format, $args = array() ) { |
| 865 | |
| 866 | // @todo Improve source/target logic. |
| 867 | $args = array_merge( |
| 868 | array( |
| 869 | 'source' => 'php', |
| 870 | 'type' => 'date', |
| 871 | // 'jquery_ui' for reverse. |
| 872 | ), $args |
| 873 | ); |
| 874 | |
| 875 | // Keep keys and values sorted by string length. |
| 876 | if ( 'time' === $args['type'] || 'time' === static::$type ) { |
| 877 | |
| 878 | $symbols = array( |
| 879 | // AM/PM. |
| 880 | 'a' => 'tt', |
| 881 | 'A' => 'TT', |
| 882 | // Swatch internet time (not supported). |
| 883 | 'B' => '', |
| 884 | // Hour. |
| 885 | 'h' => 'hh', |
| 886 | 'H' => 'HH', |
| 887 | 'g' => 'h', |
| 888 | 'G' => 'H', |
| 889 | // Minute. |
| 890 | 'i' => 'mm', |
| 891 | // Second. |
| 892 | 's' => 'ss', |
| 893 | // Microsecond. |
| 894 | 'u' => 'c', |
| 895 | // Timezone. |
| 896 | 'O' => 'z', |
| 897 | 'P' => 'Z', |
| 898 | ); |
| 899 | |
| 900 | if ( version_compare( PHP_VERSION, '7.0.0' ) >= 0 ) { |
| 901 | // Millisecond. |
| 902 | $symbols['v'] = 'l'; |
| 903 | } |
| 904 | |
| 905 | } else { |
| 906 | |
| 907 | $symbols = array( |
| 908 | // Day. |
| 909 | 'd' => 'dd', |
| 910 | 'l' => 'DD', |
| 911 | 'D' => 'D', |
| 912 | 'j' => 'd', |
| 913 | 'N' => '', |
| 914 | 'S' => '', |
| 915 | 'w' => '', |
| 916 | 'z' => 'o', |
| 917 | // Week. |
| 918 | 'W' => '', |
| 919 | // Month. |
| 920 | 'F' => 'MM', |
| 921 | 'm' => 'mm', |
| 922 | 'M' => 'M', |
| 923 | 'n' => 'm', |
| 924 | 't' => '', |
| 925 | // Year. |
| 926 | 'L' => '', |
| 927 | 'o' => '', |
| 928 | 'Y' => 'yy', |
| 929 | 'y' => 'y', |
| 930 | ); |
| 931 | } |
| 932 | |
| 933 | if ( 'jquery_ui' === $args['source'] ) { |
| 934 | // Remove empty values. |
| 935 | $symbols = array_filter( $symbols ); |
| 936 | $symbols = array_flip( $symbols ); |
| 937 | } |
| 938 | |
| 939 | $new_format = ''; |
| 940 | $escaping = false; |
| 941 | |
| 942 | $source_format_length = strlen( $source_format ); |
| 943 | |
| 944 | for ( $i = 0; $i < $source_format_length; $i ++ ) { |
| 945 | $char = $source_format[ $i ]; |
| 946 | |
| 947 | // PHP date format escaping character |
| 948 | // @todo Do we want to support non-format characters? |
| 949 | if ( '\\' === $char ) { |
| 950 | $i ++; |
| 951 | |
| 952 | if ( $escaping ) { |
| 953 | $new_format .= $source_format[ $i ]; |
| 954 | } else { |
| 955 | $new_format .= '\'' . $source_format[ $i ]; |
| 956 | } |
| 957 | |
| 958 | $escaping = true; |
| 959 | } else { |
| 960 | if ( $escaping ) { |
| 961 | $new_format .= "'"; |
| 962 | $escaping = false; |
| 963 | } |
| 964 | |
| 965 | $symbol_key = false; |
| 966 | |
| 967 | if ( isset( $source_format[ $i + 1 ] ) ) { |
| 968 | $symbol_key = $char . $source_format[ $i + 1 ]; |
| 969 | } |
| 970 | |
| 971 | // Support 2 characters. |
| 972 | if ( $symbol_key && isset( $symbols[ $symbol_key ] ) ) { |
| 973 | $new_format .= $symbols[ $symbol_key ]; |
| 974 | |
| 975 | $i ++; |
| 976 | } elseif ( isset( $symbols[ $char ] ) ) { |
| 977 | $new_format .= $symbols[ $char ]; |
| 978 | } else { |
| 979 | $new_format .= $char; |
| 980 | } |
| 981 | }//end if |
| 982 | }//end for |
| 983 | |
| 984 | return $new_format; |
| 985 | } |
| 986 | |
| 987 | /** |
| 988 | * Prepare the date/datetime/time field object or options for MomentJS formatting. |
| 989 | * |
| 990 | * @since 2.8.11 |
| 991 | * |
| 992 | * @param array|Field $options The field object or options. |
| 993 | * |
| 994 | * @return array|Field The field object or options. |
| 995 | */ |
| 996 | public function prepare_options_for_moment_js( $options ) { |
| 997 | // Handle time formats for datetime. |
| 998 | if ( 'datetime' === static::$type ) { |
| 999 | $date_format = $this->get_format_from_options_for_type( $options, static::$type, '', true ); |
| 1000 | $time_format = $this->get_format_from_options_for_type( $options, static::$type, '_time', true ); |
| 1001 | |
| 1002 | $date_format_moment_js = $this->convert_format_to_moment_js( $date_format['format'], [ |
| 1003 | 'source' => $date_format['is_js'] ? 'jquery_ui' : 'php', |
| 1004 | 'type' => 'date', |
| 1005 | ] ); |
| 1006 | $time_format_moment_js = $this->convert_format_to_moment_js( $time_format['format'], [ |
| 1007 | 'source' => $time_format['is_js'] ? 'jquery_ui' : 'php', |
| 1008 | 'type' => 'time', |
| 1009 | ] ); |
| 1010 | |
| 1011 | $options[ static::$type . '_date_format_moment_js' ] = $date_format_moment_js; |
| 1012 | $options[ static::$type . '_time_format_moment_js' ] = $time_format_moment_js; |
| 1013 | } elseif ( 'date' === static::$type ) { |
| 1014 | $date_format = $this->get_format_from_options_for_type( $options, static::$type, '', true ); |
| 1015 | |
| 1016 | $date_format_moment_js = $this->convert_format_to_moment_js( $date_format['format'], [ |
| 1017 | 'source' => $date_format['is_js'] ? 'jquery_ui' : 'php', |
| 1018 | 'type' => 'date', |
| 1019 | ] ); |
| 1020 | |
| 1021 | $options[ static::$type . '_format_moment_js' ] = $date_format_moment_js; |
| 1022 | } elseif ( 'time' === static::$type ) { |
| 1023 | $time_format = $this->get_format_from_options_for_type( $options, static::$type, '', true ); |
| 1024 | |
| 1025 | $time_format_moment_js = $this->convert_format_to_moment_js( $time_format['format'], [ |
| 1026 | 'source' => $time_format['is_js'] ? 'jquery_ui' : 'php', |
| 1027 | 'type' => 'time', |
| 1028 | ] ); |
| 1029 | |
| 1030 | $options[ static::$type . '_format_moment_js' ] = $time_format_moment_js; |
| 1031 | } |
| 1032 | |
| 1033 | return $options; |
| 1034 | } |
| 1035 | |
| 1036 | /** |
| 1037 | * Get the format from the options for a specific type (date/datetime/time). |
| 1038 | * |
| 1039 | * @since 2.8.11 |
| 1040 | * |
| 1041 | * @param array|Field $options The field object or options. |
| 1042 | * @param string $type The specific field type. |
| 1043 | * @param string $prefix The prefix to use on the format options if needed (like "_time" in datetime_time_format). |
| 1044 | * @param bool $js Whether we want to get the format in the JS context. |
| 1045 | * |
| 1046 | * @return array The format information including if found/using the JS context option and the format. |
| 1047 | */ |
| 1048 | public function get_format_from_options_for_type( $options, $type, $prefix = '', $js = false ) { |
| 1049 | $format_type = pods_v( $type . $prefix . '_type', $options ); |
| 1050 | |
| 1051 | $is_date_format = ( |
| 1052 | 'date' === $type |
| 1053 | || ( |
| 1054 | 'datetime' === $type |
| 1055 | && '' === $prefix |
| 1056 | ) |
| 1057 | ); |
| 1058 | |
| 1059 | $is_24_hour = '24' === $format_type; |
| 1060 | |
| 1061 | if ( '12' === $format_type || $is_24_hour ) { |
| 1062 | $format_type = 'format'; |
| 1063 | } |
| 1064 | |
| 1065 | // Get the format from the field setting. |
| 1066 | if ( 'format' === $format_type ) { |
| 1067 | if ( $is_date_format ) { |
| 1068 | // Get the format for date. |
| 1069 | $formats = $this->get_date_formats(); |
| 1070 | } elseif ( $is_24_hour ) { |
| 1071 | // Get the format for time (24-hour). |
| 1072 | $formats = $this->get_time_formats_24(); |
| 1073 | } else { |
| 1074 | // Get the format for time (12-hour). |
| 1075 | $formats = $this->get_time_formats(); |
| 1076 | } |
| 1077 | |
| 1078 | $format = pods_v( $type . $prefix . '_format', $options ); |
| 1079 | |
| 1080 | // Get 24-hour format. |
| 1081 | if ( $is_24_hour ) { |
| 1082 | $format = pods_v( $type . $prefix . '_format_24', $options ); |
| 1083 | } |
| 1084 | |
| 1085 | // Check if format is registered. |
| 1086 | if ( ! empty( $formats[ $format ] ) ) { |
| 1087 | return [ |
| 1088 | 'is_js' => false, |
| 1089 | 'format' => $formats[ $format ], |
| 1090 | ]; |
| 1091 | } |
| 1092 | } |
| 1093 | |
| 1094 | // Get the custom format from the field setting. |
| 1095 | if ( 'custom' === $format_type ) { |
| 1096 | $format_custom = pods_v( $type . $prefix . '_format_custom', $options ); |
| 1097 | |
| 1098 | $is_js = false; |
| 1099 | |
| 1100 | if ( $js ) { |
| 1101 | $format_custom_js = pods_v( $type . $prefix . '_format_custom_js', $options ); |
| 1102 | |
| 1103 | if ( ! empty( $format_custom_js ) ) { |
| 1104 | $is_js = true; |
| 1105 | |
| 1106 | $format_custom = $format_custom_js; |
| 1107 | } |
| 1108 | } |
| 1109 | |
| 1110 | // Check if there's a custom format. |
| 1111 | if ( ! empty( $format_custom ) ) { |
| 1112 | return [ |
| 1113 | 'is_js' => $is_js, |
| 1114 | 'format' => $format_custom, |
| 1115 | ]; |
| 1116 | } |
| 1117 | } |
| 1118 | |
| 1119 | // Fallback to wp format. |
| 1120 | $options[ $type . $prefix . '_type' ] = 'wp'; |
| 1121 | |
| 1122 | // Maybe get the date format from WordPress. |
| 1123 | if ( $is_date_format ) { |
| 1124 | return [ |
| 1125 | 'is_js' => false, |
| 1126 | 'format' => get_option( 'date_format' ), |
| 1127 | ]; |
| 1128 | } |
| 1129 | |
| 1130 | // Get the time format from WordPress. |
| 1131 | return [ |
| 1132 | 'is_js' => false, |
| 1133 | 'format' => get_option( 'time_format' ), |
| 1134 | ]; |
| 1135 | } |
| 1136 | |
| 1137 | /** |
| 1138 | * Convert the source format to MomentJS format for PHP / jQuery UI formats. |
| 1139 | * |
| 1140 | * @since 2.8.11 |
| 1141 | * |
| 1142 | * @param string|mixed $source_format The source format. |
| 1143 | * @param array $args The list of format arguments including source (php/jquery_ui) and type (date/time). |
| 1144 | * |
| 1145 | * @return string|mixed The converted MomentJS format. |
| 1146 | */ |
| 1147 | public function convert_format_to_moment_js( $source_format, $args = array() ) { |
| 1148 | if ( ! is_string( $source_format ) || '' === trim( $source_format ) ) { |
| 1149 | return $source_format; |
| 1150 | } |
| 1151 | |
| 1152 | $defaults = [ |
| 1153 | 'source' => 'php', // php or jquery_ui. |
| 1154 | 'type' => 'date', // date or time. |
| 1155 | ]; |
| 1156 | |
| 1157 | $args = array_merge( $defaults, $args ); |
| 1158 | |
| 1159 | // For PHP symbols, see https://www.php.net/manual/en/datetime.format.php |
| 1160 | // For Moment.js symbols, see https://momentjs.com/docs/#/displaying/format/ |
| 1161 | $php_replacements = [ |
| 1162 | 'A' => 'A', // for the sake of escaping below |
| 1163 | 'a' => 'a', // for the sake of escaping below |
| 1164 | 'B' => '', // Swatch internet time (.beats), no equivalent |
| 1165 | 'c' => 'YYYY-MM-DD[T]HH:mm:ssZ', // ISO 8601 |
| 1166 | 'D' => 'ddd', |
| 1167 | 'd' => 'DD', |
| 1168 | 'e' => 'zz', // deprecated since version 1.6.0 of moment.js |
| 1169 | 'F' => 'MMMM', |
| 1170 | 'G' => 'H', |
| 1171 | 'g' => 'h', |
| 1172 | 'H' => 'HH', |
| 1173 | 'h' => 'hh', |
| 1174 | 'I' => '', // Daylight Saving Time? => moment().isDST(); |
| 1175 | 'i' => 'mm', |
| 1176 | 'j' => 'D', |
| 1177 | 'L' => '', // Leap year? => moment().isLeapYear(); |
| 1178 | 'l' => 'dddd', |
| 1179 | 'M' => 'MMM', |
| 1180 | 'm' => 'MM', |
| 1181 | 'N' => 'E', |
| 1182 | 'n' => 'M', |
| 1183 | 'O' => 'ZZ', |
| 1184 | 'o' => 'YYYY', |
| 1185 | 'P' => 'Z', |
| 1186 | 'r' => 'ddd, DD MMM YYYY HH:mm:ss ZZ', // RFC 2822 |
| 1187 | 'S' => 'o', |
| 1188 | 's' => 'ss', |
| 1189 | 'T' => 'z', // deprecated since version 1.6.0 of moment.js |
| 1190 | 't' => '', // days in the month => moment().daysInMonth(); |
| 1191 | 'U' => 'X', |
| 1192 | 'u' => 'SSSSSS', // microseconds |
| 1193 | 'v' => 'SSS', // milliseconds (from PHP 7.0.0) |
| 1194 | 'W' => 'W', // for the sake of escaping below |
| 1195 | 'w' => 'e', |
| 1196 | 'Y' => 'YYYY', |
| 1197 | 'y' => 'YY', |
| 1198 | 'Z' => '', // time zone offset in minutes => moment().zone(); |
| 1199 | 'z' => 'DDD', |
| 1200 | ]; |
| 1201 | |
| 1202 | // For jQuery symbols, see https://api.jqueryui.com/datepicker/#utility-formatDate |
| 1203 | // For Moment.js symbols, see https://momentjs.com/docs/#/displaying/format/ |
| 1204 | $jquery_ui_date_replacements = [ |
| 1205 | 'dd' => 'DD', // day of month (two digit) |
| 1206 | 'd' => 'D', // day of month (no leading zero) |
| 1207 | 'oo' => 'DDDD', // day of the year (three digit) |
| 1208 | 'o' => 'DDD', // day of the year (no leading zeros) |
| 1209 | 'DD' => 'dddd', // day name long |
| 1210 | 'D' => 'dd', // day name short |
| 1211 | 'mm' => 'MM', // month of year (two digit) |
| 1212 | 'm' => 'M', // month of year (no leading zero) |
| 1213 | 'MM' => 'MMMM', // month name long |
| 1214 | 'M' => 'MMM', // month name short |
| 1215 | 'yy' => 'YYYY', // year (four digit) |
| 1216 | 'y' => 'YY', // year (two digit) |
| 1217 | '@' => 'X', // Unix timestamp (ms since 01/01/1970) |
| 1218 | '!' => '', // Windows ticks (100ns since 01/01/0001), no equivalent |
| 1219 | ]; |
| 1220 | |
| 1221 | // For jQuery symbols, see http://trentrichardson.com/examples/timepicker/#tp-formatting |
| 1222 | // For Moment.js symbols, see https://momentjs.com/docs/#/displaying/format/ |
| 1223 | $jquery_ui_time_replacements = [ |
| 1224 | 'HH' => 'HH', // Hour with leading 0 (24 hour) |
| 1225 | 'H' => 'H', // Hour with no leading 0 (24 hour) |
| 1226 | 'hh' => 'hh', // Hour with leading 0 (12 hour) |
| 1227 | 'h' => 'h', // Hour with no leading 0 (12 hour) |
| 1228 | 'mm' => 'mm', // Minute with leading 0 |
| 1229 | 'm' => 'm', // Minute with no leading 0 |
| 1230 | 'i' => 'mm', // In case they got confused with PHP time format |
| 1231 | 'ss' => 'ss', // Second with leading 0 |
| 1232 | 's' => 's', // Second with no leading 0 |
| 1233 | 'l' => 'SSS', // Milliseconds always with leading 0 |
| 1234 | 'c' => 'SSSSSS', // Microseconds always with leading 0 |
| 1235 | 't' => 'a', // a or p for AM/PM, no equivalent, switches to am/pm |
| 1236 | 'TT' => 'A', // AM or PM for AM/PM |
| 1237 | 'tt' => 'a', // am or pm for AM/PM |
| 1238 | 'T' => 'A', // A or P for AM/PM, no equivalent, switches to AM/PM |
| 1239 | 'z' => '', // Timezone as defined by timezoneList => moment().zone(); |
| 1240 | 'Z' => '', // Timezone in Iso 8601 format (+04:45) => moment().zone(); |
| 1241 | ]; |
| 1242 | |
| 1243 | // Handle PHP first since it only has one replacement logic. |
| 1244 | if ( 'php' === $args['source'] ) { |
| 1245 | return pods_replace_keys_to_values( $source_format, $php_replacements ); |
| 1246 | } |
| 1247 | |
| 1248 | // Handle jQuery UI replacements. |
| 1249 | if ( 'jquery_ui' === $args['source'] ) { |
| 1250 | if ( 'date' === $args['type'] ) { |
| 1251 | return pods_replace_keys_to_values( $source_format, $jquery_ui_date_replacements ); |
| 1252 | } elseif ( 'time' === $args['type'] ) { |
| 1253 | return pods_replace_keys_to_values( $source_format, $jquery_ui_time_replacements ); |
| 1254 | } |
| 1255 | } |
| 1256 | |
| 1257 | return $source_format; |
| 1258 | } |
| 1259 | |
| 1260 | /** |
| 1261 | * Enqueue the i18n files for jquery date/timepicker |
| 1262 | * |
| 1263 | * @deprecated since 2.8.0 |
| 1264 | * |
| 1265 | * @since 2.7.0 |
| 1266 | */ |
| 1267 | public function enqueue_jquery_ui_i18n() { |
| 1268 | $done = (array) pods_static_cache_get( 'done', __METHOD__ ); |
| 1269 | |
| 1270 | $types = array(); |
| 1271 | |
| 1272 | switch ( static::$type ) { |
| 1273 | case 'time': |
| 1274 | $types['time'] = true; |
| 1275 | |
| 1276 | break; |
| 1277 | case 'date': |
| 1278 | $types['date'] = true; |
| 1279 | |
| 1280 | break; |
| 1281 | case 'datetime': |
| 1282 | $types['time'] = true; |
| 1283 | $types['date'] = true; |
| 1284 | |
| 1285 | break; |
| 1286 | } |
| 1287 | |
| 1288 | $locale = str_replace( '_', '-', get_locale() ); |
| 1289 | |
| 1290 | if ( isset( $types['date'] ) && ! isset( $done[ 'date-' . $locale ] ) ) { |
| 1291 | if ( function_exists( 'wp_localize_jquery_ui_datepicker' ) ) { |
| 1292 | wp_localize_jquery_ui_datepicker(); |
| 1293 | } |
| 1294 | |
| 1295 | $done['date'] = true; |
| 1296 | } |
| 1297 | |
| 1298 | if ( isset( $types['time'] ) && ! isset( $done[ 'time-' . $locale ] ) ) { |
| 1299 | $locale_exists = file_exists( PODS_DIR . 'ui/js/timepicker/i18n/jquery-ui-timepicker-' . $locale . '.js' ); |
| 1300 | |
| 1301 | // Local files. |
| 1302 | if ( ! $locale_exists ) { |
| 1303 | // Fallback to the base language (non-region specific). |
| 1304 | $locale = substr( $locale, 0, strpos( $locale, '-' ) ); |
| 1305 | |
| 1306 | $locale_exists = file_exists( PODS_DIR . 'ui/js/timepicker/i18n/jquery-ui-timepicker-' . $locale . '.js' ); |
| 1307 | } |
| 1308 | |
| 1309 | if ( $locale_exists && ! wp_script_is( 'jquery-ui-timepicker-i18n-' . $locale ) ) { |
| 1310 | wp_enqueue_script( 'jquery-ui-timepicker-i18n-' . $locale, PODS_URL . 'ui/js/timepicker/i18n/jquery-ui-timepicker-' . $locale . '.js', [ 'jquery-ui-timepicker' ], '1.6.3' ); |
| 1311 | } |
| 1312 | |
| 1313 | $done[ 'time-' . $locale ] = true; |
| 1314 | } |
| 1315 | } |
| 1316 | } |
| 1317 |