Skip to content

Commit 8495629

Browse files
committed
Add datetime field support
1 parent 5638dbd commit 8495629

6 files changed

Lines changed: 58 additions & 2 deletions

File tree

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ Implement `get_registered_settings()` in your copied `Settings` class. Fields ar
111111
),
112112
```
113113

114-
26 field types are available — text, url, csv, numbercsv, postids, color, number, textarea, css, html, wysiwyg, checkbox, toggle, multicheck, radio, radiodesc, select, posttypes, taxonomies, thumbsizes, file, password, sensitive, repeater, header, and descriptive_text. See the [field types reference](https://webberzone.github.io/Settings_API/docs/02-wzsa-core-classes/field-types-reference/).
114+
27 field types are available — text, url, csv, numbercsv, postids, datetime, color, number, textarea, css, html, wysiwyg, checkbox, toggle, multicheck, radio, radiodesc, select, posttypes, taxonomies, thumbsizes, file, password, sensitive, repeater, header, and descriptive_text. See the [field types reference](https://webberzone.github.io/Settings_API/docs/02-wzsa-core-classes/field-types-reference/).
115115

116116
### 5. Instantiate the Settings API
117117

‎docs/02-wzsa-core-classes/field-types-reference.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ An unrecognized `type` falls through to `callback_missing()`, which prints a not
2222
| `csv` | Single-line input | A comma-separated list of strings; each item is trimmed. |
2323
| `numbercsv` | Single-line input | A comma-separated list of numbers. |
2424
| `postids` | Single-line input | A comma-separated list of post IDs. Renders as `text`. |
25+
| `datetime` | Local date/time input | Renders as `datetime-local` and accepts `Y-m-dTH:i` values in the site's timezone. |
2526
| `password` | Password input | Sanitized with `sanitize_text_field()`. Use `sensitive` for API keys. |
2627
| `sensitive` | Password-style input | Value is encrypted at rest and masked in the UI, showing only the last four characters. |
2728
| `number` | Number input | Uses `min`, `max`, and `step`. |

‎docs/02-wzsa-core-classes/sanitization-reference.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ Every callback receives the field configuration as its second argument, which is
3434
| `sanitize_csv_field()` | `csv` | Sanitizes the string, then trims each comma-separated item. |
3535
| `sanitize_numbercsv_field()` | `numbercsv` | Casts each item with `absint()` and drops empties. |
3636
| `sanitize_postids_field()` | `postids` | Casts each item with `absint()` and drops IDs that no longer resolve to a post. |
37+
| `sanitize_datetime_field()` | `datetime` | Accepts strict `Y-m-dTH:i` values and rejects malformed, calendar-invalid, and non-existent local times caused by daylight-saving transitions. |
3738
| `sanitize_checkbox_field()` | `checkbox`, `toggle` | Returns `1` or `0`. The hidden `-1` companion input is what makes an unchecked box save as `0`. |
3839
| `sanitize_multicheck_field()` | `multicheck` | Returns a comma-separated list of the checked keys; `-1` means nothing checked. |
3940
| `sanitize_posttypes_field()` | `posttypes` | Delegates to `sanitize_multicheck_field()`. |

‎docs/index.html‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ <h3>Settings_API reference</h3>
2424
</a>
2525
<a class="doc-card" href="{{ '/docs/02-wzsa-core-classes/field-types-reference/' | relative_url }}">
2626
<h3>Field types reference</h3>
27-
<p>All 26 field types and the arguments each one understands.</p>
27+
<p>All 27 field types and the arguments each one understands.</p>
2828
</a>
2929
<a class="doc-card" href="{{ '/docs/02-wzsa-core-classes/options-api-reference/' | relative_url }}">
3030
<h3>Options_API reference</h3>

‎settings/class-settings-form.php‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,34 @@ public function callback_text( $args ) {
553553
echo wp_kses( apply_filters( $this->prefix . '_after_setting_output', $html, $args ), $this->get_allowed_html() ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound
554554
}
555555

556+
/**
557+
* Display local date/time fields.
558+
*
559+
* @since 3.2.0
560+
*
561+
* @param array $args Field arguments.
562+
*/
563+
public function callback_datetime( $args ) {
564+
$value = $this->get_field_value( $args );
565+
$class = $this->get_field_class( $args );
566+
$attributes = $this->get_boolean_attributes( $args ) . $this->build_field_attributes( $args );
567+
$placeholder = $this->get_placeholder_attribute( $args );
568+
$field_attributes = $this->get_field_attributes( $args );
569+
570+
$html = sprintf(
571+
'<input type="datetime-local" id="%1$s" name="%2$s" class="%3$s" value="%4$s" step="60" %5$s %6$s />',
572+
$field_attributes['field_id'],
573+
$field_attributes['field_name'],
574+
$class . ' regular-text',
575+
esc_attr( stripslashes( (string) $value ) ),
576+
$attributes,
577+
$placeholder
578+
);
579+
$html .= $this->get_field_description( $args );
580+
581+
echo wp_kses( apply_filters( $this->prefix . '_after_setting_output', $html, $args ), $this->get_allowed_html() ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound
582+
}
583+
556584
/**
557585
* Display url fields.
558586
*

‎settings/class-settings-sanitize.php‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,32 @@ public function sanitize_text_field( $value ) {
109109
return $this->sanitize_textarea_field( $value );
110110
}
111111

112+
/**
113+
* Sanitize site-local date/time fields.
114+
*
115+
* @since 3.2.0
116+
*
117+
* @param string $value The date/time value.
118+
* @return string Sanitized date/time, or an empty string when invalid.
119+
*/
120+
public function sanitize_datetime_field( $value ) {
121+
$value = trim( sanitize_text_field( wp_unslash( (string) $value ) ), " \t\n\r\0\x0B" );
122+
$format = '!Y-m-d\\TH:i';
123+
$utc = \DateTimeImmutable::createFromFormat( $format, $value, new \DateTimeZone( 'UTC' ) );
124+
$errors = \DateTimeImmutable::getLastErrors();
125+
126+
if ( false === $utc || ( false !== $errors && ( $errors['warning_count'] > 0 || $errors['error_count'] > 0 ) ) || $utc->format( 'Y-m-d\\TH:i' ) !== $value ) {
127+
return '';
128+
}
129+
130+
$local = \DateTimeImmutable::createFromFormat( $format, $value, wp_timezone() );
131+
if ( false === $local || $local->format( 'Y-m-d\\TH:i' ) !== $value ) {
132+
return '';
133+
}
134+
135+
return $value;
136+
}
137+
112138
/**
113139
* Sanitize number fields
114140
*

0 commit comments

Comments
 (0)