class-wpseo-option-wpseo.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. <?php
  2. /**
  3. * WPSEO plugin file.
  4. *
  5. * @package WPSEO\Internals\Options
  6. */
  7. /**
  8. * Option: wpseo.
  9. */
  10. class WPSEO_Option_Wpseo extends WPSEO_Option {
  11. /**
  12. * Option name.
  13. *
  14. * @var string
  15. */
  16. public $option_name = 'wpseo';
  17. /**
  18. * Array of defaults for the option.
  19. *
  20. * {@internal Shouldn't be requested directly, use $this->get_defaults();}}
  21. *
  22. * @var array
  23. */
  24. protected $defaults = [
  25. // Non-form fields, set via (ajax) function.
  26. 'ms_defaults_set' => false,
  27. // Non-form field, should only be set via validation routine.
  28. 'version' => '', // Leave default as empty to ensure activation/upgrade works.
  29. // Form fields.
  30. 'disableadvanced_meta' => true,
  31. 'onpage_indexability' => true,
  32. 'baiduverify' => '', // Text field.
  33. 'googleverify' => '', // Text field.
  34. 'msverify' => '', // Text field.
  35. 'yandexverify' => '',
  36. 'site_type' => '', // List of options.
  37. 'has_multiple_authors' => '',
  38. 'environment_type' => '',
  39. 'content_analysis_active' => true,
  40. 'keyword_analysis_active' => true,
  41. 'enable_admin_bar_menu' => true,
  42. 'enable_cornerstone_content' => true,
  43. 'enable_xml_sitemap' => true,
  44. 'enable_text_link_counter' => true,
  45. 'show_onboarding_notice' => false,
  46. 'first_activated_on' => false,
  47. 'myyoast-oauth' => [
  48. 'config' => [
  49. 'clientId' => null,
  50. 'secret' => null,
  51. ],
  52. 'access_tokens' => [],
  53. ],
  54. ];
  55. /**
  56. * Sub-options which should not be overloaded with multi-site defaults.
  57. *
  58. * @var array
  59. */
  60. public $ms_exclude = [
  61. /* Privacy. */
  62. 'baiduverify',
  63. 'googleverify',
  64. 'msverify',
  65. 'yandexverify',
  66. ];
  67. /**
  68. * Possible values for the site_type option.
  69. *
  70. * @var array
  71. */
  72. protected $site_types = [
  73. '',
  74. 'blog',
  75. 'shop',
  76. 'news',
  77. 'smallBusiness',
  78. 'corporateOther',
  79. 'personalOther',
  80. ];
  81. /**
  82. * Possible environment types.
  83. *
  84. * @var array
  85. */
  86. protected $environment_types = [
  87. '',
  88. 'production',
  89. 'staging',
  90. 'development',
  91. ];
  92. /**
  93. * Possible has_multiple_authors options.
  94. *
  95. * @var array
  96. */
  97. protected $has_multiple_authors_options = [
  98. '',
  99. true,
  100. false,
  101. ];
  102. /**
  103. * Name for an option higher in the hierarchy to override setting access.
  104. *
  105. * @var string
  106. */
  107. protected $override_option_name = 'wpseo_ms';
  108. /**
  109. * Add the actions and filters for the option.
  110. *
  111. * @todo [JRF => testers] Check if the extra actions below would run into problems if an option
  112. * is updated early on and if so, change the call to schedule these for a later action on add/update
  113. * instead of running them straight away.
  114. *
  115. * @return \WPSEO_Option_Wpseo
  116. */
  117. protected function __construct() {
  118. parent::__construct();
  119. /* Clear the cache on update/add. */
  120. add_action( 'add_option_' . $this->option_name, [ 'WPSEO_Utils', 'clear_cache' ] );
  121. add_action( 'update_option_' . $this->option_name, [ 'WPSEO_Utils', 'clear_cache' ] );
  122. add_filter( 'admin_title', [ 'Yoast_Input_Validation', 'add_yoast_admin_document_title_errors' ] );
  123. /**
  124. * Filter the `wpseo` option defaults.
  125. *
  126. * @param array $defaults Array the defaults for the `wpseo` option attributes.
  127. */
  128. $this->defaults = apply_filters( 'wpseo_option_wpseo_defaults', $this->defaults );
  129. }
  130. /**
  131. * Get the singleton instance of this class.
  132. *
  133. * @return object
  134. */
  135. public static function get_instance() {
  136. if ( ! ( self::$instance instanceof self ) ) {
  137. self::$instance = new self();
  138. }
  139. return self::$instance;
  140. }
  141. /**
  142. * Add filters to make sure that the option is merged with its defaults before being returned.
  143. *
  144. * @return void
  145. */
  146. public function add_option_filters() {
  147. parent::add_option_filters();
  148. list( $hookname, $callback, $priority ) = $this->get_verify_features_option_filter_hook();
  149. if ( has_filter( $hookname, $callback ) === false ) {
  150. add_filter( $hookname, $callback, $priority );
  151. }
  152. }
  153. /**
  154. * Remove the option filters.
  155. * Called from the clean_up methods to make sure we retrieve the original old option.
  156. *
  157. * @return void
  158. */
  159. public function remove_option_filters() {
  160. parent::remove_option_filters();
  161. list( $hookname, $callback, $priority ) = $this->get_verify_features_option_filter_hook();
  162. remove_filter( $hookname, $callback, $priority );
  163. }
  164. /**
  165. * Add filters to make sure that the option default is returned if the option is not set.
  166. *
  167. * @return void
  168. */
  169. public function add_default_filters() {
  170. parent::add_default_filters();
  171. list( $hookname, $callback, $priority ) = $this->get_verify_features_default_option_filter_hook();
  172. if ( has_filter( $hookname, $callback ) === false ) {
  173. add_filter( $hookname, $callback, $priority );
  174. }
  175. }
  176. /**
  177. * Remove the default filters.
  178. * Called from the validate() method to prevent failure to add new options.
  179. *
  180. * @return void
  181. */
  182. public function remove_default_filters() {
  183. parent::remove_default_filters();
  184. list( $hookname, $callback, $priority ) = $this->get_verify_features_default_option_filter_hook();
  185. remove_filter( $hookname, $callback, $priority );
  186. }
  187. /**
  188. * Validate the option.
  189. *
  190. * @param array $dirty New value for the option.
  191. * @param array $clean Clean value for the option, normally the defaults.
  192. * @param array $old Old value of the option.
  193. *
  194. * @return array Validated clean value for the option to be saved to the database.
  195. */
  196. protected function validate_option( $dirty, $clean, $old ) {
  197. foreach ( $clean as $key => $value ) {
  198. switch ( $key ) {
  199. case 'version':
  200. $clean[ $key ] = WPSEO_VERSION;
  201. break;
  202. /* Verification strings. */
  203. case 'baiduverify':
  204. case 'googleverify':
  205. case 'msverify':
  206. case 'yandexverify':
  207. $this->validate_verification_string( $key, $dirty, $old, $clean );
  208. break;
  209. /*
  210. * Boolean dismiss warnings - not fields - may not be in form
  211. * (and don't need to be either as long as the default is false).
  212. */
  213. case 'ms_defaults_set':
  214. if ( isset( $dirty[ $key ] ) ) {
  215. $clean[ $key ] = WPSEO_Utils::validate_bool( $dirty[ $key ] );
  216. }
  217. elseif ( isset( $old[ $key ] ) ) {
  218. $clean[ $key ] = WPSEO_Utils::validate_bool( $old[ $key ] );
  219. }
  220. break;
  221. case 'site_type':
  222. $clean[ $key ] = $old[ $key ];
  223. if ( isset( $dirty[ $key ] ) && in_array( $dirty[ $key ], $this->site_types, true ) ) {
  224. $clean[ $key ] = $dirty[ $key ];
  225. }
  226. break;
  227. case 'environment_type':
  228. $clean[ $key ] = $old[ $key ];
  229. if ( isset( $dirty[ $key ] ) && in_array( $dirty[ $key ], $this->environment_types, true ) ) {
  230. $clean[ $key ] = $dirty[ $key ];
  231. }
  232. break;
  233. case 'has_multiple_authors':
  234. $clean[ $key ] = $old[ $key ];
  235. if ( isset( $dirty[ $key ] ) && in_array( $dirty[ $key ], $this->has_multiple_authors_options, true ) ) {
  236. $clean[ $key ] = $dirty[ $key ];
  237. }
  238. break;
  239. case 'first_activated_on':
  240. $clean[ $key ] = false;
  241. if ( isset( $dirty[ $key ] ) ) {
  242. if ( $dirty[ $key ] === false || WPSEO_Utils::validate_int( $dirty[ $key ] ) ) {
  243. $clean[ $key ] = $dirty[ $key ];
  244. }
  245. }
  246. break;
  247. case 'myyoast_oauth':
  248. $clean[ $key ] = $old[ $key ];
  249. if ( isset( $dirty[ $key ] ) ) {
  250. $myyoast_oauth = $dirty[ $key ];
  251. if ( ! is_array( $myyoast_oauth ) ) {
  252. $myyoast_oauth = json_decode( $dirty[ $key ], true );
  253. }
  254. if ( is_array( $myyoast_oauth ) ) {
  255. $clean[ $key ] = $dirty[ $key ];
  256. }
  257. }
  258. break;
  259. /*
  260. * Boolean (checkbox) fields.
  261. */
  262. /*
  263. * Covers:
  264. * 'disableadvanced_meta'
  265. * 'yoast_tracking'
  266. */
  267. default:
  268. $clean[ $key ] = ( isset( $dirty[ $key ] ) ? WPSEO_Utils::validate_bool( $dirty[ $key ] ) : false );
  269. break;
  270. }
  271. }
  272. return $clean;
  273. }
  274. /**
  275. * Verifies that the feature variables are turned off if the network is configured so.
  276. *
  277. * @param mixed $options Value of the option to be returned. Typically an array.
  278. *
  279. * @return mixed Filtered $options value.
  280. */
  281. public function verify_features_against_network( $options = [] ) {
  282. if ( ! is_array( $options ) || empty( $options ) ) {
  283. return $options;
  284. }
  285. // For the feature variables, set their values to off in case they are disabled.
  286. $feature_vars = [
  287. 'disableadvanced_meta' => false,
  288. 'onpage_indexability' => false,
  289. 'content_analysis_active' => false,
  290. 'keyword_analysis_active' => false,
  291. 'enable_admin_bar_menu' => false,
  292. 'enable_cornerstone_content' => false,
  293. 'enable_xml_sitemap' => false,
  294. 'enable_text_link_counter' => false,
  295. ];
  296. // We can reuse this logic from the base class with the above defaults to parse with the correct feature values.
  297. $options = $this->prevent_disabled_options_update( $options, $feature_vars );
  298. return $options;
  299. }
  300. /**
  301. * Gets the filter hook name and callback for adjusting the retrieved option value
  302. * against the network-allowed features.
  303. *
  304. * @return array Array where the first item is the hook name, the second is the hook callback,
  305. * and the third is the hook priority.
  306. */
  307. protected function get_verify_features_option_filter_hook() {
  308. return [
  309. "option_{$this->option_name}",
  310. [ $this, 'verify_features_against_network' ],
  311. 11,
  312. ];
  313. }
  314. /**
  315. * Gets the filter hook name and callback for adjusting the default option value against the network-allowed features.
  316. *
  317. * @return array Array where the first item is the hook name, the second is the hook callback,
  318. * and the third is the hook priority.
  319. */
  320. protected function get_verify_features_default_option_filter_hook() {
  321. return [
  322. "default_option_{$this->option_name}",
  323. [ $this, 'verify_features_against_network' ],
  324. 11,
  325. ];
  326. }
  327. /**
  328. * Clean a given option value.
  329. *
  330. * @param array $option_value Old (not merged with defaults or filtered) option value to
  331. * clean according to the rules for this option.
  332. * @param string $current_version Optional. Version from which to upgrade, if not set,
  333. * version specific upgrades will be disregarded.
  334. * @param array $all_old_option_values Optional. Only used when importing old options to have
  335. * access to the real old values, in contrast to the saved ones.
  336. *
  337. * @return array Cleaned option.
  338. */
  339. protected function clean_option( $option_value, $current_version = null, $all_old_option_values = null ) {
  340. return $option_value;
  341. }
  342. }