class-yoast-form.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813
  1. <?php
  2. /**
  3. * WPSEO plugin file.
  4. *
  5. * @package WPSEO\Admin
  6. */
  7. /**
  8. * Admin form class.
  9. *
  10. * @since 2.0
  11. */
  12. class Yoast_Form {
  13. /**
  14. * Instance of this class
  15. *
  16. * @var object
  17. * @since 2.0
  18. */
  19. public static $instance;
  20. /**
  21. * The short name of the option to use for the current page.
  22. *
  23. * @var string
  24. * @since 2.0
  25. */
  26. public $option_name;
  27. /**
  28. * Option values for the WPSEO_Options.
  29. *
  30. * @var array
  31. * @since 2.0
  32. */
  33. public $options = [];
  34. /**
  35. * Option instance.
  36. *
  37. * @since 8.4
  38. * @var WPSEO_Option|null
  39. */
  40. protected $option_instance = null;
  41. /**
  42. * Get the singleton instance of this class.
  43. *
  44. * @since 2.0
  45. *
  46. * @return Yoast_Form
  47. */
  48. public static function get_instance() {
  49. if ( ! ( self::$instance instanceof self ) ) {
  50. self::$instance = new self();
  51. }
  52. return self::$instance;
  53. }
  54. /**
  55. * Generates the header for admin pages.
  56. *
  57. * @since 2.0
  58. *
  59. * @param bool $form Whether or not the form start tag should be included.
  60. * @param string $option The short name of the option to use for the current page.
  61. * @param bool $contains_files Whether the form should allow for file uploads.
  62. * @param bool $option_long_name Group name of the option.
  63. */
  64. public function admin_header( $form = true, $option = 'wpseo', $contains_files = false, $option_long_name = false ) {
  65. if ( ! $option_long_name ) {
  66. $option_long_name = WPSEO_Options::get_group_name( $option );
  67. }
  68. ?>
  69. <div class="wrap yoast wpseo-admin-page <?php echo esc_attr( 'page-' . $option ); ?>">
  70. <?php
  71. /**
  72. * Display the updated/error messages.
  73. * Only needed as our settings page is not under options, otherwise it will automatically be included.
  74. *
  75. * @see settings_errors()
  76. */
  77. require_once ABSPATH . 'wp-admin/options-head.php';
  78. ?>
  79. <h1 id="wpseo-title"><?php echo esc_html( get_admin_page_title() ); ?></h1>
  80. <div class="wpseo_content_wrapper">
  81. <div class="wpseo_content_cell" id="wpseo_content_top">
  82. <?php
  83. if ( $form === true ) {
  84. $enctype = ( $contains_files ) ? ' enctype="multipart/form-data"' : '';
  85. $network_admin = new Yoast_Network_Admin();
  86. if ( $network_admin->meets_requirements() ) {
  87. $action_url = network_admin_url( 'settings.php' );
  88. $hidden_fields_cb = [ $network_admin, 'settings_fields' ];
  89. }
  90. else {
  91. $action_url = admin_url( 'options.php' );
  92. $hidden_fields_cb = 'settings_fields';
  93. }
  94. echo '<form action="' . esc_url( $action_url ) . '" method="post" id="wpseo-conf"' . $enctype . ' accept-charset="' . esc_attr( get_bloginfo( 'charset' ) ) . '">';
  95. call_user_func( $hidden_fields_cb, $option_long_name );
  96. }
  97. $this->set_option( $option );
  98. }
  99. /**
  100. * Set the option used in output for form elements.
  101. *
  102. * @since 2.0
  103. *
  104. * @param string $option_name Option key.
  105. */
  106. public function set_option( $option_name ) {
  107. $this->option_name = $option_name;
  108. $this->options = WPSEO_Options::get_option( $option_name );
  109. if ( $this->options === null ) {
  110. $this->options = (array) get_option( $option_name, [] );
  111. }
  112. $this->option_instance = WPSEO_Options::get_option_instance( $option_name );
  113. if ( ! $this->option_instance ) {
  114. $this->option_instance = null;
  115. }
  116. }
  117. /**
  118. * Sets a value in the options.
  119. *
  120. * @since 5.4
  121. *
  122. * @param string $key The key of the option to set.
  123. * @param mixed $value The value to set the option to.
  124. * @param bool $overwrite Whether to overwrite existing options. Default is false.
  125. */
  126. public function set_options_value( $key, $value, $overwrite = false ) {
  127. if ( $overwrite || ! array_key_exists( $key, $this->options ) ) {
  128. $this->options[ $key ] = $value;
  129. }
  130. }
  131. /**
  132. * Generates the footer for admin pages.
  133. *
  134. * @since 2.0
  135. *
  136. * @param bool $submit Whether or not a submit button and form end tag should be shown.
  137. * @param bool $show_sidebar Whether or not to show the banner sidebar - used by premium plugins to disable it.
  138. */
  139. public function admin_footer( $submit = true, $show_sidebar = true ) {
  140. if ( $submit ) {
  141. $settings_changed_listener = new WPSEO_Admin_Settings_Changed_Listener();
  142. echo '<div id="wpseo-submit-container">';
  143. echo '<div id="wpseo-submit-container-float" class="wpseo-admin-submit">';
  144. submit_button( __( 'Save changes', 'wordpress-seo' ) );
  145. $settings_changed_listener->show_success_message();
  146. echo '</div>';
  147. echo '<div id="wpseo-submit-container-fixed" class="wpseo-admin-submit wpseo-admin-submit-fixed" style="display: none;">';
  148. submit_button( __( 'Save changes', 'wordpress-seo' ) );
  149. $settings_changed_listener->show_success_message();
  150. echo '</div>';
  151. echo '</div>';
  152. echo '
  153. </form>';
  154. }
  155. /**
  156. * Apply general admin_footer hooks.
  157. */
  158. do_action( 'wpseo_admin_footer', $this );
  159. /**
  160. * Run possibly set actions to add for example an i18n box.
  161. */
  162. do_action( 'wpseo_admin_promo_footer' );
  163. echo '
  164. </div><!-- end of div wpseo_content_top -->';
  165. if ( $show_sidebar ) {
  166. $this->admin_sidebar();
  167. }
  168. echo '</div><!-- end of div wpseo_content_wrapper -->';
  169. do_action( 'wpseo_admin_below_content', $this );
  170. echo '
  171. </div><!-- end of wrap -->';
  172. }
  173. /**
  174. * Generates the sidebar for admin pages.
  175. *
  176. * @since 2.0
  177. */
  178. public function admin_sidebar() {
  179. // No banners in Premium.
  180. $addon_manager = new WPSEO_Addon_Manager();
  181. if ( WPSEO_Utils::is_yoast_seo_premium() && $addon_manager->has_valid_subscription( WPSEO_Addon_Manager::PREMIUM_SLUG ) ) {
  182. return;
  183. }
  184. require_once 'views/sidebar.php';
  185. }
  186. /**
  187. * Output a label element.
  188. *
  189. * @since 2.0
  190. *
  191. * @param string $text Label text string.
  192. * @param array $attr HTML attributes set.
  193. */
  194. public function label( $text, $attr ) {
  195. $defaults = [
  196. 'class' => 'checkbox',
  197. 'close' => true,
  198. 'for' => '',
  199. 'aria_label' => '',
  200. ];
  201. $attr = wp_parse_args( $attr, $defaults );
  202. $aria_label = '';
  203. if ( $attr['aria_label'] !== '' ) {
  204. $aria_label = ' aria-label="' . esc_attr( $attr['aria_label'] ) . '"';
  205. }
  206. echo "<label class='" . esc_attr( $attr['class'] ) . "' for='" . esc_attr( $attr['for'] ) . "'$aria_label>$text";
  207. if ( $attr['close'] ) {
  208. echo '</label>';
  209. }
  210. }
  211. /**
  212. * Output a legend element.
  213. *
  214. * @since 3.4
  215. *
  216. * @param string $text Legend text string.
  217. * @param array $attr HTML attributes set.
  218. */
  219. public function legend( $text, $attr ) {
  220. $defaults = [
  221. 'id' => '',
  222. 'class' => '',
  223. ];
  224. $attr = wp_parse_args( $attr, $defaults );
  225. $id = ( '' === $attr['id'] ) ? '' : ' id="' . esc_attr( $attr['id'] ) . '"';
  226. echo '<legend class="yoast-form-legend ' . esc_attr( $attr['class'] ) . '"' . $id . '>' . $text . '</legend>';
  227. }
  228. /**
  229. * Create a Checkbox input field.
  230. *
  231. * @since 2.0
  232. *
  233. * @param string $var The variable within the option to create the checkbox for.
  234. * @param string $label The label to show for the variable.
  235. * @param bool $label_left Whether the label should be left (true) or right (false).
  236. */
  237. public function checkbox( $var, $label, $label_left = false ) {
  238. if ( ! isset( $this->options[ $var ] ) ) {
  239. $this->options[ $var ] = false;
  240. }
  241. if ( $this->options[ $var ] === true ) {
  242. $this->options[ $var ] = 'on';
  243. }
  244. $class = '';
  245. if ( $label_left !== false ) {
  246. $this->label( $label_left, [ 'for' => $var ] );
  247. }
  248. else {
  249. $class = 'double';
  250. }
  251. echo '<input class="checkbox ', esc_attr( $class ), '" type="checkbox" id="', esc_attr( $var ), '" name="', esc_attr( $this->option_name ), '[', esc_attr( $var ), ']" value="on"', checked( $this->options[ $var ], 'on', false ), disabled( $this->is_control_disabled( $var ), true, false ), '/>';
  252. if ( ! empty( $label ) ) {
  253. $this->label( $label, [ 'for' => $var ] );
  254. }
  255. echo '<br class="clear" />';
  256. }
  257. /**
  258. * Create a light switch input field using a single checkbox.
  259. *
  260. * @since 3.1
  261. *
  262. * @param string $var The variable within the option to create the checkbox for.
  263. * @param string $label The label element text for the checkbox.
  264. * @param array $buttons Array of two visual labels for the buttons (defaults Disabled/Enabled).
  265. * @param bool $reverse Reverse order of buttons (default true).
  266. * @param string $help Inline Help that will be printed out before the visible toggles text.
  267. * @param bool $strong Whether the visual label is displayed in strong text. Default is false.
  268. */
  269. public function light_switch( $var, $label, $buttons = [], $reverse = true, $help = '', $strong = false ) {
  270. if ( ! isset( $this->options[ $var ] ) ) {
  271. $this->options[ $var ] = false;
  272. }
  273. if ( $this->options[ $var ] === true ) {
  274. $this->options[ $var ] = 'on';
  275. }
  276. $class = 'switch-light switch-candy switch-yoast-seo';
  277. if ( $reverse ) {
  278. $class .= ' switch-yoast-seo-reverse';
  279. }
  280. if ( empty( $buttons ) ) {
  281. $buttons = [ __( 'Disabled', 'wordpress-seo' ), __( 'Enabled', 'wordpress-seo' ) ];
  282. }
  283. list( $off_button, $on_button ) = $buttons;
  284. $help_class = '';
  285. $screen_reader_text_class = '';
  286. $help_class = ! empty( $help ) ? ' switch-container__has-help' : '';
  287. $strong_class = ( $strong ) ? ' switch-light-visual-label__strong' : '';
  288. echo '<div class="switch-container', $help_class, '">',
  289. '<span class="switch-light-visual-label' . $strong_class . '" id="', esc_attr( $var . '-label' ), '">', esc_html( $label ), '</span>' . $help,
  290. '<label class="', $class, '"><b class="switch-yoast-seo-jaws-a11y">&nbsp;</b>',
  291. '<input type="checkbox" aria-labelledby="', esc_attr( $var . '-label' ), '" id="', esc_attr( $var ), '" name="', esc_attr( $this->option_name ), '[', esc_attr( $var ), ']" value="on"', checked( $this->options[ $var ], 'on', false ), disabled( $this->is_control_disabled( $var ), true, false ), '/>',
  292. '<span aria-hidden="true">
  293. <span>', esc_html( $off_button ) ,'</span>
  294. <span>', esc_html( $on_button ) ,'</span>
  295. <a></a>
  296. </span>
  297. </label><div class="clear"></div></div>';
  298. }
  299. /**
  300. * Create a Text input field.
  301. *
  302. * @since 2.0
  303. * @since 2.1 Introduced the `$attr` parameter.
  304. *
  305. * @param string $var The variable within the option to create the text input field for.
  306. * @param string $label The label to show for the variable.
  307. * @param array|string $attr Extra attributes to add to the input field. Can be class, disabled, autocomplete.
  308. */
  309. public function textinput( $var, $label, $attr = [] ) {
  310. if ( ! is_array( $attr ) ) {
  311. $attr = [
  312. 'class' => $attr,
  313. 'disabled' => false,
  314. ];
  315. }
  316. $defaults = [
  317. 'placeholder' => '',
  318. 'class' => '',
  319. ];
  320. $attr = wp_parse_args( $attr, $defaults );
  321. $val = isset( $this->options[ $var ] ) ? $this->options[ $var ] : '';
  322. $attributes = isset( $attr['autocomplete'] ) ? ' autocomplete="' . esc_attr( $attr['autocomplete'] ) . '"' : '';
  323. if ( isset( $attr['disabled'] ) && $attr['disabled'] ) {
  324. $attributes .= ' disabled';
  325. }
  326. $this->label(
  327. $label,
  328. [
  329. 'for' => $var,
  330. 'class' => 'textinput',
  331. ]
  332. );
  333. $has_input_error = Yoast_Input_Validation::yoast_form_control_has_error( $var );
  334. $aria_attributes = Yoast_Input_Validation::get_the_aria_invalid_attribute( $var );
  335. Yoast_Input_Validation::set_error_descriptions();
  336. $aria_attributes .= Yoast_Input_Validation::get_the_aria_describedby_attribute( $var );
  337. echo '<input' . $attributes . $aria_attributes . ' class="textinput ' . esc_attr( $attr['class'] ) . '" placeholder="' . esc_attr( $attr['placeholder'] ) . '" type="text" id="', esc_attr( $var ), '" name="', esc_attr( $this->option_name ), '[', esc_attr( $var ), ']" value="', esc_attr( $val ), '"', disabled( $this->is_control_disabled( $var ), true, false ), '/>', '<br class="clear" />';
  338. echo Yoast_Input_Validation::get_the_error_description( $var );
  339. }
  340. /**
  341. * Create a textarea.
  342. *
  343. * @since 2.0
  344. *
  345. * @param string $var The variable within the option to create the textarea for.
  346. * @param string $label The label to show for the variable.
  347. * @param string|array $attr The CSS class or an array of attributes to assign to the textarea.
  348. */
  349. public function textarea( $var, $label, $attr = [] ) {
  350. if ( ! is_array( $attr ) ) {
  351. $attr = [
  352. 'class' => $attr,
  353. ];
  354. }
  355. $defaults = [
  356. 'cols' => '',
  357. 'rows' => '',
  358. 'class' => '',
  359. ];
  360. $attr = wp_parse_args( $attr, $defaults );
  361. $val = ( isset( $this->options[ $var ] ) ) ? $this->options[ $var ] : '';
  362. $this->label(
  363. $label,
  364. [
  365. 'for' => $var,
  366. 'class' => 'textinput',
  367. ]
  368. );
  369. echo '<textarea cols="' . esc_attr( $attr['cols'] ) . '" rows="' . esc_attr( $attr['rows'] ) . '" class="textinput ' . esc_attr( $attr['class'] ) . '" id="' . esc_attr( $var ) . '" name="' . esc_attr( $this->option_name ) . '[' . esc_attr( $var ) . ']"', disabled( $this->is_control_disabled( $var ), true, false ), '>' . esc_textarea( $val ) . '</textarea><br class="clear" />';
  370. }
  371. /**
  372. * Create a hidden input field.
  373. *
  374. * @since 2.0
  375. *
  376. * @param string $var The variable within the option to create the hidden input for.
  377. * @param string $id The ID of the element.
  378. */
  379. public function hidden( $var, $id = '' ) {
  380. $val = ( isset( $this->options[ $var ] ) ) ? $this->options[ $var ] : '';
  381. if ( is_bool( $val ) ) {
  382. $val = ( $val === true ) ? 'true' : 'false';
  383. }
  384. if ( '' === $id ) {
  385. $id = 'hidden_' . $var;
  386. }
  387. echo '<input type="hidden" id="' . esc_attr( $id ) . '" name="' . esc_attr( $this->option_name ) . '[' . esc_attr( $var ) . ']" value="' . esc_attr( $val ) . '"/>';
  388. }
  389. /**
  390. * Create a Select Box.
  391. *
  392. * @since 2.0
  393. *
  394. * @param string $var The variable within the option to create the select for.
  395. * @param string $label The label to show for the variable.
  396. * @param array $select_options The select options to choose from.
  397. * @param string $styled The select style. Use 'styled' to get a styled select. Default 'unstyled'.
  398. * @param bool $show_label Whether or not to show the label, if not, it will be applied as an aria-label.
  399. */
  400. public function select( $var, $label, array $select_options, $styled = 'unstyled', $show_label = true ) {
  401. if ( empty( $select_options ) ) {
  402. return;
  403. }
  404. if ( $show_label ) {
  405. $this->label(
  406. $label,
  407. [
  408. 'for' => $var,
  409. 'class' => 'select',
  410. ]
  411. );
  412. }
  413. $select_name = esc_attr( $this->option_name ) . '[' . esc_attr( $var ) . ']';
  414. $active_option = ( isset( $this->options[ $var ] ) ) ? $this->options[ $var ] : '';
  415. $wrapper_start_tag = '';
  416. $wrapper_end_tag = '';
  417. $select = new Yoast_Input_Select( $var, $select_name, $select_options, $active_option );
  418. $select->add_attribute( 'class', 'select' );
  419. if ( $this->is_control_disabled( $var ) ) {
  420. $select->add_attribute( 'disabled', 'disabled' );
  421. }
  422. if ( ! $show_label ) {
  423. $select->add_attribute( 'aria-label', $label );
  424. }
  425. if ( $styled === 'styled' ) {
  426. $wrapper_start_tag = '<span class="yoast-styled-select">';
  427. $wrapper_end_tag = '</span>';
  428. }
  429. echo $wrapper_start_tag;
  430. $select->output_html();
  431. echo $wrapper_end_tag;
  432. echo '<br class="clear"/>';
  433. }
  434. /**
  435. * Create a File upload field.
  436. *
  437. * @since 2.0
  438. *
  439. * @param string $var The variable within the option to create the file upload field for.
  440. * @param string $label The label to show for the variable.
  441. */
  442. public function file_upload( $var, $label ) {
  443. $val = '';
  444. if ( isset( $this->options[ $var ] ) && is_array( $this->options[ $var ] ) ) {
  445. $val = $this->options[ $var ]['url'];
  446. }
  447. $var_esc = esc_attr( $var );
  448. $this->label(
  449. $label,
  450. [
  451. 'for' => $var,
  452. 'class' => 'select',
  453. ]
  454. );
  455. echo '<input type="file" value="' . esc_attr( $val ) . '" class="textinput" name="' . esc_attr( $this->option_name ) . '[' . $var_esc . ']" id="' . $var_esc . '"', disabled( $this->is_control_disabled( $var ), true, false ), '/>';
  456. // Need to save separate array items in hidden inputs, because empty file inputs type will be deleted by settings API.
  457. if ( ! empty( $this->options[ $var ] ) ) {
  458. $this->hidden( 'file', $this->option_name . '_file' );
  459. $this->hidden( 'url', $this->option_name . '_url' );
  460. $this->hidden( 'type', $this->option_name . '_type' );
  461. }
  462. echo '<br class="clear"/>';
  463. }
  464. /**
  465. * Media input.
  466. *
  467. * @since 2.0
  468. *
  469. * @param string $var Option name.
  470. * @param string $label Label message.
  471. */
  472. public function media_input( $var, $label ) {
  473. $val = '';
  474. if ( isset( $this->options[ $var ] ) ) {
  475. $val = $this->options[ $var ];
  476. }
  477. $id_value = '';
  478. if ( isset( $this->options[ $var . '_id' ] ) ) {
  479. $id_value = $this->options[ $var . '_id' ];
  480. }
  481. $var_esc = esc_attr( $var );
  482. $this->label(
  483. $label,
  484. [
  485. 'for' => 'wpseo_' . $var,
  486. 'class' => 'select',
  487. ]
  488. );
  489. $id_field_id = 'wpseo_' . $var_esc . '_id';
  490. echo '<span>';
  491. echo '<input',
  492. ' class="textinput"',
  493. ' id="wpseo_', $var_esc, '"',
  494. ' type="text" size="36"',
  495. ' name="', esc_attr( $this->option_name ), '[', $var_esc, ']"',
  496. ' value="', esc_attr( $val ), '"',
  497. ' readonly="readonly"',
  498. ' /> ';
  499. echo '<input',
  500. ' id="wpseo_', $var_esc, '_button"',
  501. ' class="wpseo_image_upload_button button"',
  502. ' type="button"',
  503. ' value="', esc_attr__( 'Upload Image', 'wordpress-seo' ), '"',
  504. ' data-target-id="', esc_attr( $id_field_id ), '"',
  505. disabled( $this->is_control_disabled( $var ), true, false ),
  506. ' /> ';
  507. echo '<input',
  508. ' class="wpseo_image_remove_button button"',
  509. ' type="button"',
  510. ' value="', esc_attr__( 'Clear Image', 'wordpress-seo' ), '"',
  511. disabled( $this->is_control_disabled( $var ), true, false ),
  512. ' />';
  513. echo '<input',
  514. ' type="hidden"',
  515. ' id="', esc_attr( $id_field_id ), '"',
  516. ' name="', esc_attr( $this->option_name ), '[', $var_esc, '_id]"',
  517. ' value="', esc_attr( $id_value ), '"',
  518. ' />';
  519. echo '</span>';
  520. echo '<br class="clear"/>';
  521. }
  522. /**
  523. * Create a Radio input field.
  524. *
  525. * @since 2.0
  526. *
  527. * @param string $var The variable within the option to create the radio button for.
  528. * @param array $values The radio options to choose from.
  529. * @param string $legend Optional. The legend to show for the field set, if any.
  530. * @param array $legend_attr Optional. The attributes for the legend, if any.
  531. */
  532. public function radio( $var, $values, $legend = '', $legend_attr = [] ) {
  533. if ( ! is_array( $values ) || $values === [] ) {
  534. return;
  535. }
  536. if ( ! isset( $this->options[ $var ] ) ) {
  537. $this->options[ $var ] = false;
  538. }
  539. $var_esc = esc_attr( $var );
  540. echo '<fieldset class="yoast-form-fieldset wpseo_radio_block" id="' . $var_esc . '">';
  541. if ( is_string( $legend ) && '' !== $legend ) {
  542. $defaults = [
  543. 'id' => '',
  544. 'class' => 'radiogroup',
  545. ];
  546. $legend_attr = wp_parse_args( $legend_attr, $defaults );
  547. $this->legend( $legend, $legend_attr );
  548. }
  549. foreach ( $values as $key => $value ) {
  550. $label = $value;
  551. $aria_label = '';
  552. if ( is_array( $value ) ) {
  553. $label = isset( $value['label'] ) ? $value['label'] : '';
  554. $aria_label = isset( $value['aria_label'] ) ? $value['aria_label'] : '';
  555. }
  556. $key_esc = esc_attr( $key );
  557. echo '<input type="radio" class="radio" id="' . $var_esc . '-' . $key_esc . '" name="' . esc_attr( $this->option_name ) . '[' . $var_esc . ']" value="' . $key_esc . '" ' . checked( $this->options[ $var ], $key_esc, false ) . disabled( $this->is_control_disabled( $var ), true, false ) . ' />';
  558. $this->label(
  559. $label,
  560. [
  561. 'for' => $var_esc . '-' . $key_esc,
  562. 'class' => 'radio',
  563. 'aria_label' => $aria_label,
  564. ]
  565. );
  566. }
  567. echo '</fieldset>';
  568. }
  569. /**
  570. * Create a toggle switch input field using two radio buttons.
  571. *
  572. * @since 3.1
  573. *
  574. * @param string $var The variable within the option to create the radio buttons for.
  575. * @param array $values Associative array of on/off keys and their values to be used as
  576. * the label elements text for the radio buttons. Optionally, each
  577. * value can be an array of visible label text and screen reader text.
  578. * @param string $label The visual label for the radio buttons group, used as the fieldset legend.
  579. * @param string $help Inline Help that will be printed out before the visible toggles text.
  580. */
  581. public function toggle_switch( $var, $values, $label, $help = '' ) {
  582. if ( ! is_array( $values ) || $values === [] ) {
  583. return;
  584. }
  585. if ( ! isset( $this->options[ $var ] ) ) {
  586. $this->options[ $var ] = false;
  587. }
  588. if ( $this->options[ $var ] === true ) {
  589. $this->options[ $var ] = 'on';
  590. }
  591. if ( $this->options[ $var ] === false ) {
  592. $this->options[ $var ] = 'off';
  593. }
  594. $help_class = ! empty( $help ) ? ' switch-container__has-help' : '';
  595. $var_esc = esc_attr( $var );
  596. printf( '<div class="%s">', esc_attr( 'switch-container' . $help_class ) );
  597. echo '<fieldset id="', $var_esc, '" class="fieldset-switch-toggle"><legend>', $label, '</legend>', $help;
  598. echo $this->get_disabled_note( $var );
  599. echo '<div class="switch-toggle switch-candy switch-yoast-seo">';
  600. foreach ( $values as $key => $value ) {
  601. $screen_reader_text_html = '';
  602. if ( is_array( $value ) ) {
  603. $screen_reader_text = $value['screen_reader_text'];
  604. $screen_reader_text_html = '<span class="screen-reader-text"> ' . esc_html( $screen_reader_text ) . '</span>';
  605. $value = $value['text'];
  606. }
  607. $key_esc = esc_attr( $key );
  608. $for = $var_esc . '-' . $key_esc;
  609. echo '<input type="radio" id="' . $for . '" name="' . esc_attr( $this->option_name ) . '[' . $var_esc . ']" value="' . $key_esc . '" ' . checked( $this->options[ $var ], $key_esc, false ) . disabled( $this->is_control_disabled( $var ), true, false ) . ' />',
  610. '<label for="', $for, '">', esc_html( $value ), $screen_reader_text_html,'</label>';
  611. }
  612. echo '<a></a></div></fieldset><div class="clear"></div></div>' . PHP_EOL . PHP_EOL;
  613. }
  614. /**
  615. * Creates a toggle switch to define whether an indexable should be indexed or not.
  616. *
  617. * @param string $var The variable within the option to create the radio buttons for.
  618. * @param string $label The visual label for the radio buttons group, used as the fieldset legend.
  619. * @param string $help Inline Help that will be printed out before the visible toggles text.
  620. *
  621. * @return void
  622. */
  623. public function index_switch( $var, $label, $help = '' ) {
  624. $index_switch_values = [
  625. 'off' => __( 'Yes', 'wordpress-seo' ),
  626. 'on' => __( 'No', 'wordpress-seo' ),
  627. ];
  628. $this->toggle_switch(
  629. $var,
  630. $index_switch_values,
  631. sprintf(
  632. /* translators: %s expands to an indexable object's name, like a post type or taxonomy */
  633. esc_html__( 'Show %s in search results?', 'wordpress-seo' ),
  634. '<strong>' . esc_html( $label ) . '</strong>'
  635. ),
  636. $help
  637. );
  638. }
  639. /**
  640. * Creates a toggle switch to show hide certain options.
  641. *
  642. * @param string $var The variable within the option to create the radio buttons for.
  643. * @param string $label The visual label for the radio buttons group, used as the fieldset legend.
  644. * @param bool $inverse_keys Whether or not the option keys need to be inverted to support older functions.
  645. * @param string $help Inline Help that will be printed out before the visible toggles text.
  646. *
  647. * @return void
  648. */
  649. public function show_hide_switch( $var, $label, $inverse_keys = false, $help = '' ) {
  650. $on_key = ( $inverse_keys ) ? 'off' : 'on';
  651. $off_key = ( $inverse_keys ) ? 'on' : 'off';
  652. $show_hide_switch = [
  653. $on_key => __( 'Show', 'wordpress-seo' ),
  654. $off_key => __( 'Hide', 'wordpress-seo' ),
  655. ];
  656. $this->toggle_switch( $var, $show_hide_switch, $label, $help );
  657. }
  658. /**
  659. * Checks whether a given control should be disabled.
  660. *
  661. * @param string $var The variable within the option to check whether its control should be disabled.
  662. *
  663. * @return bool True if control should be disabled, false otherwise.
  664. */
  665. protected function is_control_disabled( $var ) {
  666. if ( $this->option_instance === null ) {
  667. return false;
  668. }
  669. return $this->option_instance->is_disabled( $var );
  670. }
  671. /**
  672. * Gets the explanation note to print if a given control is disabled.
  673. *
  674. * @param string $var The variable within the option to print a disabled note for.
  675. *
  676. * @return string Explanation note HTML string, or empty string if no note necessary.
  677. */
  678. protected function get_disabled_note( $var ) {
  679. if ( ! $this->is_control_disabled( $var ) ) {
  680. return '';
  681. }
  682. return '<p class="disabled-note">' . esc_html__( 'This feature has been disabled by the network admin.', 'wordpress-seo' ) . '</p>';
  683. }
  684. /* ********************* DEPRECATED METHODS ********************* */
  685. /**
  686. * Retrieve options based on whether we're on multisite or not.
  687. *
  688. * @since 1.2.4
  689. * @since 2.0 Moved to this class.
  690. * @deprecated 8.4
  691. * @codeCoverageIgnore
  692. *
  693. * @return array The option's value.
  694. */
  695. public function get_option() {
  696. _deprecated_function( __METHOD__, 'WPSEO 8.4' );
  697. if ( is_network_admin() ) {
  698. return get_site_option( $this->option_name );
  699. }
  700. return get_option( $this->option_name );
  701. }
  702. }