class-yoast-input-validation.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. <?php
  2. /**
  3. * WPSEO plugin file.
  4. *
  5. * @package WPSEO\Admin
  6. */
  7. /**
  8. * Implements server-side user input validation.
  9. *
  10. * @since 12.0
  11. */
  12. class Yoast_Input_Validation {
  13. /**
  14. * The error descriptions.
  15. *
  16. * @since 12.1
  17. *
  18. * @var array
  19. */
  20. private static $error_descriptions = [];
  21. /**
  22. * Check whether an option group is a Yoast SEO setting.
  23. *
  24. * The normal pattern is 'yoast' . $option_name . 'options'.
  25. *
  26. * @since 12.0
  27. *
  28. * @param string $group_name The option group name.
  29. *
  30. * @return bool Whether or not it's an Yoast SEO option group.
  31. */
  32. public static function is_yoast_option_group_name( $group_name ) {
  33. return ( strpos( $group_name, 'yoast' ) !== false );
  34. }
  35. /**
  36. * Adds an error message to the document title when submitting a settings
  37. * form and errors are returned.
  38. *
  39. * Uses the WordPress `admin_title` filter in the WPSEO_Option subclasses.
  40. *
  41. * @since 12.0
  42. *
  43. * @param string $admin_title The page title, with extra context added.
  44. *
  45. * @return string $admin_title The modified or original admin title.
  46. */
  47. public static function add_yoast_admin_document_title_errors( $admin_title ) {
  48. $errors = get_settings_errors();
  49. $error_count = 0;
  50. foreach ( $errors as $error ) {
  51. // For now, filter the admin title only in the Yoast SEO settings pages.
  52. if ( self::is_yoast_option_group_name( $error['setting'] ) && $error['code'] !== 'settings_updated' ) {
  53. $error_count++;
  54. }
  55. }
  56. if ( $error_count > 0 ) {
  57. return sprintf(
  58. /* translators: %1$s: amount of errors, %2$s: the admin page title */
  59. _n( 'The form contains %1$s error. %2$s', 'The form contains %1$s errors. %2$s', $error_count, 'wordpress-seo' ),
  60. number_format_i18n( $error_count ),
  61. $admin_title
  62. );
  63. }
  64. return $admin_title;
  65. }
  66. /**
  67. * Checks whether a specific form input field was submitted with an invalid value.
  68. *
  69. * @since 12.1
  70. *
  71. * @param string $error_code Must be the same slug-name used for the field variable and for `add_settings_error()`.
  72. *
  73. * @return bool Whether or not the submitted input field contained an invalid value.
  74. */
  75. public static function yoast_form_control_has_error( $error_code ) {
  76. $errors = get_settings_errors();
  77. foreach ( $errors as $error ) {
  78. if ( $error['code'] === $error_code ) {
  79. return true;
  80. }
  81. }
  82. return false;
  83. }
  84. /**
  85. * Sets the error descriptions.
  86. *
  87. * @since 12.1
  88. *
  89. * @param array $descriptions An associative array of error descriptions. For
  90. * each entry, the key must be the setting variable.
  91. */
  92. public static function set_error_descriptions( $descriptions = [] ) {
  93. $defaults = [
  94. 'baiduverify' => sprintf(
  95. /* translators: %s: additional message with the submitted invalid value */
  96. esc_html__( 'Baidu verification codes can only contain letters, numbers, hyphens, and underscores. %s', 'wordpress-seo' ),
  97. self::get_dirty_value_message( 'baiduverify' )
  98. ),
  99. 'facebook_site' => sprintf(
  100. /* translators: %s: additional message with the submitted invalid value */
  101. esc_html__( 'Please check the format of the Facebook Page URL you entered. %s', 'wordpress-seo' ),
  102. self::get_dirty_value_message( 'facebook_site' )
  103. ),
  104. 'fbadminapp' => sprintf(
  105. /* translators: %s: additional message with the submitted invalid value */
  106. esc_html__( 'The Facebook App ID you entered doesn\'t exist. %s', 'wordpress-seo' ),
  107. self::get_dirty_value_message( 'fbadminapp' )
  108. ),
  109. 'googleverify' => sprintf(
  110. /* translators: %s: additional message with the submitted invalid value */
  111. esc_html__( 'Google verification codes can only contain letters, numbers, hyphens, and underscores. %s', 'wordpress-seo' ),
  112. self::get_dirty_value_message( 'googleverify' )
  113. ),
  114. 'instagram_url' => sprintf(
  115. /* translators: %s: additional message with the submitted invalid value */
  116. esc_html__( 'Please check the format of the Instagram URL you entered. %s', 'wordpress-seo' ),
  117. self::get_dirty_value_message( 'instagram_url' )
  118. ),
  119. 'linkedin_url' => sprintf(
  120. /* translators: %s: additional message with the submitted invalid value */
  121. esc_html__( 'Please check the format of the Linkedin URL you entered. %s', 'wordpress-seo' ),
  122. self::get_dirty_value_message( 'linkedin_url' )
  123. ),
  124. 'msverify' => sprintf(
  125. /* translators: %s: additional message with the submitted invalid value */
  126. esc_html__( 'Bing confirmation codes can only contain letters from A to F, numbers, hyphens, and underscores. %s', 'wordpress-seo' ),
  127. self::get_dirty_value_message( 'msverify' )
  128. ),
  129. 'myspace_url' => sprintf(
  130. /* translators: %s: additional message with the submitted invalid value */
  131. esc_html__( 'Please check the format of the MySpace URL you entered. %s', 'wordpress-seo' ),
  132. self::get_dirty_value_message( 'myspace_url' )
  133. ),
  134. 'pinterest_url' => sprintf(
  135. /* translators: %s: additional message with the submitted invalid value */
  136. esc_html__( 'Please check the format of the Pinterest URL you entered. %s', 'wordpress-seo' ),
  137. self::get_dirty_value_message( 'pinterest_url' )
  138. ),
  139. 'pinterestverify' => sprintf(
  140. /* translators: %s: additional message with the submitted invalid value */
  141. esc_html__( 'Pinterest confirmation codes can only contain letters from A to F, numbers, hyphens, and underscores. %s', 'wordpress-seo' ),
  142. self::get_dirty_value_message( 'pinterestverify' )
  143. ),
  144. 'twitter_site' => sprintf(
  145. /* translators: %s: additional message with the submitted invalid value */
  146. esc_html__( 'Twitter usernames can only contain letters, numbers, and underscores. %s', 'wordpress-seo' ),
  147. self::get_dirty_value_message( 'twitter_site' )
  148. ),
  149. 'wikipedia_url' => sprintf(
  150. /* translators: %s: additional message with the submitted invalid value */
  151. esc_html__( 'Please check the format of the Wikipedia URL you entered. %s', 'wordpress-seo' ),
  152. self::get_dirty_value_message( 'wikipedia_url' )
  153. ),
  154. 'yandexverify' => sprintf(
  155. /* translators: %s: additional message with the submitted invalid value */
  156. esc_html__( 'Yandex confirmation codes can only contain letters from A to F, numbers, hyphens, and underscores. %s', 'wordpress-seo' ),
  157. self::get_dirty_value_message( 'yandexverify' )
  158. ),
  159. 'youtube_url' => sprintf(
  160. /* translators: %s: additional message with the submitted invalid value */
  161. esc_html__( 'Please check the format of the Youtube URL you entered. %s', 'wordpress-seo' ),
  162. self::get_dirty_value_message( 'youtube_url' )
  163. ),
  164. ];
  165. $descriptions = wp_parse_args( $descriptions, $defaults );
  166. self::$error_descriptions = $descriptions;
  167. }
  168. /**
  169. * Gets all the error descriptions.
  170. *
  171. * @since 12.1
  172. *
  173. * @return array An associative array of error descriptions.
  174. */
  175. public static function get_error_descriptions() {
  176. return self::$error_descriptions;
  177. }
  178. /**
  179. * Gets a specific error description.
  180. *
  181. * @since 12.1
  182. *
  183. * @param string $error_code Code of the error set via `add_settings_error()`, normally the variable name.
  184. * @return string The error description.
  185. */
  186. public static function get_error_description( $error_code ) {
  187. if ( ! isset( self::$error_descriptions[ $error_code ] ) ) {
  188. return null;
  189. }
  190. return self::$error_descriptions[ $error_code ];
  191. }
  192. /**
  193. * Gets the aria-invalid HTML attribute based on the submitted invalid value.
  194. *
  195. * @since 12.1
  196. *
  197. * @param string $error_code Code of the error set via `add_settings_error()`, normally the variable name.
  198. * @return string The aria-invalid HTML attribute or empty string.
  199. */
  200. public static function get_the_aria_invalid_attribute( $error_code ) {
  201. if ( self::yoast_form_control_has_error( $error_code ) ) {
  202. return ' aria-invalid="true"';
  203. }
  204. return '';
  205. }
  206. /**
  207. * Gets the aria-describedby HTML attribute based on the submitted invalid value.
  208. *
  209. * @since 12.1
  210. *
  211. * @param string $error_code Code of the error set via `add_settings_error()`, normally the variable name.
  212. * @return string The aria-describedby HTML attribute or empty string.
  213. */
  214. public static function get_the_aria_describedby_attribute( $error_code ) {
  215. if ( self::yoast_form_control_has_error( $error_code ) && self::get_error_description( $error_code ) ) {
  216. return ' aria-describedby="' . esc_attr( $error_code ) . '-error-description"';
  217. }
  218. return '';
  219. }
  220. /**
  221. * Gets the error description wrapped in a HTML paragraph.
  222. *
  223. * @since 12.1
  224. *
  225. * @param string $error_code Code of the error set via `add_settings_error()`, normally the variable name.
  226. * @return string The error description HTML or empty string.
  227. */
  228. public static function get_the_error_description( $error_code ) {
  229. $error_description = self::get_error_description( $error_code );
  230. if ( self::yoast_form_control_has_error( $error_code ) && $error_description ) {
  231. return '<p id="' . esc_attr( $error_code ) . '-error-description" class="yoast-input-validation__error-description">' . $error_description . '</p>';
  232. }
  233. return '';
  234. }
  235. /**
  236. * Adds the submitted invalid value to the WordPress `$wp_settings_errors` global.
  237. *
  238. * @since 12.1
  239. *
  240. * @param string $error_code Code of the error set via `add_settings_error()`, normally the variable name.
  241. * @param string $dirty_value The submitted invalid value.
  242. * @return void
  243. */
  244. public static function add_dirty_value_to_settings_errors( $error_code, $dirty_value ) {
  245. global $wp_settings_errors;
  246. if ( ! is_array( $wp_settings_errors ) ) {
  247. return;
  248. }
  249. foreach ( $wp_settings_errors as $index => $error ) {
  250. if ( $error['code'] === $error_code ) {
  251. $wp_settings_errors[ $index ]['yoast_dirty_value'] = $dirty_value;
  252. }
  253. }
  254. }
  255. /**
  256. * Gets an invalid submitted value.
  257. *
  258. * @since 12.1
  259. *
  260. * @param string $error_code Code of the error set via `add_settings_error()`, normally the variable name.
  261. * @return string The submitted invalid input field value.
  262. */
  263. public static function get_dirty_value( $error_code ) {
  264. $errors = get_settings_errors();
  265. foreach ( $errors as $error ) {
  266. if ( $error['code'] === $error_code && isset( $error['yoast_dirty_value'] ) ) {
  267. return $error['yoast_dirty_value'];
  268. }
  269. }
  270. return '';
  271. }
  272. /**
  273. * Gets a specific invalid value message.
  274. *
  275. * @since 12.1
  276. *
  277. * @param string $error_code Code of the error set via `add_settings_error()`, normally the variable name.
  278. * @return string The error invalid value message or empty string.
  279. */
  280. public static function get_dirty_value_message( $error_code ) {
  281. $dirty_value = self::get_dirty_value( $error_code );
  282. if ( $dirty_value ) {
  283. return sprintf(
  284. /* translators: %s: form value as submitted. */
  285. esc_html__( 'The submitted value was: %s', 'wordpress-seo' ),
  286. $dirty_value
  287. );
  288. }
  289. return '';
  290. }
  291. }