PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / 28.5
Yoast SEO – Advanced SEO with real-time guidance and built-in AI v28.5
28.5 28.4 28.3 28.2 28.1 28.0 27.9 27.8 27.7 27.6 27.5 trunk 18.0 18.1 18.2 18.3 18.4 18.4.1 18.5 18.5.1 18.6 18.7 18.8 18.9 19.0 All 129 releases
← All changes | admin/class-yoast-form.php +175 -75 18.428.5 View file →
@@ -5,8 +5,9 @@
5 5 * @package WPSEO\Admin
6 6 */
7 7
8 8 use Yoast\WP\SEO\Presenters\Admin\Light_Switch_Presenter;
9 +use Yoast\WP\SEO\Presenters\Admin\Sidebar_Presenter;
9 10
10 11 /**
11 12 * Admin form class.
12 13 *
@@ -16,10 +17,11 @@
16 17
17 18 /**
18 19 * Instance of this class
19 20 *
21 + * @since 2.0
22 + *
20 23 * @var Yoast_Form
21 - * @since 2.0
22 24 */
23 25 public static $instance;
24 26
25 27 /**
@@ -24,10 +26,11 @@
24 26
25 27 /**
26 28 * The short name of the option to use for the current page.
27 29 *
30 + * @since 2.0
31 + *
28 32 * @var string
29 - * @since 2.0
30 33 */
31 34 public $option_name;
32 35
33 36 /**
@@ -61,8 +64,10 @@
61 64 * @param bool $form Whether or not the form start tag should be included.
62 65 * @param string $option The short name of the option to use for the current page.
63 66 * @param bool $contains_files Whether the form should allow for file uploads.
64 67 * @param bool $option_long_name Group name of the option.
68 + *
69 + * @return void
65 70 */
66 71 public function admin_header( $form = true, $option = 'wpseo', $contains_files = false, $option_long_name = false ) {
67 72 if ( ! $option_long_name ) {
68 73 $option_long_name = WPSEO_Options::get_group_name( $option );
@@ -78,8 +83,9 @@
78 83 */
79 84 require_once ABSPATH . 'wp-admin/options-head.php';
80 85 ?>
81 86 <h1 id="wpseo-title"><?php echo esc_html( get_admin_page_title() ); ?></h1>
87 + <div id="yst-settings-header-root"></div>
82 88 <div class="wpseo_content_wrapper">
83 89 <div class="wpseo_content_cell" id="wpseo_content_top">
84 90 <?php
85 91 if ( $form === true ) {
@@ -94,14 +100,14 @@
94 100 $action_url = admin_url( 'options.php' );
95 101 $hidden_fields_cb = 'settings_fields';
96 102 }
97 103
98 - echo '<form action="' .
99 - esc_url( $action_url ) .
100 - '" method="post" id="wpseo-conf"' .
101 - $enctype . ' accept-charset="' .
102 - esc_attr( get_bloginfo( 'charset' ) ) .
103 - '" novalidate="novalidate">';
104 + echo '<form action="'
105 + . esc_url( $action_url )
106 + . '" method="post" id="wpseo-conf"'
107 + . $enctype . ' accept-charset="' // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- nothing to escape.
108 + . esc_attr( get_bloginfo( 'charset' ) )
109 + . '" novalidate="novalidate">';
104 110 call_user_func( $hidden_fields_cb, $option_long_name );
105 111 }
106 112 $this->set_option( $option );
107 113 }
@@ -111,8 +117,10 @@
111 117 *
112 118 * @since 2.0
113 119 *
114 120 * @param string $option_name Option key.
121 + *
122 + * @return void
115 123 */
116 124 public function set_option( $option_name ) {
117 125 $this->option_name = $option_name;
118 126
@@ -128,8 +136,10 @@
128 136 * @since 2.0
129 137 *
130 138 * @param bool $submit Whether or not a submit button and form end tag should be shown.
131 139 * @param bool $show_sidebar Whether or not to show the banner sidebar - used by premium plugins to disable it.
140 + *
141 + * @return void
132 142 */
133 143 public function admin_footer( $submit = true, $show_sidebar = true ) {
134 144 if ( $submit ) {
135 145 $settings_changed_listener = new WPSEO_Admin_Settings_Changed_Listener();
@@ -179,8 +189,10 @@
179 189 /**
180 190 * Generates the sidebar for admin pages.
181 191 *
182 192 * @since 2.0
193 + *
194 + * @return void
183 195 */
184 196 public function admin_sidebar() {
185 197 // No banners in Premium.
186 198 $addon_manager = new WPSEO_Addon_Manager();
@@ -187,9 +199,11 @@
187 199 if ( YoastSEO()->helpers->product->is_premium() && $addon_manager->has_valid_subscription( WPSEO_Addon_Manager::PREMIUM_SLUG ) ) {
188 200 return;
189 201 }
190 202
191 - require_once 'views/sidebar.php';
203 + $sidebar_presenter = new Sidebar_Presenter();
204 + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output escaped in presenter.
205 + echo $sidebar_presenter->present();
192 206 }
193 207
194 208 /**
195 209 * Output a label element.
@@ -195,10 +209,12 @@
195 209 * Output a label element.
196 210 *
197 211 * @since 2.0
198 212 *
199 - * @param string $text Label text string.
213 + * @param string $text Label text string, which can contain escaped html.
200 214 * @param array $attr HTML attributes set.
215 + *
216 + * @return void
201 217 */
202 218 public function label( $text, $attr ) {
203 219 $defaults = [
204 220 'class' => 'checkbox',
@@ -212,8 +228,9 @@
212 228 if ( $attr['aria_label'] !== '' ) {
213 229 $aria_label = ' aria-label="' . esc_attr( $attr['aria_label'] ) . '"';
214 230 }
215 231
232 + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- output escaped before. Specifically, the $text variable can contain escaped html.
216 233 echo "<label class='" . esc_attr( $attr['class'] ) . "' for='" . esc_attr( $attr['for'] ) . "'$aria_label>$text";
217 234 if ( $attr['close'] ) {
218 235 echo '</label>';
219 236 }
@@ -225,8 +242,10 @@
225 242 * @since 3.4
226 243 *
227 244 * @param string $text Legend text string.
228 245 * @param array $attr HTML attributes set.
246 + *
247 + * @return void
229 248 */
230 249 public function legend( $text, $attr ) {
231 250 $defaults = [
232 251 'id' => '',
@@ -234,9 +253,10 @@
234 253 ];
235 254 $attr = wp_parse_args( $attr, $defaults );
236 255
237 256 $id = ( $attr['id'] === '' ) ? '' : ' id="' . esc_attr( $attr['id'] ) . '"';
238 - echo '<legend class="yoast-form-legend ' . esc_attr( $attr['class'] ) . '"' . $id . '>' . $text . '</legend>';
257 + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- output escaped before.
258 + echo '<legend class="' . esc_attr( 'yoast-form-legend ' . $attr['class'] ) . '"' . $id . '>' . $text . '</legend>';
239 259 }
240 260
241 261 /**
242 262 * Create a Checkbox input field.
@@ -246,8 +266,10 @@
246 266 * @param string $variable The variable within the option to create the checkbox for.
247 267 * @param string $label The label to show for the variable.
248 268 * @param bool $label_left Whether the label should be left (true) or right (false).
249 269 * @param array $attr Extra attributes to add to the checkbox.
270 + *
271 + * @return void
250 272 */
251 273 public function checkbox( $variable, $label, $label_left = false, $attr = [] ) {
252 274 $val = $this->get_field_value( $variable, false );
253 275
@@ -270,9 +292,9 @@
270 292
271 293 $disabled_attribute = $this->get_disabled_attribute( $variable, $attr );
272 294
273 295 // phpcs:ignore WordPress.Security.EscapeOutput -- Reason: $disabled_attribute output is hardcoded and all other output is properly escaped.
274 - echo '<input class="checkbox ', esc_attr( $class ), '" type="checkbox" id="', esc_attr( $variable ), '" name="', esc_attr( $this->option_name ), '[', esc_attr( $variable ), ']" value="on"', checked( $val, 'on', false ), $disabled_attribute, '/>';
296 + echo '<input class="', esc_attr( 'checkbox ' . $class ), '" type="checkbox" id="', esc_attr( $variable ), '" name="', esc_attr( $this->option_name . '[' . $variable . ']' ), '" value="on"', checked( $val, 'on', false ), $disabled_attribute, '/>';
275 297
276 298 if ( ! empty( $label ) ) {
277 299 $this->label( $label, [ 'for' => $variable ] );
278 300 }
@@ -287,8 +309,10 @@
287 309 *
288 310 * @param string $variable The variables within the option to create the checkbox list for.
289 311 * @param string $labels The labels to show for the variable.
290 312 * @param array $attr Extra attributes to add to the checkbox list.
313 + *
314 + * @return void
291 315 */
292 316 public function checkbox_list( $variable, $labels, $attr = [] ) {
293 317 $defaults = [
294 318 'disabled' => false,
@@ -300,18 +324,18 @@
300 324 foreach ( $labels as $name => $label ) {
301 325 printf(
302 326 '<input class="checkbox double" id="%1$s" type="checkbox" name="%2$s" %3$s %5$s value="%4$s"/>',
303 327 esc_attr( $variable . '-' . $name ),
304 - esc_attr( $this->option_name ) . '[' . esc_attr( $variable ) . '][' . $name . ']',
328 + esc_attr( $this->option_name . '[' . $variable . '][' . $name . ']' ),
305 329 checked( ! empty( $values[ $name ] ), true, false ),
306 330 esc_attr( $name ),
307 - disabled( ( isset( $attr['disabled'] ) && $attr['disabled'] ), true, false )
331 + disabled( ( isset( $attr['disabled'] ) && $attr['disabled'] ), true, false ),
308 332 );
309 333
310 334 printf(
311 335 '<label class="checkbox" for="%1$s">%2$s</label>',
312 336 esc_attr( $variable . '-' . $name ), // #1
313 - esc_html( $label )
337 + esc_html( $label ),
314 338 );
315 339 echo '<br class="clear">';
316 340 }
317 341 }
@@ -328,8 +352,10 @@
328 352 * @param string $help Inline Help that will be printed out before the toggle.
329 353 * @param bool $strong Whether the visual label is displayed in strong text. Default is false.
330 354 * Starting from Yoast SEO 16.5, the visual label is forced to bold via CSS.
331 355 * @param array $attr Extra attributes to add to the light switch.
356 + *
357 + * @return void
332 358 */
333 359 public function light_switch( $variable, $label, $buttons = [], $reverse = true, $help = '', $strong = false, $attr = [] ) {
334 360 $val = $this->get_field_value( $variable, false );
335 361
@@ -352,9 +378,9 @@
352 378 $val,
353 379 $reverse,
354 380 $help,
355 381 $strong,
356 - $disabled_attribute
382 + $disabled_attribute,
357 383 );
358 384
359 385 // phpcs:ignore WordPress.Security.EscapeOutput -- Reason: All output is properly escaped or hardcoded in the presenter.
360 386 echo $output;
@@ -368,8 +394,10 @@
368 394 *
369 395 * @param string $variable The variable within the option to create the text input field for.
370 396 * @param string $label The label to show for the variable.
371 397 * @param array|string $attr Extra attributes to add to the input field. Can be class, disabled, autocomplete.
398 + *
399 + * @return void
372 400 */
373 401 public function textinput( $variable, $label, $attr = [] ) {
374 402 $type = 'text';
375 403 if ( ! is_array( $attr ) ) {
@@ -395,25 +423,64 @@
395 423 $label,
396 424 [
397 425 'for' => $variable,
398 426 'class' => 'textinput',
399 - ]
427 + ],
400 428 );
401 429
402 - $has_input_error = Yoast_Input_Validation::yoast_form_control_has_error( $variable );
403 430 $aria_attributes = Yoast_Input_Validation::get_the_aria_invalid_attribute( $variable );
404 431
405 - Yoast_Input_Validation::set_error_descriptions();
406 432 $aria_attributes .= Yoast_Input_Validation::get_the_aria_describedby_attribute( $variable );
407 433
408 434 $disabled_attribute = $this->get_disabled_attribute( $variable, $attr );
409 435
410 436 // phpcs:ignore WordPress.Security.EscapeOutput -- Reason: $disabled_attribute output is hardcoded and all other output is properly escaped.
411 - echo '<input' . $attributes . $aria_attributes . ' class="textinput ' . esc_attr( $attr['class'] ) . '" placeholder="' . esc_attr( $attr['placeholder'] ) . '" type="' . $type . '" id="', esc_attr( $variable ), '" name="', esc_attr( $this->option_name ), '[', esc_attr( $variable ), ']" value="', esc_attr( $val ), '"', $disabled_attribute, '/>', '<br class="clear" />';
437 + echo '<input', $attributes, $aria_attributes, ' class="', esc_attr( 'textinput ' . $attr['class'] ), '" placeholder="', esc_attr( $attr['placeholder'] ), '" type="', $type, '" id="', esc_attr( $variable ), '" name="', esc_attr( $this->option_name . '[' . $variable . ']' ), '" value="', esc_attr( $val ), '"', $disabled_attribute, '/>', '<br class="clear" />';
438 + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output escaped in getter.
412 439 echo Yoast_Input_Validation::get_the_error_description( $variable );
413 440 }
414 441
415 442 /**
443 + * Create a Number input field.
444 + *
445 + * @param string $variable The variable within the option to create the text input field for.
446 + * @param string $label The label to show for the variable.
447 + * @param array|string $attr Extra attributes to add to the input field. Can be class, disabled, autocomplete.
448 + *
449 + * @return void
450 + */
451 + public function number( $variable, $label, $attr = [] ) {
452 + $type = 'number';
453 + $defaults = [
454 + 'placeholder' => '',
455 + 'class' => 'number',
456 + 'disabled' => false,
457 + 'min' => 0,
458 + 'max' => 100,
459 + ];
460 + $attr = wp_parse_args( $attr, $defaults );
461 + $val = $this->get_field_value( $variable, 0 );
462 +
463 + $this->label(
464 + $label,
465 + [
466 + 'for' => $variable,
467 + 'class' => 'textinput ' . $attr['class'],
468 + ],
469 + );
470 +
471 + $aria_attributes = Yoast_Input_Validation::get_the_aria_invalid_attribute( $variable );
472 + $aria_attributes .= Yoast_Input_Validation::get_the_aria_describedby_attribute( $variable );
473 +
474 + $disabled_attribute = $this->get_disabled_attribute( $variable, $attr );
475 +
476 + // phpcs:ignore WordPress.Security.EscapeOutput -- Reason: $disabled_attribute output is hardcoded and all other output is properly escaped.
477 + echo '<input' . $aria_attributes . ' class="' . esc_attr( $attr['class'] ) . '" type="' . $type . '" id="', esc_attr( $variable ), '" min="', esc_attr( $attr['min'] ), '" max="', esc_attr( $attr['max'] ), '" name="', esc_attr( $this->option_name . '[' . $variable . ']' ), '" value="', esc_attr( $val ), '"', $disabled_attribute, '/>', '<br class="clear" />';
478 + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Output escaped in getter.
479 + echo Yoast_Input_Validation::get_the_error_description( $variable );
480 + }
481 +
482 + /**
416 483 * Creates a text input field with with the ability to add content after the label.
417 484 *
418 485 * @param string $variable The variable within the option to create the text input field for.
419 486 * @param string $label The label to show for the variable.
@@ -428,9 +495,9 @@
428 495 'class' => 'yoast-field-group__inputfield',
429 496 'disabled' => false,
430 497 ];
431 498
432 - $attr = \wp_parse_args( $attr, $defaults );
499 + $attr = wp_parse_args( $attr, $defaults );
433 500 $val = $this->get_field_value( $variable, '' );
434 501
435 502 if ( isset( $attr['type'] ) && $attr['type'] === 'url' ) {
436 503 $val = urldecode( $val );
@@ -442,9 +509,9 @@
442 509 $label,
443 510 [
444 511 'for' => $variable,
445 512 'class' => $attr['class'] . '--label',
446 - ]
513 + ],
447 514 );
448 515
449 516 if ( isset( $attr['extra_content'] ) ) {
450 517 // phpcs:ignore WordPress.Security.EscapeOutput -- Reason: may contain HTML that should not be escaped.
@@ -451,12 +518,9 @@
451 518 echo $attr['extra_content'];
452 519 }
453 520 echo '</div>';
454 521
455 - $has_input_error = Yoast_Input_Validation::yoast_form_control_has_error( $variable );
456 - $aria_attributes = Yoast_Input_Validation::get_the_aria_invalid_attribute( $variable );
457 -
458 - Yoast_Input_Validation::set_error_descriptions();
522 + $aria_attributes = Yoast_Input_Validation::get_the_aria_invalid_attribute( $variable );
459 523 $aria_attributes .= Yoast_Input_Validation::get_the_aria_describedby_attribute( $variable );
460 524
461 525 // phpcs:disable WordPress.Security.EscapeOutput -- Reason: output is properly escaped or hardcoded.
462 526 printf(
@@ -461,16 +525,16 @@
461 525 // phpcs:disable WordPress.Security.EscapeOutput -- Reason: output is properly escaped or hardcoded.
462 526 printf(
463 527 '<input type="%1$s" name="%2$s" id="%3$s" class="%4$s"%5$s%6$s%7$s value="%8$s"%9$s>',
464 528 $type,
465 - \esc_attr( $this->option_name ) . '[' . \esc_attr( $variable ) . ']',
466 - \esc_attr( $variable ),
467 - \esc_attr( $attr['class'] ),
468 - isset( $attr['placeholder'] ) ? ' placeholder="' . \esc_attr( $attr['placeholder'] ) . '"' : '',
469 - isset( $attr['autocomplete'] ) ? ' autocomplete="' . \esc_attr( $attr['autocomplete'] ) . '"' : '',
529 + esc_attr( $this->option_name . '[' . $variable . ']' ),
530 + esc_attr( $variable ),
531 + esc_attr( $attr['class'] ),
532 + isset( $attr['placeholder'] ) ? ' placeholder="' . esc_attr( $attr['placeholder'] ) . '"' : '',
533 + isset( $attr['autocomplete'] ) ? ' autocomplete="' . esc_attr( $attr['autocomplete'] ) . '"' : '',
470 534 $aria_attributes,
471 - \esc_attr( $val ),
472 - $this->get_disabled_attribute( $variable, $attr )
535 + esc_attr( $val ),
536 + $this->get_disabled_attribute( $variable, $attr ),
473 537 );
474 538 // phpcs:enable
475 539 // phpcs:ignore WordPress.Security.EscapeOutput -- Reason: output is properly escaped.
476 540 echo Yoast_Input_Validation::get_the_error_description( $variable );
@@ -483,8 +547,10 @@
483 547 *
484 548 * @param string $variable The variable within the option to create the textarea for.
485 549 * @param string $label The label to show for the variable.
486 550 * @param string|array $attr The CSS class or an array of attributes to assign to the textarea.
551 + *
552 + * @return void
487 553 */
488 554 public function textarea( $variable, $label, $attr = [] ) {
489 555 if ( ! is_array( $attr ) ) {
490 556 $attr = [
@@ -505,15 +571,15 @@
505 571 $label,
506 572 [
507 573 'for' => $variable,
508 574 'class' => 'textinput',
509 - ]
575 + ],
510 576 );
511 577
512 578 $disabled_attribute = $this->get_disabled_attribute( $variable, $attr );
513 579
514 580 // phpcs:ignore WordPress.Security.EscapeOutput -- Reason: $disabled_attribute output is hardcoded and all other output is properly escaped.
515 - echo '<textarea cols="' . esc_attr( $attr['cols'] ) . '" rows="' . esc_attr( $attr['rows'] ) . '" class="textinput ' . esc_attr( $attr['class'] ) . '" id="' . esc_attr( $variable ) . '" name="' . esc_attr( $this->option_name ) . '[' . esc_attr( $variable ) . ']"', $disabled_attribute, '>' . esc_textarea( $val ) . '</textarea><br class="clear" />';
581 + echo '<textarea cols="' . esc_attr( $attr['cols'] ) . '" rows="' . esc_attr( $attr['rows'] ) . '" class="' . esc_attr( 'textinput ' . $attr['class'] ) . '" id="' . esc_attr( $variable ) . '" name="' . esc_attr( $this->option_name . '[' . $variable . ']' ), '"', $disabled_attribute, '>' . esc_textarea( $val ) . '</textarea><br class="clear" />';
516 582 }
517 583
518 584 /**
519 585 * Create a hidden input field.
@@ -522,13 +588,13 @@
522 588 *
523 589 * @param string $variable The variable within the option to create the hidden input for.
524 590 * @param string $id The ID of the element.
525 591 * @param mixed $val Optional. The value to set in the input field. Otherwise the value from the options will be used.
592 + *
593 + * @return void
526 594 */
527 595 public function hidden( $variable, $id = '', $val = null ) {
528 - if ( is_null( $val ) ) {
529 - $val = $this->get_field_value( $variable, '' );
530 - }
596 + $val ??= $this->get_field_value( $variable, '' );
531 597
532 598 if ( is_bool( $val ) ) {
533 599 $val = ( $val === true ) ? 'true' : 'false';
534 600 }
@@ -536,9 +602,9 @@
536 602 if ( $id === '' ) {
537 603 $id = 'hidden_' . $variable;
538 604 }
539 605
540 - echo '<input type="hidden" id="' . esc_attr( $id ) . '" name="' . esc_attr( $this->option_name ) . '[' . esc_attr( $variable ) . ']" value="' . esc_attr( $val ) . '"/>';
606 + echo '<input type="hidden" id="' . esc_attr( $id ) . '" name="' . esc_attr( $this->option_name . '[' . $variable . ']' ), '" value="' . esc_attr( $val ) . '"/>';
541 607 }
542 608
543 609 /**
544 610 * Create a Select Box.
@@ -551,8 +617,10 @@
551 617 * @param string $styled The select style. Use 'styled' to get a styled select. Default 'unstyled'.
552 618 * @param bool $show_label Whether or not to show the label, if not, it will be applied as an aria-label.
553 619 * @param array $attr Extra attributes to add to the select.
554 620 * @param string $help Optional. Inline Help HTML that will be printed after the label. Default is empty.
621 + *
622 + * @return void
555 623 */
556 624 public function select( $variable, $label, array $select_options, $styled = 'unstyled', $show_label = true, $attr = [], $help = '' ) {
557 625 if ( empty( $select_options ) ) {
558 626 return;
@@ -568,9 +636,9 @@
568 636 $label,
569 637 [
570 638 'for' => $variable,
571 639 'class' => 'select',
572 - ]
640 + ],
573 641 );
574 642 echo $help; // phpcs:ignore WordPress.Security.EscapeOutput -- Reason: The help contains HTML.
575 643 }
576 644
@@ -595,10 +663,12 @@
595 663 $wrapper_start_tag = '<span class="yoast-styled-select">';
596 664 $wrapper_end_tag = '</span>';
597 665 }
598 666
667 + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- output escaped before.
599 668 echo $wrapper_start_tag;
600 669 $select->output_html();
670 + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- output escaped before.
601 671 echo $wrapper_end_tag;
602 672 echo '<br class="clear"/>';
603 673 }
604 674
@@ -609,8 +679,10 @@
609 679 *
610 680 * @param string $variable The variable within the option to create the file upload field for.
611 681 * @param string $label The label to show for the variable.
612 682 * @param array $attr Extra attributes to add to the file upload input.
683 + *
684 + * @return void
613 685 */
614 686 public function file_upload( $variable, $label, $attr = [] ) {
615 687 $val = $this->get_field_value( $variable, '' );
616 688 if ( is_array( $val ) ) {
@@ -627,9 +699,9 @@
627 699 $label,
628 700 [
629 701 'for' => $variable,
630 702 'class' => 'select',
631 - ]
703 + ],
632 704 );
633 705
634 706 $disabled_attribute = $this->get_disabled_attribute( $variable, $attr );
635 707
@@ -648,14 +720,21 @@
648 720 /**
649 721 * Media input.
650 722 *
651 723 * @since 2.0
724 + * @deprecated 23.5
725 + * @codeCoverageIgnore
652 726 *
653 727 * @param string $variable Option name.
654 728 * @param string $label Label message.
655 729 * @param array $attr Extra attributes to add to the media input and buttons.
730 + *
731 + * @return void
656 732 */
657 733 public function media_input( $variable, $label, $attr = [] ) {
734 +
735 + _deprecated_function( __METHOD__, 'Yoast SEO 23.5' );
736 +
658 737 $val = $this->get_field_value( $variable, '' );
659 738 $id_value = $this->get_field_value( $variable . '_id', '' );
660 739
661 740 $var_esc = esc_attr( $variable );
@@ -669,43 +748,26 @@
669 748 $label,
670 749 [
671 750 'for' => 'wpseo_' . $variable,
672 751 'class' => 'select',
673 - ]
752 + ],
674 753 );
675 754
676 755 $id_field_id = 'wpseo_' . $var_esc . '_id';
677 756
678 - $disabled_attribute = $this->get_disabled_attribute( $variable, $attr );
679 -
680 757 echo '<span>';
681 758 echo '<input',
682 759 ' class="textinput"',
683 - ' id="wpseo_', $var_esc, '"',
760 + ' id="wpseo_', $var_esc, '"', // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- output escaped before.
684 761 ' type="text" size="36"',
685 - ' name="', esc_attr( $this->option_name ), '[', $var_esc, ']"',
762 + ' name="', esc_attr( $this->option_name ), '[', $var_esc, ']"', // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- output escaped before.
686 763 ' value="', esc_attr( $val ), '"',
687 764 ' readonly="readonly"',
688 765 ' /> ';
689 766 echo '<input',
690 - ' id="wpseo_', $var_esc, '_button"',
691 - ' class="wpseo_image_upload_button button"',
692 - ' type="button"',
693 - ' value="', esc_attr__( 'Upload Image', 'wordpress-seo' ), '"',
694 - ' data-target-id="', esc_attr( $id_field_id ), '"',
695 - // phpcs:ignore WordPress.Security.EscapeOutput -- Reason: $disabled_attribute output is hardcoded.
696 - $disabled_attribute,
697 - ' /> ';
698 - echo '<input',
699 - ' class="wpseo_image_remove_button button"',
700 - ' type="button"',
701 - ' value="', esc_attr__( 'Clear Image', 'wordpress-seo' ), '"',
702 - // phpcs:ignore WordPress.Security.EscapeOutput -- Reason: $disabled_attribute output is hardcoded.
703 - $disabled_attribute,
704 - ' />';
705 - echo '<input',
706 767 ' type="hidden"',
707 768 ' id="', esc_attr( $id_field_id ), '"',
769 + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- output escaped before.
708 770 ' name="', esc_attr( $this->option_name ), '[', $var_esc, '_id]"',
709 771 ' value="', esc_attr( $id_value ), '"',
710 772 ' />';
711 773 echo '</span>';
@@ -721,8 +783,10 @@
721 783 * @param array $values The radio options to choose from.
722 784 * @param string $legend Optional. The legend to show for the field set, if any.
723 785 * @param array $legend_attr Optional. The attributes for the legend, if any.
724 786 * @param array $attr Extra attributes to add to the radio button.
787 + *
788 + * @return void
725 789 */
726 790 public function radio( $variable, $values, $legend = '', $legend_attr = [], $attr = [] ) {
727 791 if ( ! is_array( $values ) || $values === [] ) {
728 792 return;
@@ -735,8 +799,9 @@
735 799 'disabled' => false,
736 800 ];
737 801 $attr = wp_parse_args( $attr, $defaults );
738 802
803 + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- output escaped before.
739 804 echo '<fieldset class="yoast-form-fieldset wpseo_radio_block" id="' . $var_esc . '">';
740 805
741 806 if ( is_string( $legend ) && $legend !== '' ) {
742 807
@@ -754,10 +819,10 @@
754 819 $label = $value;
755 820 $aria_label = '';
756 821
757 822 if ( is_array( $value ) ) {
758 - $label = isset( $value['label'] ) ? $value['label'] : '';
759 - $aria_label = isset( $value['aria_label'] ) ? $value['aria_label'] : '';
823 + $label = ( $value['label'] ?? '' );
824 + $aria_label = ( $value['aria_label'] ?? '' );
760 825 }
761 826
762 827 $key_esc = esc_attr( $key );
763 828
@@ -770,9 +835,9 @@
770 835 [
771 836 'for' => $var_esc . '-' . $key_esc,
772 837 'class' => 'radio',
773 838 'aria_label' => $aria_label,
774 - ]
839 + ],
775 840 );
776 841 }
777 842 echo '</fieldset>';
778 843 }
@@ -788,8 +853,10 @@
788 853 * value can be an array of visible label text and screen reader text.
789 854 * @param string $label The visual label for the radio buttons group, used as the fieldset legend.
790 855 * @param string $help Inline Help that will be printed out before the visible toggles text.
791 856 * @param array $attr Extra attributes to add to the toggle switch.
857 + *
858 + * @return void
792 859 */
793 860 public function toggle_switch( $variable, $values, $label, $help = '', $attr = [] ) {
794 861 if ( ! is_array( $values ) || $values === [] ) {
795 862 return;
@@ -799,8 +866,13 @@
799 866 'disabled' => false,
800 867 ];
801 868 $attr = wp_parse_args( $attr, $defaults );
802 869
870 + if ( isset( $attr['preserve_disabled_value'] ) && $attr['preserve_disabled_value'] ) {
871 + $this->hidden( $variable );
872 + $variable .= '_disabled';
873 + }
874 +
803 875 $val = $this->get_field_value( $variable, false );
804 876 if ( $val === true ) {
805 877 $val = 'on';
806 878 }
@@ -809,16 +881,27 @@
809 881 }
810 882
811 883 $help_class = ! empty( $help ) ? ' switch-container__has-help' : '';
812 884
885 + $has_premium_upsell = ( isset( $attr['show_premium_upsell'] ) && $attr['show_premium_upsell'] && isset( $attr['premium_upsell_url'] ) && ! empty( $attr['premium_upsell_url'] ) );
886 + $upsell_class = ( $has_premium_upsell ) ? ' premium-upsell' : '';
887 +
813 888 $var_esc = esc_attr( $variable );
814 889
815 - printf( '<div class="%s">', esc_attr( 'switch-container' . $help_class ) );
890 + printf( '<div class="%s">', esc_attr( 'switch-container' . $help_class . $upsell_class ) );
891 + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- output escaped before.
816 892 echo '<fieldset id="', $var_esc, '" class="fieldset-switch-toggle"><legend>', $label, '</legend>', $help;
817 893
818 894 // Show disabled note if attribute does not exists or does exist and is set to true.
819 895 if ( ! isset( $attr['show_disabled_note'] ) || ( $attr['show_disabled_note'] === true ) ) {
820 - echo $this->get_disabled_note( $variable );
896 + if ( isset( $attr['note_when_disabled'] ) ) {
897 + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- output escaped before.
898 + echo $this->get_disabled_note( $variable, $attr['note_when_disabled'] );
899 + }
900 + else {
901 + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- output escaped before.
902 + echo $this->get_disabled_note( $variable );
903 + }
821 904 }
822 905
823 906 echo '<div class="switch-toggle switch-candy switch-yoast-seo">';
824 907
@@ -836,12 +919,24 @@
836 919 $disabled_attribute = $this->get_disabled_attribute( $variable, $attr );
837 920
838 921 // phpcs:ignore WordPress.Security.EscapeOutput -- Reason: $disabled_attribute output is hardcoded and all other output is properly escaped.
839 922 echo '<input type="radio" id="' . $for . '" name="' . esc_attr( $this->option_name ) . '[' . $var_esc . ']" value="' . $key_esc . '" ' . checked( $val, $key_esc, false ) . $disabled_attribute . ' />',
923 + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- output escaped before.
840 924 '<label for="', $for, '">', esc_html( $value ), $screen_reader_text_html, '</label>';
841 925 }
842 926
843 - echo '<a></a></div></fieldset><div class="clear"></div></div>' . PHP_EOL . PHP_EOL;
927 + $upsell_button = '';
928 + if ( $has_premium_upsell ) {
929 + $upsell_button = '<a class="yoast-button yoast-button--buy yoast-button--small" data-action="load-nfd-ctb" data-ctb-id="f6a84663-465f-4cb5-8ba5-f7a6d72224b2" href='
930 + . esc_url( $attr['premium_upsell_url'] ) . ' target="_blank">'
931 + . esc_html__( 'Unlock with Premium!', 'wordpress-seo' )
932 + /* translators: Hidden accessibility text. */
933 + . '<span class="screen-reader-text">' . esc_html__( '(Opens in a new browser tab)', 'wordpress-seo' ) . '</span>'
934 + . '<span aria-hidden="true" class="yoast-button--buy__caret"></span></a>';
935 + }
936 +
937 + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- All variable output is escaped above.
938 + echo '<a></a></div></fieldset><div class="clear"></div>' . $upsell_button . '</div>' . PHP_EOL . PHP_EOL;
844 939 }
845 940
846 941 /**
847 942 * Creates a toggle switch to define whether an indexable should be indexed or not.
@@ -871,12 +966,12 @@
871 966 $index_switch_values,
872 967 sprintf(
873 968 /* translators: %s expands to an indexable object's name, like a post type or taxonomy */
874 969 esc_html__( 'Show %s in search results?', 'wordpress-seo' ),
875 - $label
970 + $label,
876 971 ),
877 972 $help,
878 - [ 'disabled' => $is_disabled ]
973 + [ 'disabled' => $is_disabled ],
879 974 );
880 975 }
881 976
882 977 /**
@@ -910,9 +1005,9 @@
910 1005 $variable,
911 1006 $show_hide_switch,
912 1007 $label,
913 1008 $help,
914 - [ 'disabled' => $is_disabled ]
1009 + [ 'disabled' => $is_disabled ],
915 1010 );
916 1011 }
917 1012
918 1013 /**
@@ -954,17 +1049,17 @@
954 1049
955 1050 /**
956 1051 * Gets the explanation note to print if a given control is disabled.
957 1052 *
958 - * @param string $variable The variable within the option to print a disabled note for.
1053 + * @param string $variable The variable within the option to print a disabled note for.
1054 + * @param string $custom_note An optional custom note to print instead.
959 1055 *
960 1056 * @return string Explanation note HTML string, or empty string if no note necessary.
961 1057 */
962 - protected function get_disabled_note( $variable ) {
963 - if ( ! $this->is_control_disabled( $variable ) ) {
1058 + protected function get_disabled_note( $variable, $custom_note = '' ) {
1059 + if ( $custom_note === '' && ! $this->is_control_disabled( $variable ) ) {
964 1060 return '';
965 1061 }
966 -
967 1062 $disabled_message = esc_html__( 'This feature has been disabled by the network admin.', 'wordpress-seo' );
968 1063
969 1064 // The explanation to show when disabling the Usage tracking feature for multisite subsites.
970 1065 if ( $this->is_tracking_on_subsite( $variable ) ) {
@@ -969,8 +1064,13 @@
969 1064 // The explanation to show when disabling the Usage tracking feature for multisite subsites.
970 1065 if ( $this->is_tracking_on_subsite( $variable ) ) {
971 1066 $disabled_message = esc_html__( 'This feature has been disabled since subsites never send tracking data.', 'wordpress-seo' );
972 1067 }
1068 +
1069 + if ( $custom_note ) {
1070 + $disabled_message = esc_html( $custom_note );
1071 + }
1072 +
973 1073 return '<p class="disabled-note">' . $disabled_message . '</p>';
974 1074 }
975 1075
976 1076 /**