PageRenderTime 51ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-content/plugins/all-in-one-seo-pack/app/Common/Migration/Meta.php

https://gitlab.com/ebrjose/comcebu
PHP | 461 lines | 318 code | 55 blank | 88 comment | 39 complexity | b85912302fc591f18cdc11c401152a52 MD5 | raw file
  1. <?php
  2. namespace AIOSEO\Plugin\Common\Migration;
  3. // Exit if accessed directly.
  4. if ( ! defined( 'ABSPATH' ) ) {
  5. exit;
  6. }
  7. // phpcs:disable WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound
  8. use AIOSEO\Plugin\Common\Models;
  9. /**
  10. * Migrates the post meta from V3.
  11. *
  12. * @since 4.0.0
  13. */
  14. class Meta {
  15. /**
  16. * Holds the old options array.
  17. *
  18. * @since 4.0.3
  19. *
  20. * @var array|null
  21. */
  22. protected static $oldOptions = null;
  23. /**
  24. * Migrates the plugin meta data.
  25. *
  26. * @since 4.0.0
  27. *
  28. * @return void
  29. */
  30. public function migrateMeta() {
  31. try {
  32. if ( as_next_scheduled_action( 'aioseo_migrate_post_meta' ) ) {
  33. return;
  34. }
  35. as_schedule_single_action( time() + 30, 'aioseo_migrate_post_meta', [], 'aioseo' );
  36. } catch ( \Exception $e ) {
  37. // Do nothing.
  38. }
  39. }
  40. /**
  41. * Migrates the post meta data from V3.
  42. *
  43. * @since 4.0.0
  44. *
  45. * @return void
  46. */
  47. public function migratePostMeta() {
  48. if ( aioseo()->cache->get( 'v3_migration_in_progress_settings' ) ) {
  49. aioseo()->helpers->scheduleSingleAction( 'aioseo_migrate_post_meta', 30, [], true );
  50. return;
  51. }
  52. $postsPerAction = 50;
  53. $publicPostTypes = implode( "', '", aioseo()->helpers->getPublicPostTypes( true ) );
  54. $timeStarted = gmdate( 'Y-m-d H:i:s', aioseo()->cache->get( 'v3_migration_in_progress_posts' ) );
  55. $postsToMigrate = aioseo()->db
  56. ->start( 'posts' . ' as p' )
  57. ->select( 'p.ID' )
  58. ->leftJoin( 'aioseo_posts as ap', '`p`.`ID` = `ap`.`post_id`' )
  59. ->whereRaw( "( ap.post_id IS NULL OR ap.updated < '$timeStarted' )" )
  60. ->whereRaw( "( p.post_type IN ( '$publicPostTypes' ) )" )
  61. ->whereRaw( 'p.post_status NOT IN( \'auto-draft\' )' )
  62. ->orderBy( 'p.ID DESC' )
  63. ->limit( $postsPerAction )
  64. ->run()
  65. ->result();
  66. if ( ! $postsToMigrate || ! count( $postsToMigrate ) ) {
  67. aioseo()->cache->delete( 'v3_migration_in_progress_posts' );
  68. return;
  69. }
  70. foreach ( $postsToMigrate as $post ) {
  71. $newPostMeta = $this->getMigratedPostMeta( $post->ID );
  72. $aioseoPost = Models\Post::getPost( $post->ID );
  73. $aioseoPost->set( $newPostMeta );
  74. $aioseoPost->save();
  75. $this->updateLocalizedPostMeta( $post->ID, $newPostMeta );
  76. $this->migrateAdditionalPostMeta( $post->ID );
  77. }
  78. if ( count( $postsToMigrate ) === $postsPerAction ) {
  79. try {
  80. as_schedule_single_action( time() + 30, 'aioseo_migrate_post_meta', [], 'aioseo' );
  81. } catch ( \Exception $e ) {
  82. // Do nothing.
  83. }
  84. } else {
  85. aioseo()->cache->delete( 'v3_migration_in_progress_posts' );
  86. }
  87. }
  88. /**
  89. * Returns the migrated post meta for a given post.
  90. *
  91. * @since 4.0.3
  92. *
  93. * @param int $postId The post ID.
  94. * @return array $meta The post meta.
  95. */
  96. public function getMigratedPostMeta( $postId ) {
  97. if ( is_category() || is_tag() || is_tax() || ! is_numeric( $postId ) ) {
  98. return [];
  99. }
  100. if ( null === self::$oldOptions ) {
  101. self::$oldOptions = get_option( 'aioseop_options' );
  102. }
  103. if ( empty( self::$oldOptions ) ) {
  104. return [];
  105. }
  106. $postMeta = aioseo()->db
  107. ->start( 'postmeta' . ' as pm' )
  108. ->select( 'pm.meta_key, pm.meta_value' )
  109. ->where( 'pm.post_id', $postId )
  110. ->whereRaw( "`pm`.`meta_key` LIKE '_aioseop_%'" )
  111. ->run()
  112. ->result();
  113. $mappedMeta = [
  114. '_aioseop_title' => 'title',
  115. '_aioseop_description' => 'description',
  116. '_aioseop_custom_link' => 'canonical_url',
  117. '_aioseop_sitemap_exclude' => '',
  118. '_aioseop_disable' => '',
  119. '_aioseop_noindex' => 'robots_noindex',
  120. '_aioseop_nofollow' => 'robots_nofollow',
  121. '_aioseop_sitemap_priority' => 'priority',
  122. '_aioseop_sitemap_frequency' => 'frequency',
  123. '_aioseop_keywords' => 'keywords',
  124. '_aioseop_opengraph_settings' => ''
  125. ];
  126. $meta = [
  127. 'post_id' => $postId,
  128. ];
  129. if ( ! $postMeta || ! count( $postMeta ) ) {
  130. return $meta;
  131. }
  132. foreach ( $postMeta as $record ) {
  133. $name = $record->meta_key;
  134. $value = $record->meta_value;
  135. if ( ! in_array( $name, array_keys( $mappedMeta ), true ) ) {
  136. continue;
  137. }
  138. switch ( $name ) {
  139. case '_aioseop_description':
  140. $meta[ $mappedMeta[ $name ] ] = aioseo()->helpers->sanitizeOption( aioseo()->migration->helpers->macrosToSmartTags( $value ) );
  141. break;
  142. case '_aioseop_title':
  143. if ( ! empty( $value ) ) {
  144. $meta[ $mappedMeta[ $name ] ] = $this->getPostTitle( $postId, $value );
  145. }
  146. break;
  147. case '_aioseop_sitemap_exclude':
  148. if ( empty( $value ) ) {
  149. break;
  150. }
  151. $this->migrateExcludedPost( $postId );
  152. break;
  153. case '_aioseop_disable':
  154. if ( empty( $value ) ) {
  155. break;
  156. }
  157. $this->migrateSitemapExcludedPost( $postId );
  158. break;
  159. case '_aioseop_noindex':
  160. case '_aioseop_nofollow':
  161. if ( 'on' === (string) $value ) {
  162. $meta['robots_default'] = false;
  163. $meta[ $mappedMeta[ $name ] ] = true;
  164. } elseif ( 'off' === (string) $value ) {
  165. $meta['robots_default'] = false;
  166. }
  167. break;
  168. case '_aioseop_keywords':
  169. $meta[ $mappedMeta[ $name ] ] = aioseo()->migration->helpers->oldKeywordsToNewKeywords( $value );
  170. break;
  171. case '_aioseop_opengraph_settings':
  172. $meta += $this->convertOpenGraphMeta( $value );
  173. break;
  174. case '_aioseop_sitemap_priority':
  175. case '_aioseop_sitemap_frequency':
  176. if ( empty( $value ) ) {
  177. $meta[ $mappedMeta[ $name ] ] = 'default';
  178. break;
  179. }
  180. $meta[ $mappedMeta[ $name ] ] = $value;
  181. break;
  182. default:
  183. $meta[ $mappedMeta[ $name ] ] = esc_html( wp_strip_all_tags( strval( $value ) ) );
  184. break;
  185. }
  186. }
  187. return $meta;
  188. }
  189. /**
  190. * Migrates a given disabled post from V3.
  191. *
  192. * @since 4.0.3
  193. *
  194. * @param int $postId The post ID.
  195. * @return void
  196. */
  197. private function migrateExcludedPost( $postId ) {
  198. $post = get_post( $postId );
  199. if ( ! is_object( $post ) ) {
  200. return;
  201. }
  202. aioseo()->options->sitemap->general->advancedSettings->enable = true;
  203. $excludedPosts = aioseo()->options->sitemap->general->advancedSettings->excludePosts;
  204. foreach ( $excludedPosts as $excludedPost ) {
  205. $excludedPost = json_decode( $excludedPost );
  206. if ( $excludedPost->value === $postId ) {
  207. return;
  208. }
  209. }
  210. $excludedPost = [
  211. 'value' => $post->ID,
  212. 'type' => $post->post_type,
  213. 'label' => $post->post_title,
  214. 'link' => get_permalink( $post )
  215. ];
  216. $excludedPosts[] = wp_json_encode( $excludedPost );
  217. aioseo()->options->sitemap->general->advancedSettings->excludePosts = $excludedPosts;
  218. $deprecatedOptions = aioseo()->internalOptions->internal->deprecatedOptions;
  219. if ( ! in_array( 'excludePosts', $deprecatedOptions, true ) ) {
  220. array_push( $deprecatedOptions, 'excludePosts' );
  221. aioseo()->internalOptions->internal->deprecatedOptions = $deprecatedOptions;
  222. }
  223. }
  224. /**
  225. * Migrates a given sitemap excluded post from V3.
  226. *
  227. * @since 4.0.3
  228. *
  229. * @param int $postId The post ID.
  230. * @return void
  231. */
  232. private function migrateSitemapExcludedPost( $postId ) {
  233. $post = get_post( $postId );
  234. if ( ! is_object( $post ) ) {
  235. return;
  236. }
  237. $excludedPosts = aioseo()->options->deprecated->searchAppearance->advanced->excludePosts;
  238. foreach ( $excludedPosts as $excludedPost ) {
  239. $excludedPost = json_decode( $excludedPost );
  240. if ( $excludedPost->value === $postId ) {
  241. return;
  242. }
  243. }
  244. $excludedPost = [
  245. 'value' => $post->ID,
  246. 'type' => $post->post_type,
  247. 'label' => $post->post_title,
  248. 'link' => get_permalink( $post )
  249. ];
  250. $excludedPosts[] = wp_json_encode( $excludedPost );
  251. aioseo()->options->deprecated->searchAppearance->advanced->excludePosts = $excludedPosts;
  252. }
  253. /**
  254. * Updates the traditional post meta table with the new data.
  255. *
  256. * @since 4.1.0
  257. *
  258. * @param int $postId The post ID.
  259. * @param array $newMeta The new meta data.
  260. * @return void
  261. */
  262. protected function updateLocalizedPostMeta( $postId, $newMeta ) {
  263. $localizedFields = [
  264. 'title',
  265. 'description',
  266. 'keywords',
  267. 'og_title',
  268. 'og_description',
  269. 'og_article_section',
  270. 'og_article_tags',
  271. 'twitter_title',
  272. 'twitter_description'
  273. ];
  274. foreach ( $newMeta as $k => $v ) {
  275. if ( ! in_array( $k, $localizedFields, true ) ) {
  276. continue;
  277. }
  278. if ( in_array( $k, [ 'keywords', 'og_article_tags' ], true ) ) {
  279. $v = ! empty( $v ) ? aioseo()->helpers->jsonTagsToCommaSeparatedList( $v ) : '';
  280. }
  281. update_post_meta( $postId, "_aioseo_{$k}", $v );
  282. }
  283. }
  284. /**
  285. * Migrates additional post meta data.
  286. *
  287. * @since 4.0.2
  288. *
  289. * @param int $postId The post ID.
  290. * @return void
  291. */
  292. public function migrateAdditionalPostMeta( $postId ) {
  293. static $disabled = null;
  294. if ( null === $disabled ) {
  295. $disabled = (
  296. ! aioseo()->options->sitemap->general->enable ||
  297. (
  298. aioseo()->options->sitemap->general->advancedSettings->enable &&
  299. aioseo()->options->sitemap->general->advancedSettings->excludeImages
  300. )
  301. );
  302. }
  303. if ( $disabled ) {
  304. return;
  305. }
  306. aioseo()->sitemap->image->scanPost( $postId );
  307. }
  308. /**
  309. * Maps the old Open Graph meta to the social meta columns in V4.
  310. *
  311. * @since 4.0.0
  312. *
  313. * @param array $ogMeta The old V3 Open Graph meta.
  314. * @return array $meta The mapped meta.
  315. */
  316. public function convertOpenGraphMeta( $ogMeta ) {
  317. $ogMeta = aioseo()->helpers->maybeUnserialize( $ogMeta );
  318. if ( ! is_array( $ogMeta ) ) {
  319. return [];
  320. }
  321. $mappedSocialMeta = [
  322. 'aioseop_opengraph_settings_title' => 'og_title',
  323. 'aioseop_opengraph_settings_desc' => 'og_description',
  324. 'aioseop_opengraph_settings_image' => 'og_image_custom_url',
  325. 'aioseop_opengraph_settings_imagewidth' => 'og_image_width',
  326. 'aioseop_opengraph_settings_imageheight' => 'og_image_height',
  327. 'aioseop_opengraph_settings_video' => 'og_video',
  328. 'aioseop_opengraph_settings_videowidth' => 'og_video_width',
  329. 'aioseop_opengraph_settings_videoheight' => 'og_video_height',
  330. 'aioseop_opengraph_settings_category' => 'og_object_type',
  331. 'aioseop_opengraph_settings_section' => 'og_article_section',
  332. 'aioseop_opengraph_settings_tag' => 'og_article_tags',
  333. 'aioseop_opengraph_settings_setcard' => 'twitter_card',
  334. 'aioseop_opengraph_settings_customimg_twitter' => 'twitter_image_custom_url',
  335. ];
  336. $meta = [];
  337. foreach ( $ogMeta as $name => $value ) {
  338. if ( ! in_array( $name, array_keys( $mappedSocialMeta ), true ) ) {
  339. continue;
  340. }
  341. switch ( $name ) {
  342. case 'aioseop_opengraph_settings_desc':
  343. case 'aioseop_opengraph_settings_title':
  344. $meta[ $mappedSocialMeta[ $name ] ] = aioseo()->helpers->sanitizeOption( aioseo()->migration->helpers->macrosToSmartTags( $value ) );
  345. break;
  346. case 'aioseop_opengraph_settings_image':
  347. $value = strval( $value );
  348. if ( empty( $value ) ) {
  349. break;
  350. }
  351. $meta['og_image_type'] = 'custom_image';
  352. $meta[ $mappedSocialMeta[ $name ] ] = strval( $value );
  353. break;
  354. case 'aioseop_opengraph_settings_video':
  355. $meta[ $mappedSocialMeta[ $name ] ] = esc_url( $value );
  356. break;
  357. case 'aioseop_opengraph_settings_customimg_twitter':
  358. $value = strval( $value );
  359. if ( empty( $value ) ) {
  360. break;
  361. }
  362. $meta['twitter_image_type'] = 'custom_image';
  363. $meta['twitter_use_og'] = false;
  364. $meta[ $mappedSocialMeta[ $name ] ] = strval( $value );
  365. break;
  366. case 'aioseop_opengraph_settings_imagewidth':
  367. case 'aioseop_opengraph_settings_imageheight':
  368. case 'aioseop_opengraph_settings_videowidth':
  369. case 'aioseop_opengraph_settings_videoheight':
  370. $value = intval( $value );
  371. if ( ! $value || $value <= 0 ) {
  372. break;
  373. }
  374. $meta[ $mappedSocialMeta[ $name ] ] = $value;
  375. break;
  376. case 'aioseop_opengraph_settings_tag':
  377. $meta[ $mappedSocialMeta[ $name ] ] = aioseo()->migration->helpers->oldKeywordsToNewKeywords( $value );
  378. break;
  379. default:
  380. $meta[ $mappedSocialMeta[ $name ] ] = esc_html( strval( $value ) );
  381. break;
  382. }
  383. }
  384. return $meta;
  385. }
  386. /**
  387. * Returns the title as it was in V3.
  388. *
  389. * @since 4.0.0
  390. *
  391. * @param int $postId The post ID.
  392. * @param string $seoTitle The old SEO title.
  393. * @return string The title.
  394. */
  395. protected function getPostTitle( $postId, $seoTitle = '' ) {
  396. $post = get_post( $postId );
  397. if ( ! is_object( $post ) ) {
  398. return '';
  399. }
  400. $postType = $post->post_type;
  401. $oldOptions = get_option( 'aioseo_options_v3' );
  402. $titleFormat = isset( $oldOptions[ "aiosp_${postType}_title_format" ] ) ? $oldOptions[ "aiosp_${postType}_title_format" ] : '';
  403. $seoTitle = aioseo()->helpers->pregReplace( '/(%post_title%|%page_title%)/', $seoTitle, $titleFormat );
  404. return aioseo()->helpers->sanitizeOption( aioseo()->migration->helpers->macrosToSmartTags( $seoTitle ) );
  405. }
  406. }