class-wpseo-option-social.php 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. <?php
  2. /**
  3. * WPSEO plugin file.
  4. *
  5. * @package WPSEO\Internals\Options
  6. */
  7. /**
  8. * Option: wpseo_social.
  9. */
  10. class WPSEO_Option_Social extends WPSEO_Option {
  11. /**
  12. * Option name.
  13. *
  14. * @var string
  15. */
  16. public $option_name = 'wpseo_social';
  17. /**
  18. * Array of defaults for the option.
  19. *
  20. * Shouldn't be requested directly, use $this->get_defaults();
  21. *
  22. * @var array
  23. */
  24. protected $defaults = [
  25. // Form fields.
  26. 'facebook_site' => '', // Text field.
  27. 'instagram_url' => '',
  28. 'linkedin_url' => '',
  29. 'myspace_url' => '',
  30. 'og_default_image' => '', // Text field.
  31. 'og_default_image_id' => '',
  32. 'og_frontpage_title' => '', // Text field.
  33. 'og_frontpage_desc' => '', // Text field.
  34. 'og_frontpage_image' => '', // Text field.
  35. 'og_frontpage_image_id' => '',
  36. 'opengraph' => true,
  37. 'pinterest_url' => '',
  38. 'pinterestverify' => '',
  39. 'twitter' => true,
  40. 'twitter_site' => '', // Text field.
  41. 'twitter_card_type' => 'summary_large_image',
  42. 'youtube_url' => '',
  43. 'wikipedia_url' => '',
  44. // Form field, but not always available.
  45. 'fbadminapp' => '', // Facebook app ID.
  46. ];
  47. /**
  48. * Array of sub-options which should not be overloaded with multi-site defaults.
  49. *
  50. * @var array
  51. */
  52. public $ms_exclude = [
  53. /* Privacy. */
  54. 'pinterestverify',
  55. 'fbadminapp',
  56. ];
  57. /**
  58. * Array of allowed twitter card types.
  59. *
  60. * While we only have the options summary and summary_large_image in the
  61. * interface now, we might change that at some point.
  62. *
  63. * {@internal Uncomment any of these to allow them in validation *and* automatically
  64. * add them as a choice in the options page.}}
  65. *
  66. * @var array
  67. */
  68. public static $twitter_card_types = [
  69. 'summary' => '',
  70. 'summary_large_image' => '',
  71. // 'photo' => '',
  72. // 'gallery' => '',
  73. // 'app' => '',
  74. // 'player' => '',
  75. // 'product' => '',
  76. ];
  77. /**
  78. * Add the actions and filters for the option.
  79. */
  80. protected function __construct() {
  81. parent::__construct();
  82. add_filter( 'admin_title', [ 'Yoast_Input_Validation', 'add_yoast_admin_document_title_errors' ] );
  83. }
  84. /**
  85. * Get the singleton instance of this class.
  86. *
  87. * @return object
  88. */
  89. public static function get_instance() {
  90. if ( ! ( self::$instance instanceof self ) ) {
  91. self::$instance = new self();
  92. }
  93. return self::$instance;
  94. }
  95. /**
  96. * Translate/set strings used in the option defaults.
  97. *
  98. * @return void
  99. */
  100. public function translate_defaults() {
  101. self::$twitter_card_types['summary'] = __( 'Summary', 'wordpress-seo' );
  102. self::$twitter_card_types['summary_large_image'] = __( 'Summary with large image', 'wordpress-seo' );
  103. }
  104. /**
  105. * Validate the option.
  106. *
  107. * @param array $dirty New value for the option.
  108. * @param array $clean Clean value for the option, normally the defaults.
  109. * @param array $old Old value of the option.
  110. *
  111. * @return array Validated clean value for the option to be saved to the database.
  112. */
  113. protected function validate_option( $dirty, $clean, $old ) {
  114. foreach ( $clean as $key => $value ) {
  115. switch ( $key ) {
  116. /* Text fields. */
  117. case 'og_frontpage_desc':
  118. case 'og_frontpage_title':
  119. if ( isset( $dirty[ $key ] ) && $dirty[ $key ] !== '' ) {
  120. $clean[ $key ] = WPSEO_Utils::sanitize_text_field( $dirty[ $key ] );
  121. }
  122. break;
  123. case 'og_default_image_id':
  124. case 'og_frontpage_image_id':
  125. if ( isset( $dirty[ $key ] ) ) {
  126. $clean[ $key ] = (int) $dirty[ $key ];
  127. if ( $dirty[ $key ] === '' ) {
  128. $clean[ $key ] = $dirty[ $key ];
  129. }
  130. }
  131. break;
  132. /* URL text fields - no ftp allowed. */
  133. case 'facebook_site':
  134. case 'instagram_url':
  135. case 'linkedin_url':
  136. case 'myspace_url':
  137. case 'pinterest_url':
  138. case 'og_default_image':
  139. case 'og_frontpage_image':
  140. case 'youtube_url':
  141. case 'wikipedia_url':
  142. $this->validate_url( $key, $dirty, $old, $clean );
  143. break;
  144. case 'pinterestverify':
  145. $this->validate_verification_string( $key, $dirty, $old, $clean );
  146. break;
  147. /* Twitter user name. */
  148. case 'twitter_site':
  149. if ( isset( $dirty[ $key ] ) && $dirty[ $key ] !== '' ) {
  150. $twitter_id = sanitize_text_field( ltrim( $dirty[ $key ], '@' ) );
  151. /*
  152. * From the Twitter documentation about twitter screen names:
  153. * Typically a maximum of 15 characters long, but some historical accounts
  154. * may exist with longer names.
  155. * A username can only contain alphanumeric characters (letters A-Z, numbers 0-9)
  156. * with the exception of underscores.
  157. *
  158. * @link https://support.twitter.com/articles/101299-why-can-t-i-register-certain-usernames
  159. * @link https://dev.twitter.com/docs/platform-objects/users
  160. */
  161. if ( preg_match( '`^[A-Za-z0-9_]{1,25}$`', $twitter_id ) ) {
  162. $clean[ $key ] = $twitter_id;
  163. }
  164. elseif ( preg_match( '`^http(?:s)?://(?:www\.)?twitter\.com/(?P<handle>[A-Za-z0-9_]{1,25})/?$`', $twitter_id, $matches ) ) {
  165. $clean[ $key ] = $matches['handle'];
  166. }
  167. else {
  168. if ( isset( $old[ $key ] ) && $old[ $key ] !== '' ) {
  169. $twitter_id = sanitize_text_field( ltrim( $old[ $key ], '@' ) );
  170. if ( preg_match( '`^[A-Za-z0-9_]{1,25}$`', $twitter_id ) ) {
  171. $clean[ $key ] = $twitter_id;
  172. }
  173. }
  174. if ( function_exists( 'add_settings_error' ) ) {
  175. add_settings_error(
  176. $this->group_name, // Slug title of the setting.
  177. $key, // Suffix-ID for the error message box.
  178. sprintf(
  179. /* translators: %s expands to a twitter user name. */
  180. __( '%s does not seem to be a valid Twitter Username. Please correct.', 'wordpress-seo' ),
  181. '<strong>' . esc_html( sanitize_text_field( $dirty[ $key ] ) ) . '</strong>'
  182. ), // The error message.
  183. 'error' // Error type, either 'error' or 'updated'.
  184. );
  185. }
  186. }
  187. unset( $twitter_id );
  188. Yoast_Input_Validation::add_dirty_value_to_settings_errors( $key, $dirty[ $key ] );
  189. }
  190. break;
  191. case 'twitter_card_type':
  192. if ( isset( $dirty[ $key ], self::$twitter_card_types[ $dirty[ $key ] ] ) && $dirty[ $key ] !== '' ) {
  193. $clean[ $key ] = $dirty[ $key ];
  194. }
  195. break;
  196. /* Boolean fields. */
  197. case 'opengraph':
  198. case 'twitter':
  199. $clean[ $key ] = ( isset( $dirty[ $key ] ) ? WPSEO_Utils::validate_bool( $dirty[ $key ] ) : false );
  200. break;
  201. case 'fbadminapp':
  202. $this->validate_facebook_app_id( $key, $dirty, $old, $clean );
  203. break;
  204. }
  205. }
  206. return $clean;
  207. }
  208. /**
  209. * Clean a given option value.
  210. *
  211. * @param array $option_value Old (not merged with defaults or filtered) option value to
  212. * clean according to the rules for this option.
  213. * @param string $current_version Optional. Version from which to upgrade, if not set,
  214. * version specific upgrades will be disregarded.
  215. * @param array $all_old_option_values Optional. Only used when importing old options to have
  216. * access to the real old values, in contrast to the saved ones.
  217. *
  218. * @return array Cleaned option.
  219. */
  220. protected function clean_option( $option_value, $current_version = null, $all_old_option_values = null ) {
  221. /* Move options from very old option to this one. */
  222. $old_option = null;
  223. if ( isset( $all_old_option_values ) ) {
  224. // Ok, we have an import.
  225. if ( isset( $all_old_option_values['wpseo_indexation'] ) && is_array( $all_old_option_values['wpseo_indexation'] ) && $all_old_option_values['wpseo_indexation'] !== [] ) {
  226. $old_option = $all_old_option_values['wpseo_indexation'];
  227. }
  228. }
  229. else {
  230. $old_option = get_option( 'wpseo_indexation' );
  231. }
  232. if ( is_array( $old_option ) && $old_option !== [] ) {
  233. $move = [
  234. 'opengraph',
  235. ];
  236. foreach ( $move as $key ) {
  237. if ( isset( $old_option[ $key ] ) && ! isset( $option_value[ $key ] ) ) {
  238. $option_value[ $key ] = $old_option[ $key ];
  239. }
  240. }
  241. unset( $move, $key );
  242. }
  243. unset( $old_option );
  244. return $option_value;
  245. }
  246. }