class-upgrade.php 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853
  1. <?php
  2. /**
  3. * WPSEO plugin file.
  4. *
  5. * @package WPSEO\Internal
  6. */
  7. /**
  8. * This code handles the option upgrades.
  9. */
  10. class WPSEO_Upgrade {
  11. /**
  12. * Class constructor.
  13. */
  14. public function __construct() {
  15. $version = WPSEO_Options::get( 'version' );
  16. WPSEO_Options::maybe_set_multisite_defaults( false );
  17. $routines = [
  18. '1.5.0' => 'upgrade_15',
  19. '2.0' => 'upgrade_20',
  20. '2.1' => 'upgrade_21',
  21. '2.2' => 'upgrade_22',
  22. '2.3' => 'upgrade_23',
  23. '3.0' => 'upgrade_30',
  24. '3.3' => 'upgrade_33',
  25. '3.6' => 'upgrade_36',
  26. '4.0' => 'upgrade_40',
  27. '4.4' => 'upgrade_44',
  28. '4.7' => 'upgrade_47',
  29. '4.9' => 'upgrade_49',
  30. '5.0' => 'upgrade_50',
  31. '5.1' => 'upgrade_50_51',
  32. '5.5' => 'upgrade_55',
  33. '5.6' => 'upgrade_56',
  34. '6.1' => 'upgrade_61',
  35. '6.3' => 'upgrade_63',
  36. '7.0-RC0' => 'upgrade_70',
  37. '7.1-RC0' => 'upgrade_71',
  38. '7.3-RC0' => 'upgrade_73',
  39. '7.4-RC0' => 'upgrade_74',
  40. '7.5.3' => 'upgrade_753',
  41. '7.7-RC0' => 'upgrade_77',
  42. '7.7.2-RC0' => 'upgrade_772',
  43. '9.0-RC0' => 'upgrade_90',
  44. '10.0-RC0' => 'upgrade_100',
  45. '11.1-RC0' => 'upgrade_111',
  46. /** Reset notifications because we removed the AMP Glue plugin notification */
  47. '12.1-RC0' => 'clean_all_notifications',
  48. '12.3-RC0' => 'upgrade_123',
  49. '12.4-RC0' => 'upgrade_124',
  50. ];
  51. array_walk( $routines, [ $this, 'run_upgrade_routine' ], $version );
  52. if ( version_compare( $version, '12.5-RC0', '<' ) ) {
  53. /*
  54. * We have to run this by hook, because otherwise:
  55. * - the theme support check isn't available.
  56. * - the notification center notifications are not filled yet.
  57. */
  58. add_action( 'init', [ $this, 'upgrade_125' ] );
  59. }
  60. // Since 3.7.
  61. $upsell_notice = new WPSEO_Product_Upsell_Notice();
  62. $upsell_notice->set_upgrade_notice();
  63. /**
  64. * Filter: 'wpseo_run_upgrade' - Runs the upgrade hook which are dependent on Yoast SEO.
  65. *
  66. * @api string - The current version of Yoast SEO
  67. */
  68. do_action( 'wpseo_run_upgrade', $version );
  69. $this->finish_up();
  70. }
  71. /**
  72. * Runs the upgrade routine.
  73. *
  74. * @param string $routine The method to call.
  75. * @param string $version The new version.
  76. * @param string $current_version The current set version.
  77. *
  78. * @return void
  79. */
  80. protected function run_upgrade_routine( $routine, $version, $current_version ) {
  81. if ( version_compare( $current_version, $version, '<' ) ) {
  82. $this->$routine( $current_version );
  83. }
  84. }
  85. /**
  86. * Adds a new upgrade history entry.
  87. *
  88. * @param string $current_version The old version from which we are upgrading.
  89. * @param string $new_version The version we are upgrading to.
  90. */
  91. protected function add_upgrade_history( $current_version, $new_version ) {
  92. $upgrade_history = new WPSEO_Upgrade_History();
  93. $upgrade_history->add( $current_version, $new_version, array_keys( WPSEO_Options::$options ) );
  94. }
  95. /**
  96. * Runs the needed cleanup after an update, setting the DB version to latest version, flushing caches etc.
  97. */
  98. protected function finish_up() {
  99. WPSEO_Options::set( 'version', WPSEO_VERSION );
  100. // Just flush rewrites, always, to at least make them work after an upgrade.
  101. add_action( 'shutdown', 'flush_rewrite_rules' );
  102. // Flush the sitemap cache.
  103. WPSEO_Sitemaps_Cache::clear();
  104. // Make sure all our options always exist - issue #1245.
  105. WPSEO_Options::ensure_options_exist();
  106. }
  107. /**
  108. * Run the Yoast SEO 1.5 upgrade routine.
  109. *
  110. * @param string $version Current plugin version.
  111. */
  112. private function upgrade_15( $version ) {
  113. // Clean up options and meta.
  114. WPSEO_Options::clean_up( null, $version );
  115. WPSEO_Meta::clean_up();
  116. }
  117. /**
  118. * Moves options that moved position in WPSEO 2.0.
  119. */
  120. private function upgrade_20() {
  121. /**
  122. * Clean up stray wpseo_ms options from the options table, option should only exist in the sitemeta table.
  123. * This could have been caused in many version of Yoast SEO, so deleting it for everything below 2.0.
  124. */
  125. delete_option( 'wpseo_ms' );
  126. $wpseo = $this->get_option_from_database( 'wpseo' );
  127. $this->save_option_setting( $wpseo, 'pinterestverify' );
  128. // Re-save option to trigger sanitization.
  129. $this->cleanup_option_data( 'wpseo' );
  130. }
  131. /**
  132. * Detects if taxonomy terms were split and updates the corresponding taxonomy meta's accordingly.
  133. */
  134. private function upgrade_21() {
  135. $taxonomies = get_option( 'wpseo_taxonomy_meta', [] );
  136. if ( ! empty( $taxonomies ) ) {
  137. foreach ( $taxonomies as $taxonomy => $tax_metas ) {
  138. foreach ( $tax_metas as $term_id => $tax_meta ) {
  139. if ( function_exists( 'wp_get_split_term' ) ) {
  140. $new_term_id = wp_get_split_term( $term_id, $taxonomy );
  141. if ( $new_term_id !== false ) {
  142. $taxonomies[ $taxonomy ][ $new_term_id ] = $taxonomies[ $taxonomy ][ $term_id ];
  143. unset( $taxonomies[ $taxonomy ][ $term_id ] );
  144. }
  145. }
  146. }
  147. }
  148. update_option( 'wpseo_taxonomy_meta', $taxonomies );
  149. }
  150. }
  151. /**
  152. * Performs upgrade functions to Yoast SEO 2.2.
  153. */
  154. private function upgrade_22() {
  155. // Unschedule our tracking.
  156. wp_clear_scheduled_hook( 'yoast_tracking' );
  157. $this->cleanup_option_data( 'wpseo' );
  158. }
  159. /**
  160. * Schedules upgrade function to Yoast SEO 2.3.
  161. */
  162. private function upgrade_23() {
  163. add_action( 'wp', [ $this, 'upgrade_23_query' ], 90 );
  164. add_action( 'admin_head', [ $this, 'upgrade_23_query' ], 90 );
  165. }
  166. /**
  167. * Performs upgrade query to Yoast SEO 2.3.
  168. */
  169. public function upgrade_23_query() {
  170. $wp_query = new WP_Query( 'post_type=any&meta_key=_yoast_wpseo_sitemap-include&meta_value=never&order=ASC' );
  171. if ( ! empty( $wp_query->posts ) ) {
  172. $options = get_option( 'wpseo_xml' );
  173. $excluded_posts = [];
  174. if ( $options['excluded-posts'] !== '' ) {
  175. $excluded_posts = explode( ',', $options['excluded-posts'] );
  176. }
  177. foreach ( $wp_query->posts as $post ) {
  178. if ( ! in_array( $post->ID, $excluded_posts ) ) {
  179. $excluded_posts[] = $post->ID;
  180. }
  181. }
  182. // Updates the meta value.
  183. $options['excluded-posts'] = implode( ',', $excluded_posts );
  184. // Update the option.
  185. update_option( 'wpseo_xml', $options );
  186. }
  187. // Remove the meta fields.
  188. delete_post_meta_by_key( '_yoast_wpseo_sitemap-include' );
  189. }
  190. /**
  191. * Performs upgrade functions to Yoast SEO 3.0.
  192. */
  193. private function upgrade_30() {
  194. // Remove the meta fields for sitemap prio.
  195. delete_post_meta_by_key( '_yoast_wpseo_sitemap-prio' );
  196. }
  197. /**
  198. * Performs upgrade functions to Yoast SEO 3.3.
  199. */
  200. private function upgrade_33() {
  201. // Notification dismissals have been moved to User Meta instead of global option.
  202. delete_option( Yoast_Notification_Center::STORAGE_KEY );
  203. }
  204. /**
  205. * Performs upgrade functions to Yoast SEO 3.6.
  206. */
  207. private function upgrade_36() {
  208. global $wpdb;
  209. // Between 3.2 and 3.4 the sitemap options were saved with autoloading enabled.
  210. $wpdb->query( 'DELETE FROM ' . $wpdb->options . ' WHERE option_name LIKE "wpseo_sitemap_%" AND autoload = "yes"' );
  211. }
  212. /**
  213. * Removes the about notice when its still in the database.
  214. */
  215. private function upgrade_40() {
  216. $center = Yoast_Notification_Center::get();
  217. $center->remove_notification_by_id( 'wpseo-dismiss-about' );
  218. }
  219. /**
  220. * Moves the content-analysis-active and keyword-analysis-acive options from wpseo-titles to wpseo.
  221. */
  222. private function upgrade_44() {
  223. $wpseo_titles = $this->get_option_from_database( 'wpseo_titles' );
  224. $this->save_option_setting( $wpseo_titles, 'content-analysis-active', 'content_analysis_active' );
  225. $this->save_option_setting( $wpseo_titles, 'keyword-analysis-active', 'keyword_analysis_active' );
  226. // Remove irrelevant content from the option.
  227. $this->cleanup_option_data( 'wpseo_titles' );
  228. }
  229. /**
  230. * Renames the meta name for the cornerstone content. It was a public meta field and it has to be private.
  231. */
  232. private function upgrade_47() {
  233. global $wpdb;
  234. // The meta key has to be private, so prefix it.
  235. $wpdb->query(
  236. $wpdb->prepare(
  237. 'UPDATE ' . $wpdb->postmeta . ' SET meta_key = %s WHERE meta_key = "yst_is_cornerstone"',
  238. WPSEO_Cornerstone_Filter::META_NAME
  239. )
  240. );
  241. }
  242. /**
  243. * Removes the 'wpseo-dismiss-about' notice for every user that still has it.
  244. */
  245. private function upgrade_49() {
  246. global $wpdb;
  247. /*
  248. * Using a filter to remove the notification for the current logged in user. The notification center is
  249. * initializing the notifications before the upgrade routine has been executedd and is saving the stored
  250. * notifications on shutdown. This causes the returning notification. By adding this filter the shutdown
  251. * routine on the notification center will remove the notification.
  252. */
  253. add_filter( 'yoast_notifications_before_storage', [ $this, 'remove_about_notice' ] );
  254. $meta_key = $wpdb->get_blog_prefix() . Yoast_Notification_Center::STORAGE_KEY;
  255. $usermetas = $wpdb->get_results(
  256. $wpdb->prepare(
  257. '
  258. SELECT user_id, meta_value
  259. FROM ' . $wpdb->usermeta . '
  260. WHERE meta_key = %s AND meta_value LIKE %s
  261. ',
  262. $meta_key,
  263. '%wpseo-dismiss-about%'
  264. ),
  265. ARRAY_A
  266. );
  267. if ( empty( $usermetas ) ) {
  268. return;
  269. }
  270. foreach ( $usermetas as $usermeta ) {
  271. $notifications = maybe_unserialize( $usermeta['meta_value'] );
  272. foreach ( $notifications as $notification_key => $notification ) {
  273. if ( ! empty( $notification['options']['id'] ) && $notification['options']['id'] === 'wpseo-dismiss-about' ) {
  274. unset( $notifications[ $notification_key ] );
  275. }
  276. }
  277. update_user_option( $usermeta['user_id'], Yoast_Notification_Center::STORAGE_KEY, array_values( $notifications ) );
  278. }
  279. }
  280. /**
  281. * Removes the wpseo-dismiss-about notice from a list of notifications.
  282. *
  283. * @param Yoast_Notification[] $notifications The notifications to filter.
  284. *
  285. * @return Yoast_Notification[] The filtered list of notifications. Excluding the wpseo-dismiss-about notification.
  286. */
  287. public function remove_about_notice( $notifications ) {
  288. foreach ( $notifications as $notification_key => $notification ) {
  289. if ( $notification->get_id() === 'wpseo-dismiss-about' ) {
  290. unset( $notifications[ $notification_key ] );
  291. }
  292. }
  293. return $notifications;
  294. }
  295. /**
  296. * Adds the yoast_seo_links table to the database.
  297. */
  298. private function upgrade_50() {
  299. global $wpdb;
  300. $link_installer = new WPSEO_Link_Installer();
  301. $link_installer->install();
  302. // Trigger reindex notification.
  303. $notifier = new WPSEO_Link_Notifier();
  304. $notifier->manage_notification();
  305. // Deletes the post meta value, which might created in the RC.
  306. $wpdb->query( 'DELETE FROM ' . $wpdb->postmeta . ' WHERE meta_key = "_yst_content_links_processed"' );
  307. }
  308. /**
  309. * Updates the internal_link_count column to support improved functionality.
  310. *
  311. * @param string $version The current version to compare with.
  312. */
  313. private function upgrade_50_51( $version ) {
  314. global $wpdb;
  315. if ( version_compare( $version, '5.0', '>=' ) ) {
  316. $count_storage = new WPSEO_Meta_Storage();
  317. $wpdb->query( 'ALTER TABLE ' . $count_storage->get_table_name() . ' MODIFY internal_link_count int(10) UNSIGNED NULL DEFAULT NULL' );
  318. }
  319. }
  320. /**
  321. * Register new capabilities and roles.
  322. */
  323. private function upgrade_55() {
  324. // Register roles.
  325. do_action( 'wpseo_register_roles' );
  326. WPSEO_Role_Manager_Factory::get()->add();
  327. // Register capabilities.
  328. do_action( 'wpseo_register_capabilities' );
  329. WPSEO_Capability_Manager_Factory::get()->add();
  330. }
  331. /**
  332. * Updates legacy license page options to the latest version.
  333. */
  334. private function upgrade_56() {
  335. global $wpdb;
  336. // Make sure License Server checks are on the latest server version by default.
  337. update_option( 'wpseo_license_server_version', WPSEO_License_Page_Manager::VERSION_BACKWARDS_COMPATIBILITY );
  338. // Make sure incoming link count entries are at least 0, not NULL.
  339. $count_storage = new WPSEO_Meta_Storage();
  340. $wpdb->query( 'UPDATE ' . $count_storage->get_table_name() . ' SET incoming_link_count = 0 WHERE incoming_link_count IS NULL' );
  341. }
  342. /**
  343. * Updates the links for the link count when there is a difference between the site and home url.
  344. * We've used the site url instead of the home url.
  345. *
  346. * @return void
  347. */
  348. private function upgrade_61() {
  349. // When the home url is the same as the site url, just do nothing.
  350. if ( home_url() === site_url() ) {
  351. return;
  352. }
  353. global $wpdb;
  354. $link_storage = new WPSEO_Link_Storage();
  355. $wpdb->query( 'DELETE FROM ' . $link_storage->get_table_name() );
  356. $meta_storage = new WPSEO_Meta_Storage();
  357. $wpdb->query( 'DELETE FROM ' . $meta_storage->get_table_name() );
  358. }
  359. /**
  360. * Removes some no longer used options for noindexing subpages and for meta keywords and its associated templates.
  361. *
  362. * @return void
  363. */
  364. private function upgrade_63() {
  365. $this->cleanup_option_data( 'wpseo_titles' );
  366. }
  367. /**
  368. * Perform the 7.0 upgrade, moves settings around, deletes several options.
  369. *
  370. * @return void
  371. */
  372. private function upgrade_70() {
  373. $wpseo_permalinks = $this->get_option_from_database( 'wpseo_permalinks' );
  374. $wpseo_xml = $this->get_option_from_database( 'wpseo_xml' );
  375. $wpseo_rss = $this->get_option_from_database( 'wpseo_rss' );
  376. $wpseo = $this->get_option_from_database( 'wpseo' );
  377. $wpseo_internallinks = $this->get_option_from_database( 'wpseo_internallinks' );
  378. // Move some permalink settings, then delete the option.
  379. $this->save_option_setting( $wpseo_permalinks, 'redirectattachment', 'disable-attachment' );
  380. $this->save_option_setting( $wpseo_permalinks, 'stripcategorybase' );
  381. // Move one XML sitemap setting, then delete the option.
  382. $this->save_option_setting( $wpseo_xml, 'enablexmlsitemap', 'enable_xml_sitemap' );
  383. // Move the RSS settings to the search appearance settings, then delete the RSS option.
  384. $this->save_option_setting( $wpseo_rss, 'rssbefore' );
  385. $this->save_option_setting( $wpseo_rss, 'rssafter' );
  386. $this->save_option_setting( $wpseo, 'company_logo' );
  387. $this->save_option_setting( $wpseo, 'company_name' );
  388. $this->save_option_setting( $wpseo, 'company_or_person' );
  389. $this->save_option_setting( $wpseo, 'person_name' );
  390. // Remove the website name and altername name as we no longer need them.
  391. $this->cleanup_option_data( 'wpseo' );
  392. // All the breadcrumbs settings have moved to the search appearance settings.
  393. foreach ( array_keys( $wpseo_internallinks ) as $key ) {
  394. $this->save_option_setting( $wpseo_internallinks, $key );
  395. }
  396. // Convert hidden metabox options to display metabox options.
  397. $title_options = get_option( 'wpseo_titles' );
  398. foreach ( $title_options as $key => $value ) {
  399. if ( strpos( $key, 'hideeditbox-tax-' ) === 0 ) {
  400. $taxonomy = substr( $key, strlen( 'hideeditbox-tax-' ) );
  401. WPSEO_Options::set( 'display-metabox-tax-' . $taxonomy, ! $value );
  402. continue;
  403. }
  404. if ( strpos( $key, 'hideeditbox-' ) === 0 ) {
  405. $post_type = substr( $key, strlen( 'hideeditbox-' ) );
  406. WPSEO_Options::set( 'display-metabox-pt-' . $post_type, ! $value );
  407. continue;
  408. }
  409. }
  410. // Cleanup removed options.
  411. delete_option( 'wpseo_xml' );
  412. delete_option( 'wpseo_permalinks' );
  413. delete_option( 'wpseo_rss' );
  414. delete_option( 'wpseo_internallinks' );
  415. // Remove possibly present plugin conflict notice for plugin that was removed from the list of conflicting plugins.
  416. $yoast_plugin_conflict = WPSEO_Plugin_Conflict::get_instance();
  417. $yoast_plugin_conflict->clear_error( 'header-footer/plugin.php' );
  418. // Moves the user meta for excluding from the XML sitemap to a noindex.
  419. global $wpdb;
  420. $wpdb->query( "UPDATE $wpdb->usermeta SET meta_key = 'wpseo_noindex_author' WHERE meta_key = 'wpseo_excludeauthorsitemap'" );
  421. }
  422. /**
  423. * Perform the 7.1 upgrade.
  424. *
  425. * @return void
  426. */
  427. private function upgrade_71() {
  428. $this->cleanup_option_data( 'wpseo_social' );
  429. // Move the breadcrumbs setting and invert it.
  430. $title_options = $this->get_option_from_database( 'wpseo_titles' );
  431. if ( array_key_exists( 'breadcrumbs-blog-remove', $title_options ) ) {
  432. WPSEO_Options::set( 'breadcrumbs-display-blog-page', ! $title_options['breadcrumbs-blog-remove'] );
  433. $this->cleanup_option_data( 'wpseo_titles' );
  434. }
  435. }
  436. /**
  437. * Perform the 7.3 upgrade.
  438. *
  439. * @return void
  440. */
  441. private function upgrade_73() {
  442. global $wpdb;
  443. // We've moved the cornerstone checkbox to our proper namespace.
  444. $wpdb->query( "UPDATE $wpdb->postmeta SET meta_key = '_yoast_wpseo_is_cornerstone' WHERE meta_key = '_yst_is_cornerstone'" );
  445. // Remove the previous Whip dismissed message, as this is a new one regarding PHP 5.2.
  446. delete_option( 'whip_dismiss_timestamp' );
  447. }
  448. /**
  449. * Performs the 7.4 upgrade.
  450. *
  451. * @return void
  452. */
  453. private function upgrade_74() {
  454. $this->remove_sitemap_validators();
  455. }
  456. /**
  457. * Performs the 7.5.3 upgrade.
  458. *
  459. * When upgrading purging media is potentially relevant.
  460. *
  461. * @return void
  462. */
  463. private function upgrade_753() {
  464. // Only when attachments are not disabled.
  465. if ( WPSEO_Options::get( 'disable-attachment' ) === true ) {
  466. return;
  467. }
  468. // Only when attachments are not no-indexed.
  469. if ( WPSEO_Options::get( 'noindex-attachment' ) === true ) {
  470. return;
  471. }
  472. // Set purging relevancy.
  473. WPSEO_Options::set( 'is-media-purge-relevant', true );
  474. }
  475. /**
  476. * Performs the 7.7 upgrade.
  477. *
  478. * @return void
  479. */
  480. private function upgrade_77() {
  481. // Remove all OpenGraph content image cache.
  482. $this->delete_post_meta( '_yoast_wpseo_post_image_cache' );
  483. }
  484. /**
  485. * Performs the 7.7.2 upgrade.
  486. *
  487. * @return void
  488. */
  489. private function upgrade_772() {
  490. if ( WPSEO_Utils::is_woocommerce_active() ) {
  491. $this->migrate_woocommerce_archive_setting_to_shop_page();
  492. }
  493. }
  494. /**
  495. * Performs the 9.0 upgrade.
  496. *
  497. * @return void
  498. */
  499. private function upgrade_90() {
  500. global $wpdb;
  501. // Invalidate all sitemap cache transients.
  502. WPSEO_Sitemaps_Cache_Validator::cleanup_database();
  503. // Removes all scheduled tasks for hitting the sitemap index.
  504. wp_clear_scheduled_hook( 'wpseo_hit_sitemap_index' );
  505. $wpdb->query( 'DELETE FROM ' . $wpdb->options . ' WHERE option_name LIKE "wpseo_sitemap_%"' );
  506. }
  507. /**
  508. * Performs the 10.0 upgrade.
  509. *
  510. * @return void
  511. */
  512. private function upgrade_100() {
  513. // Removes recalibration notifications.
  514. $this->clean_all_notifications();
  515. // Removes recalibration options.
  516. WPSEO_Options::clean_up( 'wpseo' );
  517. delete_option( 'wpseo_recalibration_beta_mailinglist_subscription' );
  518. }
  519. /**
  520. * Performs the 11.1 upgrade.
  521. *
  522. * @return void
  523. */
  524. private function upgrade_111() {
  525. // Set company_or_person to company when it's an invalid value.
  526. $company_or_person = WPSEO_Options::get( 'company_or_person', '' );
  527. if ( ! in_array( $company_or_person, [ 'company', 'person' ], true ) ) {
  528. WPSEO_Options::set( 'company_or_person', 'company' );
  529. }
  530. }
  531. /**
  532. * Performs the 12.3 upgrade.
  533. *
  534. * Removes the about notice when its still in the database.
  535. */
  536. private function upgrade_123() {
  537. $plugins = [
  538. 'yoast-seo-premium',
  539. 'video-seo-for-wordpress-seo-by-yoast',
  540. 'yoast-news-seo',
  541. 'local-seo-for-yoast-seo',
  542. 'yoast-woocommerce-seo',
  543. 'yoast-acf-analysis',
  544. ];
  545. $center = Yoast_Notification_Center::get();
  546. foreach ( $plugins as $plugin ) {
  547. $center->remove_notification_by_id( 'wpseo-outdated-yoast-seo-plugin-' . $plugin );
  548. }
  549. }
  550. /**
  551. * Performs the 12.4 upgrade.
  552. *
  553. * Removes the Google plus defaults from the database.
  554. */
  555. private function upgrade_124() {
  556. $this->cleanup_option_data( 'wpseo_social' );
  557. }
  558. /**
  559. * Performs the 12.5 upgrade.
  560. */
  561. public function upgrade_125() {
  562. // Disables the force rewrite title when the theme supports it through WordPress.
  563. if ( WPSEO_Options::get( 'forcerewritetitle', false ) && current_theme_supports( 'title-tag' ) ) {
  564. WPSEO_Options::set( 'forcerewritetitle', false );
  565. }
  566. global $wpdb;
  567. $wpdb->query( "DELETE FROM $wpdb->usermeta WHERE meta_key = 'wp_yoast_promo_hide_premium_upsell_admin_block'" );
  568. // Removes the WordPress update notification, because it is no longer necessary when WordPress 5.3 is released.
  569. $center = Yoast_Notification_Center::get();
  570. $center->remove_notification_by_id( 'wpseo-dismiss-wordpress-upgrade' );
  571. }
  572. /**
  573. * Removes all notifications saved in the database under 'wp_yoast_notifications'.
  574. *
  575. * @return void
  576. */
  577. private function clean_all_notifications() {
  578. global $wpdb;
  579. delete_metadata( 'user', 0, $wpdb->get_blog_prefix() . Yoast_Notification_Center::STORAGE_KEY, '', true );
  580. }
  581. /**
  582. * Removes the post meta fields for a given meta key.
  583. *
  584. * @param string $meta_key The meta key.
  585. *
  586. * @return void
  587. */
  588. private function delete_post_meta( $meta_key ) {
  589. global $wpdb;
  590. $deleted = $wpdb->delete( $wpdb->postmeta, [ 'meta_key' => $meta_key ], [ '%s' ] );
  591. if ( $deleted ) {
  592. wp_cache_set( 'last_changed', microtime(), 'posts' );
  593. }
  594. }
  595. /**
  596. * Removes all sitemap validators.
  597. *
  598. * This should be executed on every upgrade routine until we have removed the sitemap caching in the database.
  599. *
  600. * @return void
  601. */
  602. private function remove_sitemap_validators() {
  603. global $wpdb;
  604. // Remove all sitemap validators.
  605. $wpdb->query( "DELETE FROM $wpdb->options WHERE option_name LIKE 'wpseo_sitemap%validator%'" );
  606. }
  607. /**
  608. * Retrieves the option value directly from the database.
  609. *
  610. * @param string $option_name Option to retrieve.
  611. *
  612. * @return array|mixed The content of the option if exists, otherwise an empty array.
  613. */
  614. protected function get_option_from_database( $option_name ) {
  615. global $wpdb;
  616. // Load option directly from the database, to avoid filtering and sanitization.
  617. $sql = $wpdb->prepare( 'SELECT option_value FROM ' . $wpdb->options . ' WHERE option_name = %s', $option_name );
  618. $results = $wpdb->get_results( $sql, ARRAY_A );
  619. if ( ! empty( $results ) ) {
  620. return maybe_unserialize( $results[0]['option_value'] );
  621. }
  622. return [];
  623. }
  624. /**
  625. * Cleans the option to make sure only relevant settings are there.
  626. *
  627. * @param string $option_name Option name save.
  628. *
  629. * @return void
  630. */
  631. protected function cleanup_option_data( $option_name ) {
  632. $data = get_option( $option_name, [] );
  633. if ( ! is_array( $data ) || $data === [] ) {
  634. return;
  635. }
  636. /*
  637. * Clean up the option by re-saving it.
  638. *
  639. * The option framework will remove any settings that are not configured
  640. * for this option, removing any migrated settings.
  641. */
  642. update_option( $option_name, $data );
  643. }
  644. /**
  645. * Saves an option setting to where it should be stored.
  646. *
  647. * @param array $source_data The option containing the value to be migrated.
  648. * @param string $source_setting Name of the key in the "from" option.
  649. * @param string|null $target_setting Name of the key in the "to" option.
  650. *
  651. * @return void
  652. */
  653. protected function save_option_setting( $source_data, $source_setting, $target_setting = null ) {
  654. if ( $target_setting === null ) {
  655. $target_setting = $source_setting;
  656. }
  657. if ( isset( $source_data[ $source_setting ] ) ) {
  658. WPSEO_Options::set( $target_setting, $source_data[ $source_setting ] );
  659. }
  660. }
  661. /**
  662. * Migrates WooCommerce archive settings to the WooCommerce Shop page meta-data settings.
  663. *
  664. * If no Shop page is defined, nothing will be migrated.
  665. *
  666. * @return void
  667. */
  668. private function migrate_woocommerce_archive_setting_to_shop_page() {
  669. $shop_page_id = wc_get_page_id( 'shop' );
  670. if ( $shop_page_id === -1 ) {
  671. return;
  672. }
  673. $title = WPSEO_Meta::get_value( 'title', $shop_page_id );
  674. if ( empty( $title ) ) {
  675. $option_title = WPSEO_Options::get( 'title-ptarchive-product' );
  676. WPSEO_Meta::set_value(
  677. 'title',
  678. $option_title,
  679. $shop_page_id
  680. );
  681. WPSEO_Options::set( 'title-ptarchive-product', '' );
  682. }
  683. $meta_description = WPSEO_Meta::get_value( 'metadesc', $shop_page_id );
  684. if ( empty( $meta_description ) ) {
  685. $option_metadesc = WPSEO_Options::get( 'metadesc-ptarchive-product' );
  686. WPSEO_Meta::set_value(
  687. 'metadesc',
  688. $option_metadesc,
  689. $shop_page_id
  690. );
  691. WPSEO_Options::set( 'metadesc-ptarchive-product', '' );
  692. }
  693. $bc_title = WPSEO_Meta::get_value( 'bctitle', $shop_page_id );
  694. if ( empty( $bc_title ) ) {
  695. $option_bctitle = WPSEO_Options::get( 'bctitle-ptarchive-product' );
  696. WPSEO_Meta::set_value(
  697. 'bctitle',
  698. $option_bctitle,
  699. $shop_page_id
  700. );
  701. WPSEO_Options::set( 'bctitle-ptarchive-product', '' );
  702. }
  703. $noindex = WPSEO_Meta::get_value( 'meta-robots-noindex', $shop_page_id );
  704. if ( $noindex === '0' ) {
  705. $option_noindex = WPSEO_Options::get( 'noindex-ptarchive-product' );
  706. WPSEO_Meta::set_value(
  707. 'meta-robots-noindex',
  708. $option_noindex,
  709. $shop_page_id
  710. );
  711. WPSEO_Options::set( 'noindex-ptarchive-product', false );
  712. }
  713. }
  714. }