PluginProbe
WebberZone Top 10 — Popular Posts / 4.5.2
WebberZone Top 10 — Popular Posts v4.5.2
4.5.2 4.5.1 4.5.0 4.4.3 4.4.2 4.4.1 4.4.0 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 trunk 1.0 1.0.1 1.1 1.2 1.3 1.4 1.4.1 1.5 1.5.1 1.5.2 1.5.3 1.6 All 118 releases
← All changes | includes/admin/settings/class-settings-sanitize.php +274 -4 4.3.3 → 4.5.2 View file →
@@ -15,8 +15,10 @@
15 15 }
16 16
17 17 /**
18 18 * Settings Sanitize Class.
19 + *
20 + * @since 4.0.0
19 21 */
20 22 class Settings_Sanitize {
21 23
22 24 /**
@@ -71,15 +73,33 @@
71 73 return $default_value;
72 74 }
73 75
74 76 /**
75 - * Miscellaneous sanitize function
77 + * Fallback for field types that declare no sanitize callback of their own.
76 78 *
77 79 * @param mixed $value Setting Value.
78 - * @return string Sanitized value.
80 + * @return mixed Sanitized value.
79 81 */
80 82 public function sanitize_missing( $value ) {
81 - return $value;
83 + if ( is_array( $value ) ) {
84 + $sanitized = array();
85 +
86 + foreach ( $value as $key => $item ) {
87 + $sanitized[ sanitize_text_field( (string) $key ) ] = $this->sanitize_missing( $item );
88 + }
89 +
90 + return $sanitized;
91 + }
92 +
93 + if ( is_bool( $value ) || is_int( $value ) || is_float( $value ) ) {
94 + return $value;
95 + }
96 +
97 + if ( is_object( $value ) || is_null( $value ) ) {
98 + return '';
99 + }
100 +
101 + return sanitize_text_field( wp_unslash( (string) $value ) );
82 102 }
83 103
84 104 /**
85 105 * Sanitize text fields
@@ -91,8 +111,32 @@
91 111 return $this->sanitize_textarea_field( $value );
92 112 }
93 113
94 114 /**
115 + * Sanitize site-local date/time fields.
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 +
138 + /**
95 139 * Sanitize number fields
96 140 *
97 141 * @param string $value The field value.
98 142 * @return string Sanitized value
@@ -146,8 +190,12 @@
146 190 * @return string Sanitized value
147 191 */
148 192 public function sanitize_textarea_field( $value ) {
149 193
194 + if ( ! current_user_can( 'unfiltered_html' ) ) {
195 + return wp_kses_post( wp_unslash( $value ) );
196 + }
197 +
150 198 global $allowedposttags;
151 199
152 200 // We need more tags to allow for script and style.
153 201 $moretags = array(
@@ -197,8 +245,18 @@
197 245 return $value;
198 246 }
199 247
200 248 /**
249 + * Sanitize toggle fields
250 + *
251 + * @param mixed $value The field value.
252 + * @return int Sanitized value
253 + */
254 + public function sanitize_toggle_field( $value ) {
255 + return $this->sanitize_checkbox_field( $value );
256 + }
257 +
258 + /**
201 259 * Sanitize multicheck fields
202 260 *
203 261 * @param array|int $value The field value.
204 262 * @return string $value Sanitized value
@@ -259,8 +317,145 @@
259 317 return esc_url_raw( $value );
260 318 }
261 319
262 320 /**
321 + * Sanitize file fields, which hold the URL picked in the media browser.
322 + *
323 + * @param string $value The field value.
324 + * @return string Sanitized value
325 + */
326 + public function sanitize_file_field( $value ) {
327 + return esc_url_raw( wp_unslash( $value ) );
328 + }
329 +
330 + /**
331 + * Sanitize password fields.
332 + *
333 + * @param string $value The field value.
334 + * @return string Sanitized value
335 + */
336 + public function sanitize_password_field( $value ) {
337 + return sanitize_text_field( wp_unslash( $value ) );
338 + }
339 +
340 + /**
341 + * Sanitize WYSIWYG fields.
342 + *
343 + * @param string $value The field value.
344 + * @return string Sanitized value
345 + */
346 + public function sanitize_wysiwyg_field( $value ) {
347 + return wp_kses_post( wp_unslash( $value ) );
348 + }
349 +
350 + /**
351 + * Sanitize HTML fields.
352 + *
353 + * @param string $value The field value.
354 + * @return string Sanitized value
355 + */
356 + public function sanitize_html_field( $value ) {
357 + return $this->sanitize_textarea_field( $value );
358 + }
359 +
360 + /**
361 + * Sanitize CSS fields.
362 + *
363 + * @param string $value The field value.
364 + * @return string Sanitized value
365 + */
366 + public function sanitize_css_field( $value ) {
367 + return wp_strip_all_tags( wp_unslash( $value ) );
368 + }
369 +
370 + /**
371 + * Sanitize radio fields against the options the field actually offers.
372 + *
373 + * @param mixed $value The field value.
374 + * @param array $field Field configuration array.
375 + * @return string Sanitized value
376 + */
377 + public function sanitize_radio_field( $value, $field = array() ) {
378 + return $this->sanitize_choice( $value, array_keys( (array) ( $field['options'] ?? array() ) ), $field );
379 + }
380 +
381 + /**
382 + * Sanitize select fields against the options the field actually offers.
383 + *
384 + * @param mixed $value The field value.
385 + * @param array $field Field configuration array.
386 + * @return string Sanitized value
387 + */
388 + public function sanitize_select_field( $value, $field = array() ) {
389 + return $this->sanitize_choice( $value, array_keys( (array) ( $field['options'] ?? array() ) ), $field );
390 + }
391 +
392 + /**
393 + * Sanitize radio fields that carry a description per option.
394 + *
395 + * @param mixed $value The field value.
396 + * @param array $field Field configuration array.
397 + * @return string Sanitized value
398 + */
399 + public function sanitize_radiodesc_field( $value, $field = array() ) {
400 + $allowed = array();
401 +
402 + foreach ( (array) ( $field['options'] ?? array() ) as $option ) {
403 + if ( isset( $option['id'] ) ) {
404 + $allowed[] = $option['id'];
405 + }
406 + }
407 +
408 + return $this->sanitize_choice( $value, $allowed, $field );
409 + }
410 +
411 + /**
412 + * Sanitize thumbnail size fields.
413 + *
414 + * @param mixed $value The field value.
415 + * @param array $field Field configuration array.
416 + * @return string Sanitized value
417 + */
418 + public function sanitize_thumbsizes_field( $value, $field = array() ) {
419 + $allowed = array_keys( (array) ( $field['options'] ?? array() ) );
420 +
421 + // The form injects this size at render time, so it is never in the registered options.
422 + $allowed[] = $this->prefix . '_thumbnail';
423 +
424 + return $this->sanitize_choice( $value, $allowed, $field );
425 + }
426 +
427 + /**
428 + * Restrict a value to a list of allowed choices.
429 + *
430 + * @param mixed $value The field value.
431 + * @param array $allowed Allowed choices.
432 + * @param array $field Field configuration array.
433 + * @return string Sanitized value
434 + */
435 + protected function sanitize_choice( $value, $allowed, $field = array() ) {
436 + $value = sanitize_text_field( wp_unslash( (string) $value ) );
437 + $allowed = array_map( 'strval', (array) $allowed );
438 +
439 + if ( in_array( $value, $allowed, true ) ) {
440 + return $value;
441 + }
442 +
443 + // The select callback prints option values through sanitize_key().
444 + foreach ( $allowed as $choice ) {
445 + if ( sanitize_key( $choice ) === $value ) {
446 + return $choice;
447 + }
448 + }
449 +
450 + if ( isset( $field['default'] ) ) {
451 + return (string) $field['default'];
452 + }
453 +
454 + return empty( $allowed ) ? '' : reset( $allowed );
455 + }
456 +
457 + /**
263 458 * Sanitize sensitive fields.
264 459 *
265 460 * @param string $value The field value.
266 461 * @param string|array $key The field key.
@@ -297,8 +492,14 @@
297 492 * @param array $field Field configuration array.
298 493 * @return array Sanitized array
299 494 */
300 495 public function sanitize_repeater_field( $value, $field = array() ) {
496 + // No usable controls are rendered, so submitted rows are forged.
497 + if ( ! empty( $field['disabled'] ) || ! empty( $field['pro'] ) ) {
498 + $stored = ! empty( $field['id'] ) ? $this->get_option( $field['id'], array() ) : array();
499 + return is_array( $stored ) ? $stored : array();
500 + }
501 +
301 502 if ( ! is_array( $value ) ) {
302 503 return array();
303 504 }
304 505
@@ -395,8 +596,77 @@
395 596 return $sanitized_value;
396 597 }
397 598
398 599 /**
600 + * Find repeater rows that fail their own required-field rules.
601 + *
602 + * Purely structural - returns what is wrong, not a human message, so it carries no i18n.
603 + *
604 + * @param array $rows Sanitized repeater rows, as returned by sanitize_repeater_field().
605 + * @param array $field Repeater field configuration.
606 + * @return array Map of row index => issue, where issue may have a 'missing' key
607 + * (subfield IDs with required => true that are empty) and/or a
608 + * 'missing_one_of' key (the required_one_of group, present only when
609 + * none of it is filled).
610 + */
611 + public static function get_incomplete_repeater_rows( array $rows, array $field ) {
612 + $subfields = ! empty( $field['fields'] ) && is_array( $field['fields'] ) ? $field['fields'] : array();
613 +
614 + $required_subfields = array();
615 + foreach ( $subfields as $subfield_id => $subfield ) {
616 + // Row values are keyed by the subfield's own id; the array key may be numeric.
617 + if ( ! empty( $subfield['required'] ) ) {
618 + $required_subfields[] = $subfield['id'] ?? $subfield_id;
619 + }
620 + }
621 +
622 + $required_one_of = ! empty( $field['required_one_of'] ) && is_array( $field['required_one_of'] ) ? $field['required_one_of'] : array();
623 +
624 + if ( empty( $required_subfields ) && empty( $required_one_of ) ) {
625 + return array();
626 + }
627 +
628 + $is_filled = static function ( $values, $subfield_id ) {
629 + return '' !== trim( (string) ( $values[ $subfield_id ] ?? '' ), " \t\n\r\0\x0B," );
630 + };
631 + $incomplete = array();
632 +
633 + foreach ( array_values( $rows ) as $index => $row ) {
634 + $values = isset( $row['fields'] ) && is_array( $row['fields'] ) ? $row['fields'] : array();
635 + $issue = array();
636 +
637 + $missing = array();
638 + foreach ( $required_subfields as $subfield_id ) {
639 + if ( ! $is_filled( $values, $subfield_id ) ) {
640 + $missing[] = $subfield_id;
641 + }
642 + }
643 + if ( ! empty( $missing ) ) {
644 + $issue['missing'] = $missing;
645 + }
646 +
647 + if ( ! empty( $required_one_of ) ) {
648 + $filled = false;
649 + foreach ( $required_one_of as $subfield_id ) {
650 + if ( $is_filled( $values, $subfield_id ) ) {
651 + $filled = true;
652 + break;
653 + }
654 + }
655 + if ( ! $filled ) {
656 + $issue['missing_one_of'] = $required_one_of;
657 + }
658 + }
659 +
660 + if ( ! empty( $issue ) ) {
661 + $incomplete[ $index ] = $issue;
662 + }
663 + }
664 +
665 + return $incomplete;
666 + }
667 +
668 + /**
399 669 * Convert a string to CSV.
400 670 *
401 671 * @param array $input_array Input string.
402 672 * @param string $delimiter Delimiter.
@@ -453,9 +723,9 @@
453 723 return $output;
454 724 }
455 725
456 726 /**
457 - * Processes category/taxonomy slugs and adds a new element to the settings array containing the term taxonomy IDs.
727 + * Resolve taxonomy slugs to term taxonomy IDs.
458 728 *
459 729 * @param array $settings The settings array containing the taxonomy slugs to sanitize.
460 730 * @param string $source_key The key in the settings array containing the slugs. Pattern is Name (taxonomy:term_taxonomy_id).
461 731 * @param string $target_key The key in the settings array to store the sanitized term taxonomy IDs.