update_meta_data($field, $this->datetime_local_to_mysql($_POST[$field]));
}
}
foreach (array_keys(self::text_fields()) as $field) {
if (isset($_POST[$field])) {
$order->update_meta_data($field, sanitize_text_field(wp_unslash($_POST[$field])));
}
}
$order->save();
}
/**
* Convert a MySQL datetime string (as written by current_time('mysql')) to
* the HTML5 `datetime-local` format. Done as pure string reformatting so
* the value's timezone is preserved — current_time('mysql') already uses
* WP local time, and the browser interprets datetime-local as local time.
* Using strtotime()/date() here would re-interpret the value in the server
* timezone and drift on UTC-server / non-UTC-site configurations.
*/
private function mysql_to_datetime_local($value) {
$value = trim((string) $value);
if ($value === '') {
return '';
}
// Accepts 'YYYY-MM-DD HH:MM[:SS]' or 'YYYY-MM-DDTHH:MM[:SS]'.
if (preg_match('/^(\d{4}-\d{2}-\d{2})[ T](\d{2}:\d{2})/', $value, $m)) {
return $m[1] . 'T' . $m[2];
}
return '';
}
/**
* Convert an HTML5 datetime-local form value to a MySQL datetime string.
* No timezone conversion — the form value and the stored value are both
* treated as WP local time (matching current_time('mysql')).
*
* Browsers prevent out-of-range values on ``
* but a power user editing via DevTools or a script POSTing directly to
* the order edit URL could submit `2026-13-45T25:99`. The regex matches
* structurally; checkdate() + minute/hour bounds catch the semantics.
*/
private function datetime_local_to_mysql($value) {
$value = sanitize_text_field(wp_unslash($value));
if ($value === '') {
return '';
}
if (!preg_match('/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})(?::(\d{2}))?$/', $value, $m)) {
return '';
}
list(, $year, $month, $day, $hour, $minute) = $m;
$second = isset($m[6]) ? $m[6] : '00';
if (!checkdate((int) $month, (int) $day, (int) $year)) {
return '';
}
if ((int) $hour > 23 || (int) $minute > 59 || (int) $second > 59) {
return '';
}
return $year . '-' . $month . '-' . $day . ' ' . $hour . ':' . $minute . ':' . $second;
}
}