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-form.php +114 -25 4.4.1 → 4.5.2 View file →
@@ -73,9 +73,9 @@
73 73 *
74 74 * @return string Description of the field.
75 75 */
76 76 public function get_field_description( $args ) {
77 - $desc = ! empty( $args['desc'] ) ? '<p class="description">' . wp_kses_post( $args['desc'] ) . '</p>' : '';
77 + $desc = ! empty( $args['desc'] ) ? '<p class="description">' . wp_kses( $args['desc'], $this->get_allowed_html() ) . '</p>' : '';
78 78
79 79 /**
80 80 * After Settings Output filter
81 81 *
@@ -106,9 +106,9 @@
106 106 $default = $this->get_field_default( $args );
107 107 if ( is_array( $default ) ) {
108 108 $default = implode( ',', array_map( 'strval', $default ) );
109 109 }
110 - $default = trim( (string) $default );
110 + $default = trim( (string) $default, " \t\n\r\0\x0B" );
111 111
112 112 // Map option keys to their labels where the field has a choices list.
113 113 if ( ! empty( $args['options'] ) && is_array( $args['options'] ) ) {
114 114 if ( 'radiodesc' === $type && '' !== $default ) {
@@ -124,9 +124,9 @@
124 124 }
125 125 } elseif ( '' !== $default && 'multicheck' === $type ) {
126 126 $labels = array();
127 127 foreach ( explode( ',', $default ) as $key ) {
128 - $key = trim( $key );
128 + $key = trim( $key, " \t\n\r\0\x0B" );
129 129 $labels[] = isset( $args['options'][ $key ] ) && is_string( $args['options'][ $key ] ) ? $args['options'][ $key ] : $key;
130 130 }
131 131 $default = implode( ', ', $labels );
132 132 }
@@ -196,9 +196,9 @@
196 196 if ( is_array( $value ) || is_array( $default ) || in_array( $type, array( 'multicheck', 'posttypes', 'taxonomies' ), true ) ) {
197 197 return $this->normalize_list_value( $value ) !== $this->normalize_list_value( $default );
198 198 }
199 199
200 - return trim( (string) $value ) !== trim( (string) $default );
200 + return trim( (string) $value, " \t\n\r\0\x0B" ) !== trim( (string) $default, " \t\n\r\0\x0B" );
201 201 }
202 202
203 203 /**
204 204 * Normalize a list-style value (array or comma-separated string) into a
@@ -280,9 +280,9 @@
280 280 $class = implode( ' ', array_map( 'sanitize_html_class', explode( ' ', $args['field_class'] ?? '' ) ) );
281 281 if ( $default_class ) {
282 282 $class = $default_class . ' ' . $class;
283 283 }
284 - return trim( $class );
284 + return trim( $class, " \t\n\r\0\x0B" );
285 285 }
286 286
287 287 /**
288 288 * Get placeholder attribute string.
@@ -300,9 +300,9 @@
300 300 * @param array $args Field arguments.
301 301 * @return string Concatenated boolean attributes.
302 302 */
303 303 protected function get_boolean_attributes( $args ) {
304 - $disabled = ( ! empty( $args['disabled'] ) || ! empty( $args['pro'] ) ) ? ' disabled="disabled"' : '';
304 + $disabled = $this->is_field_disabled( $args ) ? ' disabled="disabled"' : '';
305 305 $readonly = ( isset( $args['readonly'] ) && true === $args['readonly'] ) ? ' readonly="readonly"' : '';
306 306 $required = ( isset( $args['required'] ) && true === $args['required'] ) ? ' required' : '';
307 307 return $disabled . $readonly . $required;
308 308 }
@@ -307,8 +307,18 @@
307 307 return $disabled . $readonly . $required;
308 308 }
309 309
310 310 /**
311 + * Whether a field is disabled, either explicitly or because it is a pro-only field.
312 + *
313 + * @param array $args Field arguments.
314 + * @return bool Whether the field is disabled.
315 + */
316 + protected function is_field_disabled( $args ) {
317 + return ! empty( $args['disabled'] ) || ! empty( $args['pro'] );
318 + }
319 +
320 + /**
311 321 * Get field ID and name attributes.
312 322 *
313 323 * @param array $args Field arguments.
314 324 * @return array Array containing field_id and field_name.
@@ -341,8 +351,20 @@
341 351 );
342 352 }
343 353
344 354 /**
355 + * Get the rendered field ID for a field definition.
356 + *
357 + * @param array $args Field arguments.
358 + * @return string Field ID.
359 + */
360 + public function get_field_id( $args ) {
361 + $field_attributes = $this->get_field_attributes( $args );
362 +
363 + return $field_attributes['field_id'];
364 + }
365 +
366 + /**
345 367 * Returns the allowed HTML tags and attributes for settings form output.
346 368 *
347 369 * Use the `{prefix}_settings_form_allowed_html` filter to add extra tags or
348 370 * attributes needed by custom field types or `field_attributes` entries.
@@ -423,14 +445,33 @@
423 445 'class' => true,
424 446 'style' => true,
425 447 ),
426 448 'button' => array(
427 - 'type' => true,
428 - 'id' => true,
429 - 'class' => true,
430 - 'style' => true,
431 - 'disabled' => true,
449 + 'type' => true,
450 + 'id' => true,
451 + 'class' => true,
452 + 'style' => true,
453 + 'disabled' => true,
454 + 'aria-controls' => true,
455 + 'aria-expanded' => true,
456 + 'aria-label' => true,
432 457 ),
458 + 'div' => array(
459 + 'id' => true,
460 + 'class' => true,
461 + 'style' => true,
462 + 'aria-hidden' => true,
463 + 'aria-busy' => true,
464 + 'role' => true,
465 + ),
466 + 'span' => array(
467 + 'class' => true,
468 + 'style' => true,
469 + 'aria-hidden' => true,
470 + 'aria-live' => true,
471 + 'aria-atomic' => true,
472 + 'role' => true,
473 + ),
433 474 'template' => array(
434 475 'class' => true,
435 476 'data-id' => true,
436 477 ),
@@ -545,8 +586,34 @@
545 586 echo wp_kses( apply_filters( $this->prefix . '_after_setting_output', $html, $args ), $this->get_allowed_html() ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound
546 587 }
547 588
548 589 /**
590 + * Display local date/time fields.
591 + *
592 + * @param array $args Field arguments.
593 + */
594 + public function callback_datetime( $args ) {
595 + $value = $this->get_field_value( $args );
596 + $class = $this->get_field_class( $args );
597 + $attributes = $this->get_boolean_attributes( $args ) . $this->build_field_attributes( $args );
598 + $placeholder = $this->get_placeholder_attribute( $args );
599 + $field_attributes = $this->get_field_attributes( $args );
600 +
601 + $html = sprintf(
602 + '<input type="datetime-local" id="%1$s" name="%2$s" class="%3$s" value="%4$s" step="60" %5$s %6$s />',
603 + $field_attributes['field_id'],
604 + $field_attributes['field_name'],
605 + $class . ' regular-text',
606 + esc_attr( stripslashes( (string) $value ) ),
607 + $attributes,
608 + $placeholder
609 + );
610 + $html .= $this->get_field_description( $args );
611 +
612 + echo wp_kses( apply_filters( $this->prefix . '_after_setting_output', $html, $args ), $this->get_allowed_html() ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound
613 + }
614 +
615 + /**
549 616 * Display url fields.
550 617 *
551 618 * @param array $args Array of arguments.
552 619 */
@@ -649,9 +716,9 @@
649 716 * @param array $args Field arguments.
650 717 * @return string Disabled attribute or empty string.
651 718 */
652 719 protected function get_disabled_attribute( $args ) {
653 - return ( ! empty( $args['disabled'] ) || ! empty( $args['pro'] ) ) ? ' disabled="disabled"' : '';
720 + return $this->is_field_disabled( $args ) ? ' disabled="disabled"' : '';
654 721 }
655 722
656 723 /**
657 724 * Display checkboxes.
@@ -929,9 +996,9 @@
929 996 public function callback_number( $args ) {
930 997 $value = $this->get_field_value( $args );
931 998 $max = isset( $args['max'] ) ? intval( $args['max'] ) : 999999;
932 999 $min = isset( $args['min'] ) ? intval( $args['min'] ) : 0;
933 - $step = isset( $args['step'] ) ? intval( $args['step'] ) : 1;
1000 + $step = isset( $args['step'] ) && ( is_numeric( $args['step'] ) || 'any' === $args['step'] ) ? $args['step'] : 1;
934 1001 $size = $args['size'] ?? 'regular';
935 1002 $placeholder = $this->get_placeholder_attribute( $args );
936 1003 $attributes = $this->get_boolean_attributes( $args );
937 1004
@@ -1216,8 +1283,13 @@
1216 1283
1217 1284 $class = $this->get_field_class( $args );
1218 1285 $attributes = $this->get_boolean_attributes( $args ) . $this->build_field_attributes( $args );
1219 1286
1287 + // `disabled` does nothing on the wrapper; the class neutralises the buttons.
1288 + if ( $this->is_field_disabled( $args ) ) {
1289 + $class .= ' wz-repeater-disabled';
1290 + }
1291 +
1220 1292 $data_index = (string) count( $value );
1221 1293 $live_update_field = ! empty( $args['live_update_field'] ) ? $args['live_update_field'] : 'name';
1222 1294 $fallback_title = ! empty( $args['new_item_text'] ) ? $args['new_item_text'] : $this->translation_strings['repeater_new_item'];
1223 1295 $live_update_options = ! empty( $args['live_update_field_options'] ) && is_array( $args['live_update_field_options'] ) ? $args['live_update_field_options'] : array();
@@ -1245,9 +1317,9 @@
1245 1317 }
1246 1318 }
1247 1319 ?>
1248 1320 </div>
1249 - <button type="button" class="button add-item" data-target="<?php echo esc_attr( $args['id'] ); ?>">
1321 + <button type="button" class="button add-item" data-target="<?php echo esc_attr( $args['id'] ); ?>" <?php disabled( $this->is_field_disabled( $args ) ); ?>>
1250 1322 <?php echo esc_html( ! empty( $args['add_button_text'] ) ? $args['add_button_text'] : 'Add Item' ); ?>
1251 1323 </button>
1252 1324
1253 1325 <template class="repeater-template" data-id="<?php echo esc_attr( $args['id'] ); ?>">
@@ -1290,12 +1362,19 @@
1290 1362 // For new items, use a placeholder that will be replaced.
1291 1363 $item_id = '{{ROW_ID}}';
1292 1364 }
1293 1365
1366 + $parent_disabled = $this->is_field_disabled( $args );
1367 + $content_id = sprintf(
1368 + '%s-%s-%s-content',
1369 + sanitize_key( $this->settings_key ),
1370 + sanitize_key( $args['id'] ),
1371 + '{{ROW_ID}}' === $item_id ? '{{ROW_ID}}' : sanitize_key( $item_id )
1372 + );
1294 1373 ?>
1295 1374 <div class="wz-repeater-item" data-row-id="<?php echo esc_attr( $item_id ); ?>">
1296 - <input type="hidden" name="<?php echo esc_attr( $this->settings_key ); ?>[<?php echo esc_attr( $args['id'] ); ?>][<?php echo esc_attr( $index ); ?>][row_id]" value="<?php echo esc_attr( $item_id ); ?>" />
1297 - <div class="repeater-item-header">
1375 + <input type="hidden" name="<?php echo esc_attr( $this->settings_key ); ?>[<?php echo esc_attr( $args['id'] ); ?>][<?php echo esc_attr( $index ); ?>][row_id]" value="<?php echo esc_attr( $item_id ); ?>" <?php disabled( $parent_disabled ); ?> />
1376 + <button type="button" class="repeater-item-header" aria-expanded="false" aria-controls="<?php echo esc_attr( $content_id ); ?>">
1298 1377 <?php
1299 1378 $display_field = ! empty( $args['live_update_field'] ) ? $args['live_update_field'] : 'name';
1300 1379 $live_options = ! empty( $args['live_update_field_options'] ) && is_array( $args['live_update_field_options'] ) ? $args['live_update_field_options'] : array();
1301 1380 $raw_live_value = ! empty( $item['fields'][ $display_field ] ) ? (string) $item['fields'][ $display_field ] : '';
@@ -1303,11 +1382,11 @@
1303 1382 ? ( isset( $live_options[ $raw_live_value ] ) ? $live_options[ $raw_live_value ] : $raw_live_value )
1304 1383 : $fallback_title;
1305 1384 ?>
1306 1385 <span class="repeater-title"><?php echo esc_html( $display_value ); ?></span>
1307 - <span class="toggle-icon">▼</span>
1308 - </div>
1309 - <div class="repeater-item-content" style="display: none;">
1386 + <span class="toggle-icon" aria-hidden="true">▼</span>
1387 + </button>
1388 + <div id="<?php echo esc_attr( $content_id ); ?>" class="repeater-item-content" aria-hidden="true" style="display: none;">
1310 1389 <?php
1311 1390 foreach ( $args['fields'] as $field ) {
1312 1391 $field_id = sanitize_key( $field['id'] );
1313 1392
@@ -1318,8 +1397,18 @@
1318 1397 '_repeater_id' => $args['id'],
1319 1398 '_index' => $index,
1320 1399 )
1321 1400 );
1401 +
1402 + // Subfields do not inherit the repeater's own arguments.
1403 + if ( $parent_disabled ) {
1404 + $field_args['disabled'] = true;
1405 + }
1406 +
1407 + // Rows collapse, and a browser blocks submit on a hidden required
1408 + // control without reporting why. The label keeps its asterisk.
1409 + $field_args['required'] = false;
1410 +
1322 1411 $field_args = Settings_API::parse_field_args( $field_args, $args['section'] );
1323 1412
1324 1413 if ( ! isset( $field['type'] ) || ! is_string( $field['type'] ) ) {
1325 1414 continue;
@@ -1352,16 +1441,16 @@
1352 1441 </div>
1353 1442
1354 1443 <div class="repeater-item-footer">
1355 1444 <div class="repeater-item-actions">
1356 - <button type="button" class="button button-secondary move-up">
1357 - <span class="dashicons dashicons-arrow-up-alt2"></span>
1445 + <button type="button" class="button button-secondary move-up" aria-label="<?php echo esc_attr( $this->translation_strings['repeater_move_up'] ?? 'Move item up' ); ?>" <?php disabled( $parent_disabled ); ?>>
1446 + <span class="dashicons dashicons-arrow-up-alt2" aria-hidden="true"></span>
1358 1447 </button>
1359 - <button type="button" class="button button-secondary move-down">
1360 - <span class="dashicons dashicons-arrow-down-alt2"></span>
1448 + <button type="button" class="button button-secondary move-down" aria-label="<?php echo esc_attr( $this->translation_strings['repeater_move_down'] ?? 'Move item down' ); ?>" <?php disabled( $parent_disabled ); ?>>
1449 + <span class="dashicons dashicons-arrow-down-alt2" aria-hidden="true"></span>
1361 1450 </button>
1362 - <button type="button" class="button button-secondary remove-item">
1363 - <span class="dashicons dashicons-trash"></span>
1451 + <button type="button" class="button button-secondary remove-item" aria-label="<?php echo esc_attr( $this->translation_strings['repeater_remove_item'] ?? 'Remove item' ); ?>" <?php disabled( $parent_disabled ); ?>>
1452 + <span class="dashicons dashicons-trash" aria-hidden="true"></span>
1364 1453 </button>
1365 1454 </div>
1366 1455 </div>
1367 1456 </div>