Your IP : 216.73.216.162


Current Path : /home/x/b/o/xbodynamge/namtation/wp-content/
Upload File :
Current File : /home/x/b/o/xbodynamge/namtation/wp-content/Migration.tar

Migration.php000066600000014014151146742350007222 0ustar00<?php
namespace AIOSEO\Plugin\Common\Migration;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

// phpcs:disable WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound

/**
 * Handles the migration from V3 to V4.
 */
class Migration {
	/**
	 * The old V3 options.
	 *
	 * @since 4.0.0
	 *
	 * @var array
	 */
	public $oldOptions = [];

	/**
	 * Meta class instance.
	 *
	 * @since 4.2.7
	 *
	 * @var Meta
	 */
	public $meta = null;

	/**
	 * Helpers class instance.
	 *
	 * @since 4.2.7
	 *
	 * @var Helpers
	 */
	public $helpers = null;

	/**
	 * Class constructor.
	 *
	 * @since 4.0.0
	 */
	public function __construct() {
		$this->meta    = new Meta();
		$this->helpers = new Helpers();

		// NOTE: This needs to go above the is_admin check in order for it to run at all.
		add_action( 'aioseo_migrate_post_meta', [ $this->meta, 'migratePostMeta' ] );

		if ( ! is_admin() ) {
			return;
		}

		if ( wp_doing_ajax() || wp_doing_cron() ) {
			return;
		}

		add_action( 'init', [ $this, 'init' ], 2000 );
	}

	/**
	 * Initializes the class.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	public function init() {
		// Since the version numbers may vary, we only want to compare the first 3 numbers.
		$lastActiveVersion = aioseo()->internalOptions->internal->lastActiveVersion;
		$lastActiveVersion = $lastActiveVersion ? explode( '-', $lastActiveVersion ) : null;

		if ( version_compare( $lastActiveVersion[0], '4.0.0', '<' ) ) {
			aioseo()->internalOptions->internal->migratedVersion = $lastActiveVersion[0];
			add_action( 'wp_loaded', [ $this, 'doMigration' ] );
		}

		// Run our migration again for V4 users between v4.0.0 and v4.0.4.
		if (
			version_compare( $lastActiveVersion[0], '4.0.0', '>=' ) &&
			version_compare( $lastActiveVersion[0], '4.0.4', '<' ) &&
			get_option( 'aioseop_options' )
		) {
			add_action( 'wp_loaded', [ $this, 'redoMetaMigration' ] );
		}

		// Stop migration for new v4 users where it was incorrectly triggered.
		if ( version_compare( $lastActiveVersion[0], '4.0.4', '=' ) && ! get_option( 'aioseop_options' ) ) {
			aioseo()->core->cache->delete( 'v3_migration_in_progress_posts' );
			aioseo()->core->cache->delete( 'v3_migration_in_progress_terms' );

			try {
				aioseo()->actionScheduler->unschedule( 'aioseo_migrate_post_meta' );
				aioseo()->actionScheduler->unschedule( 'aioseo_migrate_term_meta' );
			} catch ( \Exception $e ) {
				// Do nothing.
			}
		}
	}

	/**
	 * Starts the migration.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	public function doMigration() {
		// If our tables do not exist, create them now.
		if ( ! aioseo()->core->db->tableExists( 'aioseo_posts' ) ) {
			aioseo()->updates->addInitialCustomTablesForV4();
		}

		$this->oldOptions = ( new OldOptions() )->oldOptions;

		if (
			! $this->oldOptions ||
			! is_array( $this->oldOptions ) ||
			! count( $this->oldOptions )
		) {
			return;
		}

		update_option( 'aioseo_options_v3', $this->oldOptions );

		aioseo()->core->cache->update( 'v3_migration_in_progress_posts', time(), WEEK_IN_SECONDS );

		$this->migrateSettings();
		$this->meta->migrateMeta();
	}

	/**
	 * Reruns the post meta migration.
	 *
	 * This is meant for users on v4.0.0, v4.0.1 or v4.0.2 where the migration might have failed.
	 *
	 * @since 4.0.3
	 *
	 * @return void
	 */
	public function redoMetaMigration() {
		aioseo()->core->cache->update( 'v3_migration_in_progress_posts', time(), WEEK_IN_SECONDS );
		$this->meta->migrateMeta();
	}

	/**
	 * Migrates the plugin settings.
	 *
	 * @since 4.0.0
	 *
	 * @param  array $oldOptions The old options. We pass it in directly via the Importer/Exporter.
	 * @return void
	 */
	public function migrateSettings( $oldOptions = [] ) {
		if ( empty( $this->oldOptions ) && ! empty( $oldOptions ) ) {
			$this->oldOptions = ( new OldOptions( $oldOptions ) )->oldOptions;

			if (
				! $this->oldOptions ||
				! is_array( $this->oldOptions ) ||
				! count( $this->oldOptions )
			) {
				return;
			}
		}

		aioseo()->core->cache->update( 'v3_migration_in_progress_settings', time() );

		new GeneralSettings();

		if ( ! isset( $this->oldOptions['modules']['aiosp_feature_manager_options'] ) ) {
			new Sitemap();
			aioseo()->core->cache->delete( 'v3_migration_in_progress_settings' );

			return;
		}

		$this->migrateFeatureManager();

		if ( isset( $this->oldOptions['modules']['aiosp_feature_manager_options']['aiosp_feature_manager_enable_opengraph'] ) ) {
			new SocialMeta();
		}

		if ( isset( $this->oldOptions['modules']['aiosp_feature_manager_options']['aiosp_feature_manager_enable_sitemap'] ) ) {
			new Sitemap();
		}

		if ( isset( $this->oldOptions['modules']['aiosp_feature_manager_options']['aiosp_feature_manager_enable_robots'] ) ) {
			new RobotsTxt();
		}

		if ( aioseo()->helpers->isWpmlActive() ) {
			new Wpml();
		}

		aioseo()->core->cache->delete( 'v3_migration_in_progress_settings' );
	}

	/**
	 * Migrates the Feature Manager settings.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	protected function migrateFeatureManager() {
		if ( empty( $this->oldOptions['modules']['aiosp_feature_manager_options'] ) ) {
			return;
		}

		if ( empty( $this->oldOptions['modules']['aiosp_feature_manager_options']['aiosp_feature_manager_enable_opengraph'] ) ) {
			aioseo()->options->social->facebook->general->enable = false;
			aioseo()->options->social->twitter->general->enable  = false;
		}

		if ( empty( $this->oldOptions['modules']['aiosp_feature_manager_options']['aiosp_feature_manager_enable_sitemap'] ) ) {
			aioseo()->options->sitemap->general->enable = false;
			aioseo()->options->sitemap->rss->enable     = false;
		}

		if ( ! empty( $this->oldOptions['modules']['aiosp_feature_manager_options']['aiosp_feature_manager_enable_robots'] ) ) {
			aioseo()->options->tools->robots->enable = true;
		}
	}

	/**
	 * Checks whether the V3 migration is running.
	 *
	 * @since 4.1.8
	 *
	 * @return bool Whether the V3 migration is running.
	 */
	public function isMigrationRunning() {
		return aioseo()->core->cache->get( 'v3_migration_in_progress_settings' ) || aioseo()->core->cache->get( 'v3_migration_in_progress_posts' );
	}
}Sitemap.php000066600000035775151146742350006714 0ustar00<?php
namespace AIOSEO\Plugin\Common\Migration;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

// phpcs:disable WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound

/**
 * Migrates the XML Sitemap settings from V3.
 *
 * @since 4.0.0
 */
class Sitemap {
	/**
	 * The old V3 options.
	 *
	 * @since 4.0.0
	 *
	 * @var array
	 */
	protected $oldOptions = [];

	/**
	 * Class constructor.
	 *
	 * @since 4.0.0
	 */
	public function __construct() {
		$this->oldOptions = aioseo()->migration->oldOptions;

		if ( empty( $this->oldOptions['modules']['aiosp_sitemap_options'] ) ) {
			return;
		}

		$this->checkIfStatic();
		$this->migrateLinksPerIndex();
		$this->migrateIncludedObjects();
		$this->migratePrioFreq();
		$this->migrateAdditionalPages();
		$this->migrateExcludedPages();
		$this->regenerateSitemap();

		$settings = [
			'aiosp_sitemap_indexes'          => [ 'type' => 'boolean', 'newOption' => [ 'sitemap', 'general', 'indexes' ] ],
			'aiosp_sitemap_archive'          => [ 'type' => 'boolean', 'newOption' => [ 'sitemap', 'general', 'date' ] ],
			'aiosp_sitemap_author'           => [ 'type' => 'boolean', 'newOption' => [ 'sitemap', 'general', 'author' ] ],
			'aiosp_sitemap_images'           => [ 'type' => 'boolean', 'newOption' => [ 'sitemap', 'general', 'advancedSettings', 'excludeImages' ] ],
			'aiosp_sitemap_rss_sitemap'      => [ 'type' => 'boolean', 'newOption' => [ 'sitemap', 'rss', 'enable' ] ],
			'aiosp_sitemap_filename'         => [ 'type' => 'string', 'newOption' => [ 'sitemap', 'general', 'filename' ] ],
			'aiosp_sitemap_publication_name' => [ 'type' => 'boolean', 'newOption' => [ 'sitemap', 'news', 'publicationName' ] ],
			'aiosp_sitemap_rewrite'          => [ 'type' => 'boolean', 'newOption' => [ 'deprecated', 'sitemap', 'general', 'advancedSettings', 'dynamic' ] ]
		];

		aioseo()->migration->helpers->mapOldToNew( $settings, $this->oldOptions['modules']['aiosp_sitemap_options'] );

		if (
			aioseo()->options->sitemap->general->advancedSettings->excludePosts ||
			aioseo()->options->sitemap->general->advancedSettings->excludeTerms ||
			aioseo()->options->sitemap->general->advancedSettings->excludeImages ||
			( in_array( 'staticSitemap', aioseo()->internalOptions->internal->deprecatedOptions, true ) && ! aioseo()->options->deprecated->sitemap->general->advancedSettings->dynamic )
		) {
			aioseo()->options->sitemap->general->advancedSettings->enable = true;
		}
	}

	/**
	 * Check if the sitemap is statically generated.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function checkIfStatic() {
		if (
			isset( $this->oldOptions['modules']['aiosp_sitemap_options']['aiosp_sitemap_rewrite'] ) &&
			empty( $this->oldOptions['modules']['aiosp_sitemap_options']['aiosp_sitemap_rewrite'] )
		) {
			$deprecatedOptions = aioseo()->internalOptions->internal->deprecatedOptions;
			array_push( $deprecatedOptions, 'staticSitemap' );
			aioseo()->internalOptions->internal->deprecatedOptions = $deprecatedOptions;

			aioseo()->options->deprecated->sitemap->general->advancedSettings->dynamic = false;
		}
	}

	/**
	 * Migrates the amount of links per sitemap index.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migrateLinksPerIndex() {
		if ( ! empty( $this->oldOptions['modules']['aiosp_sitemap_options']['aiosp_sitemap_max_posts'] ) ) {
			$value = intval( $this->oldOptions['modules']['aiosp_sitemap_options']['aiosp_sitemap_max_posts'] );
			if ( ! $value ) {
				return;
			}
			$value = $value > 50000 ? 50000 : $value;
			aioseo()->options->sitemap->general->linksPerIndex = $value;
		}
	}

	/**
	 * Migrates the excluded object settings.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	protected function migrateExcludedPages() {
		if (
			empty( $this->oldOptions['modules']['aiosp_sitemap_options']['aiosp_sitemap_excl_terms'] ) &&
			empty( $this->oldOptions['modules']['aiosp_sitemap_options']['aiosp_sitemap_excl_pages'] )
		) {
			return;
		}

		$excludedPosts = aioseo()->options->sitemap->general->advancedSettings->excludePosts;
		if ( ! empty( $this->oldOptions['modules']['aiosp_sitemap_options']['aiosp_sitemap_excl_pages'] ) ) {
			$pages = explode( ',', $this->oldOptions['modules']['aiosp_sitemap_options']['aiosp_sitemap_excl_pages'] );
			if ( count( $pages ) ) {
				foreach ( $pages as $page ) {
					$page = trim( $page );
					$id   = intval( $page );
					if ( ! $id ) {
						$post = get_page_by_path( $page, OBJECT, aioseo()->helpers->getPublicPostTypes( true ) );
						if ( $post && is_object( $post ) ) {
							$id = $post->ID;
						}
					}

					if ( $id ) {
						$post = get_post( $id );
						if ( ! is_object( $post ) ) {
							continue;
						}

						$excludedPost        = new \stdClass();
						$excludedPost->value = $id;
						$excludedPost->type  = $post->post_type;
						$excludedPost->label = $post->post_title;
						$excludedPost->link  = get_permalink( $id );

						array_push( $excludedPosts, wp_json_encode( $excludedPost ) );
					}
				}
			}
		}
		aioseo()->options->sitemap->general->advancedSettings->excludePosts = $excludedPosts;

		$excludedTerms = aioseo()->options->sitemap->general->advancedSettings->excludeTerms;
		if ( ! empty( $this->oldOptions['modules']['aiosp_sitemap_options']['aiosp_sitemap_excl_terms'] ) ) {
			foreach ( $this->oldOptions['modules']['aiosp_sitemap_options']['aiosp_sitemap_excl_terms'] as $taxonomy ) {
				foreach ( $taxonomy['terms'] as $id ) {
					$term = get_term( $id );
					if ( ! is_a( $term, 'WP_Term' ) ) {
						continue;
					}

					$excludedTerm        = new \stdClass();
					$excludedTerm->value = $id;
					$excludedTerm->type  = $term->taxonomy;
					$excludedTerm->label = $term->name;
					$excludedTerm->link  = get_term_link( $term );

					array_push( $excludedTerms, wp_json_encode( $excludedTerm ) );
				}
			}
		}
		aioseo()->options->sitemap->general->advancedSettings->excludeTerms = $excludedTerms;
	}

	/**
	 * Migrates the objects that are included in the sitemap.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	protected function migrateIncludedObjects() {
		if (
			! isset( $this->oldOptions['modules']['aiosp_sitemap_options']['aiosp_sitemap_posttypes'] ) &&
			! isset( $this->oldOptions['modules']['aiosp_sitemap_options']['aiosp_sitemap_taxonomies'] )
		) {
			return;
		}

		if ( ! is_array( $this->oldOptions['modules']['aiosp_sitemap_options']['aiosp_sitemap_posttypes'] ) ) {
			$this->oldOptions['modules']['aiosp_sitemap_options']['aiosp_sitemap_posttypes'] = [];
		}

		if ( ! is_array( $this->oldOptions['modules']['aiosp_sitemap_options']['aiosp_sitemap_taxonomies'] ) ) {
			$this->oldOptions['modules']['aiosp_sitemap_options']['aiosp_sitemap_taxonomies'] = [];
		}

		$publicPostTypes  = aioseo()->helpers->getPublicPostTypes( true );
		$publicTaxonomies = aioseo()->helpers->getPublicTaxonomies( true );

		if ( in_array( 'all', $this->oldOptions['modules']['aiosp_sitemap_options']['aiosp_sitemap_posttypes'], true ) ) {
			aioseo()->options->sitemap->general->postTypes->all      = true;
			aioseo()->options->sitemap->general->postTypes->included = array_values( $publicPostTypes );
		} else {
			$allPostTypes = true;
			foreach ( $publicPostTypes as $postType ) {
				if ( ! in_array( $postType, $this->oldOptions['modules']['aiosp_sitemap_options']['aiosp_sitemap_posttypes'], true ) ) {
					$allPostTypes = false;
				}
			}

			aioseo()->options->sitemap->general->postTypes->all      = $allPostTypes;
			aioseo()->options->sitemap->general->postTypes->included = array_values(
				array_intersect( $publicPostTypes, $this->oldOptions['modules']['aiosp_sitemap_options']['aiosp_sitemap_posttypes'] )
			);
		}

		if ( in_array( 'all', $this->oldOptions['modules']['aiosp_sitemap_options']['aiosp_sitemap_taxonomies'], true ) ) {
			aioseo()->options->sitemap->general->taxonomies->all      = true;
			aioseo()->options->sitemap->general->taxonomies->included = array_values( $publicTaxonomies );
		} else {
			$allTaxonomies = true;
			foreach ( $publicTaxonomies as $taxonomy ) {
				if ( ! in_array( $taxonomy, $this->oldOptions['modules']['aiosp_sitemap_options']['aiosp_sitemap_taxonomies'], true ) ) {
					$allTaxonomies = false;
				}
			}

			aioseo()->options->sitemap->general->taxonomies->all      = $allTaxonomies;
			aioseo()->options->sitemap->general->taxonomies->included = array_values(
				array_intersect( $publicTaxonomies, $this->oldOptions['modules']['aiosp_sitemap_options']['aiosp_sitemap_taxonomies'] )
			);
		}
	}

	/**
	 * Migrates the additional pages that are included in the sitemap.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migrateAdditionalPages() {
		if ( empty( $this->oldOptions['modules']['aiosp_sitemap_options']['aiosp_sitemap_addl_pages'] ) ) {
			return;
		}

		$pages = [];
		foreach ( $this->oldOptions['modules']['aiosp_sitemap_options']['aiosp_sitemap_addl_pages'] as $url => $values ) {
			$page               = new \stdClass();
			$page->url          = esc_url( wp_strip_all_tags( $url ) );
			$page->priority     = [ 'label' => $values['prio'], 'value' => $values['prio'] ];
			$page->frequency    = [ 'label' => $values['freq'], 'value' => $values['freq'] ];
			$page->lastModified = gmdate( 'm/d/Y', strtotime( $values['mod'] ) );

			$pages[] = wp_json_encode( $page );
		}

		aioseo()->options->sitemap->general->additionalPages->enable = true;
		aioseo()->options->sitemap->general->additionalPages->pages  = $pages;
	}

	/**
	 * Migrates the priority/frequency settings.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migratePrioFreq() {
		$settings = [
			'aiosp_sitemap_prio_homepage'   => [ 'type' => 'float', 'newOption' => [ 'sitemap', 'general', 'advancedSettings', 'priority', 'homePage', 'priority' ] ],
			'aiosp_sitemap_freq_homepage'   => [ 'type' => 'string', 'newOption' => [ 'sitemap', 'general', 'advancedSettings', 'priority', 'homePage', 'frequency' ] ],
			'aiosp_sitemap_prio_post'       => [ 'type' => 'float', 'newOption' => [ 'sitemap', 'general', 'advancedSettings', 'priority', 'postTypes', 'priority' ] ],
			'aiosp_sitemap_freq_post'       => [ 'type' => 'string', 'newOption' => [ 'sitemap', 'general', 'advancedSettings', 'priority', 'postTypes', 'frequency' ] ],
			'aiosp_sitemap_prio_post_post'  => [ 'type' => 'float', 'newOption' => [ 'sitemap', 'priority', 'postTypes', 'post', 'priority' ], 'dynamic' => true ],
			'aiosp_sitemap_freq_post_post'  => [ 'type' => 'string', 'newOption' => [ 'sitemap', 'priority', 'postTypes', 'post', 'frequency' ], 'dynamic' => true ],
			'aiosp_sitemap_prio_taxonomies' => [ 'type' => 'float', 'newOption' => [ 'sitemap', 'general', 'advancedSettings', 'priority', 'taxonomies', 'priority' ] ],
			'aiosp_sitemap_freq_taxonomies' => [ 'type' => 'string', 'newOption' => [ 'sitemap', 'general', 'advancedSettings', 'priority', 'taxonomies', 'frequency' ] ],
			'aiosp_sitemap_prio_archive'    => [ 'type' => 'float', 'newOption' => [ 'sitemap', 'general', 'advancedSettings', 'priority', 'archive', 'priority' ] ],
			'aiosp_sitemap_freq_archive'    => [ 'type' => 'string', 'newOption' => [ 'sitemap', 'general', 'advancedSettings', 'priority', 'archive', 'frequency' ] ],
			'aiosp_sitemap_prio_author'     => [ 'type' => 'float', 'newOption' => [ 'sitemap', 'general', 'advancedSettings', 'priority', 'author', 'priority' ] ],
			'aiosp_sitemap_freq_author'     => [ 'type' => 'string', 'newOption' => [ 'sitemap', 'general', 'advancedSettings', 'priority', 'author', 'frequency' ] ],
		];

		foreach ( $this->oldOptions['modules']['aiosp_sitemap_options'] as $name => $value ) {
			// Ignore fixed settings.
			if ( in_array( $name, array_keys( $settings ), true ) ) {
				continue;
			}

			$type = false;
			$slug = '';
			if ( preg_match( '#aiosp_sitemap_prio_(.*)#', (string) $name, $slug ) ) {
				$type = 'priority';
			} elseif ( preg_match( '#aiosp_sitemap_freq_(.*)#', (string) $name, $slug ) ) {
				$type = 'frequency';
			}

			if ( empty( $slug ) || empty( $slug[1] ) ) {
				continue;
			}

			$objectSlug = aioseo()->helpers->pregReplace( '#post_(?!tag)|taxonomies_#', '', $slug[1] );

			if ( in_array( $objectSlug, aioseo()->helpers->getPublicPostTypes( true ), true ) ) {
				$settings[ $name ] = [
					'type'      => 'priority' === $type ? 'float' : 'string',
					'newOption' => [ 'sitemap', 'priority', 'postTypes', $objectSlug, $type ],
					'dynamic'   => true
				];
				continue;
			}

			if ( in_array( $objectSlug, aioseo()->helpers->getPublicTaxonomies( true ), true ) ) {
				$settings[ $name ] = [
					'type'      => 'priority' === $type ? 'float' : 'string',
					'newOption' => [ 'sitemap', 'priority', 'taxonomies', $objectSlug, $type ],
					'dynamic'   => true
				];
			}
		}

		$mainOptions    = aioseo()->options->noConflict();
		$dynamicOptions = aioseo()->dynamicOptions->noConflict();
		foreach ( $settings as $name => $values ) {
			// If setting is set to default, do nothing.
			if (
				empty( $this->oldOptions['modules']['aiosp_sitemap_options'][ $name ] ) ||
				'no' === $this->oldOptions['modules']['aiosp_sitemap_options'][ $name ]
			) {
				unset( $settings[ $name ] );
				continue;
			}

			// If value is "Select Individual", set grouped to false.
			$value = $this->oldOptions['modules']['aiosp_sitemap_options'][ $name ];
			if ( 'sel' === $value ) {
				if ( preg_match( '#post$#', (string) $name ) ) {
					aioseo()->options->sitemap->general->advancedSettings->priority->postTypes->grouped = false;
				} else {
					aioseo()->options->sitemap->general->advancedSettings->priority->taxonomies->grouped = false;
				}
				continue;
			}

			$object        = new \stdClass();
			$object->label = $value;
			$object->value = $value;

			$error      = false;
			$options    = ! empty( $values['dynamic'] ) ? $dynamicOptions : $mainOptions;
			$lastOption = '';
			for ( $i = 0; $i < count( $values['newOption'] ); $i++ ) {
				$lastOption = $values['newOption'][ $i ];
				if ( ! $options->has( $lastOption, false ) ) {
					$error = true;
					break;
				}

				if ( count( $values['newOption'] ) - 1 !== $i ) {
					$options = $options->$lastOption;
				}
			}

			if ( $error ) {
				continue;
			}

			$options->$lastOption = wp_json_encode( $object );
		}

		if ( count( $settings ) ) {
			$mainOptions->sitemap->general->advancedSettings->enable = true;
		}
	}

	/**
	 * Regenerates the sitemap if it is static.
	 *
	 * We need to do this since the stylesheet URLs have changed.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function regenerateSitemap() {
		if (
			isset( $this->oldOptions['modules']['aiosp_sitemap_options']['aiosp_sitemap_rewrite'] ) &&
			empty( $this->oldOptions['modules']['aiosp_sitemap_options']['aiosp_sitemap_rewrite'] )
		) {
			$files         = aioseo()->sitemap->file->files();
			$detectedFiles = [];
			foreach ( $files as $filename ) {
				// We don't want to delete the video sitemap here at all.
				$isVideoSitemap = preg_match( '#.*video.*#', (string) $filename ) ? true : false;
				if ( ! $isVideoSitemap ) {
					$detectedFiles[] = $filename;
				}
			}

			$fs = aioseo()->core->fs;
			if ( count( $detectedFiles ) && $fs->isWpfsValid() ) {
				foreach ( $detectedFiles as $file ) {
					$fs->fs->delete( $file, false, 'f' );
				}
			}

			aioseo()->sitemap->file->generate( true );
		}
	}
}Meta.php000066600000031130151146742350006155 0ustar00<?php
namespace AIOSEO\Plugin\Common\Migration;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

// phpcs:disable WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound

use AIOSEO\Plugin\Common\Models;

/**
 * Migrates the post meta from V3.
 *
 * @since 4.0.0
 */
class Meta {
	/**
	 * Holds the old options array.
	 *
	 * @since 4.0.3
	 *
	 * @var array|null
	 */
	protected static $oldOptions = null;

	/**
	 * Migrates the plugin meta data.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	public function migrateMeta() {
		try {
			if ( as_next_scheduled_action( 'aioseo_migrate_post_meta' ) ) {
				return;
			}

			as_schedule_single_action( time() + 30, 'aioseo_migrate_post_meta', [], 'aioseo' );
		} catch ( \Exception $e ) {
			// Do nothing.
		}
	}

	/**
	 * Migrates the post meta data from V3.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	public function migratePostMeta() {
		if ( aioseo()->core->cache->get( 'v3_migration_in_progress_settings' ) ) {
			aioseo()->actionScheduler->scheduleSingle( 'aioseo_migrate_post_meta', 30, [], true );

			return;
		}

		$postsPerAction  = 50;
		$publicPostTypes = implode( "', '", aioseo()->helpers->getPublicPostTypes( true ) );
		$timeStarted     = gmdate( 'Y-m-d H:i:s', aioseo()->core->cache->get( 'v3_migration_in_progress_posts' ) );

		$postsToMigrate = aioseo()->core->db
			->start( 'posts' . ' as p' )
			->select( 'p.ID' )
			->leftJoin( 'aioseo_posts as ap', '`p`.`ID` = `ap`.`post_id`' )
			->whereRaw( "( ap.post_id IS NULL OR ap.updated < '$timeStarted' )" )
			->whereRaw( "( p.post_type IN ( '$publicPostTypes' ) )" )
			->whereRaw( 'p.post_status NOT IN( \'auto-draft\' )' )
			->orderBy( 'p.ID DESC' )
			->limit( $postsPerAction )
			->run()
			->result();

		if ( ! $postsToMigrate || ! count( $postsToMigrate ) ) {
			aioseo()->core->cache->delete( 'v3_migration_in_progress_posts' );

			return;
		}

		foreach ( $postsToMigrate as $post ) {
			$newPostMeta = $this->getMigratedPostMeta( $post->ID );

			$aioseoPost = Models\Post::getPost( $post->ID );
			$aioseoPost->set( $newPostMeta );
			$aioseoPost->save();

			$this->updateLocalizedPostMeta( $post->ID, $newPostMeta );
			$this->migrateAdditionalPostMeta( $post->ID );
		}

		if ( count( $postsToMigrate ) === $postsPerAction ) {
			try {
				as_schedule_single_action( time() + 30, 'aioseo_migrate_post_meta', [], 'aioseo' );
			} catch ( \Exception $e ) {
				// Do nothing.
			}
		} else {
			aioseo()->core->cache->delete( 'v3_migration_in_progress_posts' );
		}
	}

	/**
	 * Returns the migrated post meta for a given post.
	 *
	 * @since 4.0.3
	 *
	 * @param  int   $postId The post ID.
	 * @return array         The post meta.
	 */
	public function getMigratedPostMeta( $postId ) {
		if ( is_category() || is_tag() || is_tax() || ! is_numeric( $postId ) ) {
			return [];
		}

		if ( null === self::$oldOptions ) {
			self::$oldOptions = get_option( 'aioseop_options' );
		}

		if ( empty( self::$oldOptions ) ) {
			return [];
		}

		$postMeta = aioseo()->core->db
			->start( 'postmeta' . ' as pm' )
			->select( 'pm.meta_key, pm.meta_value' )
			->where( 'pm.post_id', $postId )
			->whereRaw( "`pm`.`meta_key` LIKE '_aioseop_%'" )
			->run()
			->result();

		$mappedMeta = [
			'_aioseop_title'              => 'title',
			'_aioseop_description'        => 'description',
			'_aioseop_custom_link'        => 'canonical_url',
			'_aioseop_sitemap_exclude'    => '',
			'_aioseop_disable'            => '',
			'_aioseop_noindex'            => 'robots_noindex',
			'_aioseop_nofollow'           => 'robots_nofollow',
			'_aioseop_sitemap_priority'   => 'priority',
			'_aioseop_sitemap_frequency'  => 'frequency',
			'_aioseop_keywords'           => 'keywords',
			'_aioseop_opengraph_settings' => ''
		];

		$meta = [
			'post_id' => $postId,
		];

		if ( ! $postMeta || ! count( $postMeta ) ) {
			return $meta;
		}

		foreach ( $postMeta as $record ) {
			$name  = $record->meta_key;
			$value = $record->meta_value;

			if ( ! in_array( $name, array_keys( $mappedMeta ), true ) ) {
				continue;
			}

			switch ( $name ) {
				case '_aioseop_description':
					$meta[ $mappedMeta[ $name ] ] = aioseo()->helpers->sanitizeOption( aioseo()->migration->helpers->macrosToSmartTags( $value ) );
					break;
				case '_aioseop_title':
					if ( ! empty( $value ) ) {
						$meta[ $mappedMeta[ $name ] ] = $this->getPostTitle( $postId, $value );
					}
					break;
				case '_aioseop_sitemap_exclude':
					if ( empty( $value ) ) {
						break;
					}
					$this->migrateExcludedPost( $postId );
					break;
				case '_aioseop_disable':
					if ( empty( $value ) ) {
						break;
					}
					$this->migrateSitemapExcludedPost( $postId );
					break;
				case '_aioseop_noindex':
				case '_aioseop_nofollow':
					if ( 'on' === (string) $value ) {
						$meta['robots_default']       = false;
						$meta[ $mappedMeta[ $name ] ] = true;
					} elseif ( 'off' === (string) $value ) {
						$meta['robots_default'] = false;
					}
					break;
				case '_aioseop_keywords':
					$meta[ $mappedMeta[ $name ] ] = aioseo()->migration->helpers->oldKeywordsToNewKeywords( $value );
					break;
				case '_aioseop_opengraph_settings':
					$meta += $this->convertOpenGraphMeta( $value );
					break;
				case '_aioseop_sitemap_priority':
				case '_aioseop_sitemap_frequency':
					if ( empty( $value ) ) {
						$meta[ $mappedMeta[ $name ] ] = 'default';
						break;
					}
					$meta[ $mappedMeta[ $name ] ] = $value;
					break;
				default:
					$meta[ $mappedMeta[ $name ] ] = esc_html( wp_strip_all_tags( strval( $value ) ) );
					break;
			}
		}

		return $meta;
	}

	/**
	 * Migrates a given disabled post from V3.
	 *
	 * @since 4.0.3
	 *
	 * @param  int  $postId The post ID.
	 * @return void
	 */
	private function migrateExcludedPost( $postId ) {
		$post = get_post( $postId );
		if ( ! is_object( $post ) ) {
			return;
		}

		aioseo()->options->sitemap->general->advancedSettings->enable = true;
		$excludedPosts = aioseo()->options->sitemap->general->advancedSettings->excludePosts;

		foreach ( $excludedPosts as $excludedPost ) {
			$excludedPost = json_decode( $excludedPost );
			if ( $excludedPost->value === $postId ) {
				return;
			}
		}

		$excludedPost = [
			'value' => $post->ID,
			'type'  => $post->post_type,
			'label' => $post->post_title,
			'link'  => get_permalink( $post )
		];

		$excludedPosts[] = wp_json_encode( $excludedPost );
		aioseo()->options->sitemap->general->advancedSettings->excludePosts = $excludedPosts;

		$deprecatedOptions = aioseo()->internalOptions->internal->deprecatedOptions;
		if ( ! in_array( 'excludePosts', $deprecatedOptions, true ) ) {
			array_push( $deprecatedOptions, 'excludePosts' );
			aioseo()->internalOptions->internal->deprecatedOptions = $deprecatedOptions;
		}
	}

	/**
	 * Migrates a given sitemap excluded post from V3.
	 *
	 * @since 4.0.3
	 *
	 * @param  int  $postId The post ID.
	 * @return void
	 */
	private function migrateSitemapExcludedPost( $postId ) {
		$post = get_post( $postId );
		if ( ! is_object( $post ) ) {
			return;
		}

		$excludedPosts = aioseo()->options->deprecated->searchAppearance->advanced->excludePosts;
		foreach ( $excludedPosts as $excludedPost ) {
			$excludedPost = json_decode( $excludedPost );
			if ( $excludedPost->value === $postId ) {
				return;
			}
		}

		$excludedPost = [
			'value' => $post->ID,
			'type'  => $post->post_type,
			'label' => $post->post_title,
			'link'  => get_permalink( $post )
		];

		$excludedPosts[] = wp_json_encode( $excludedPost );
		aioseo()->options->deprecated->searchAppearance->advanced->excludePosts = $excludedPosts;
	}

	/**
	 * Updates the traditional post meta table with the new data.
	 *
	 * @since 4.1.0
	 *
	 * @param  int   $postId  The post ID.
	 * @param  array $newMeta The new meta data.
	 * @return void
	 */
	protected function updateLocalizedPostMeta( $postId, $newMeta ) {
		$localizedFields = [
			'title',
			'description',
			'keywords',
			'og_title',
			'og_description',
			'og_article_section',
			'og_article_tags',
			'twitter_title',
			'twitter_description'
		];

		foreach ( $newMeta as $k => $v ) {
			if ( ! in_array( $k, $localizedFields, true ) ) {
				continue;
			}

			if ( in_array( $k, [ 'keywords', 'og_article_tags' ], true ) ) {
				$v = ! empty( $v ) ? aioseo()->helpers->jsonTagsToCommaSeparatedList( $v ) : '';
			}

			update_post_meta( $postId, "_aioseo_{$k}", $v );
		}
	}

	/**
	 * Migrates additional post meta data.
	 *
	 * @since 4.0.2
	 *
	 * @param  int  $postId The post ID.
	 * @return void
	 */
	public function migrateAdditionalPostMeta( $postId ) {
		static $disabled = null;

		if ( null === $disabled ) {
			$disabled = (
				! aioseo()->options->sitemap->general->enable ||
				(
					aioseo()->options->sitemap->general->advancedSettings->enable &&
					aioseo()->options->sitemap->general->advancedSettings->excludeImages
				)
			);
		}
		if ( $disabled ) {
			return;
		}

		aioseo()->sitemap->image->scanPost( $postId );
	}

	/**
	 * Maps the old Open Graph meta to the social meta columns in V4.
	 *
	 * @since 4.0.0
	 *
	 * @param  array $ogMeta The old V3 Open Graph meta.
	 * @return array $meta   The mapped meta.
	 */
	public function convertOpenGraphMeta( $ogMeta ) {
		$ogMeta = aioseo()->helpers->maybeUnserialize( $ogMeta );

		if ( ! is_array( $ogMeta ) ) {
			return [];
		}

		$mappedSocialMeta = [
			'aioseop_opengraph_settings_title'             => 'og_title',
			'aioseop_opengraph_settings_desc'              => 'og_description',
			'aioseop_opengraph_settings_image'             => 'og_image_custom_url',
			'aioseop_opengraph_settings_imagewidth'        => 'og_image_width',
			'aioseop_opengraph_settings_imageheight'       => 'og_image_height',
			'aioseop_opengraph_settings_video'             => 'og_video',
			'aioseop_opengraph_settings_videowidth'        => 'og_video_width',
			'aioseop_opengraph_settings_videoheight'       => 'og_video_height',
			'aioseop_opengraph_settings_category'          => 'og_object_type',
			'aioseop_opengraph_settings_section'           => 'og_article_section',
			'aioseop_opengraph_settings_tag'               => 'og_article_tags',
			'aioseop_opengraph_settings_setcard'           => 'twitter_card',
			'aioseop_opengraph_settings_customimg_twitter' => 'twitter_image_custom_url',
		];

		$meta = [];
		foreach ( $ogMeta as $name => $value ) {
			if ( ! in_array( $name, array_keys( $mappedSocialMeta ), true ) ) {
				continue;
			}

			switch ( $name ) {
				case 'aioseop_opengraph_settings_desc':
				case 'aioseop_opengraph_settings_title':
					$meta[ $mappedSocialMeta[ $name ] ] = aioseo()->helpers->sanitizeOption( aioseo()->migration->helpers->macrosToSmartTags( $value ) );
					break;
				case 'aioseop_opengraph_settings_image':
					$value = strval( $value );
					if ( empty( $value ) ) {
						break;
					}

					$meta['og_image_type']              = 'custom_image';
					$meta[ $mappedSocialMeta[ $name ] ] = strval( $value );
					break;
				case 'aioseop_opengraph_settings_video':
					$meta[ $mappedSocialMeta[ $name ] ] = esc_url( $value );
					break;
				case 'aioseop_opengraph_settings_customimg_twitter':
					$value = strval( $value );
					if ( empty( $value ) ) {
						break;
					}
					$meta['twitter_image_type']         = 'custom_image';
					$meta['twitter_use_og']             = false;
					$meta[ $mappedSocialMeta[ $name ] ] = strval( $value );
					break;
				case 'aioseop_opengraph_settings_imagewidth':
				case 'aioseop_opengraph_settings_imageheight':
				case 'aioseop_opengraph_settings_videowidth':
				case 'aioseop_opengraph_settings_videoheight':
					$value = intval( $value );
					if ( ! $value || $value <= 0 ) {
						break;
					}
					$meta[ $mappedSocialMeta[ $name ] ] = $value;
					break;
				case 'aioseop_opengraph_settings_tag':
					$meta[ $mappedSocialMeta[ $name ] ] = aioseo()->migration->helpers->oldKeywordsToNewKeywords( $value );
					break;
				default:
					$meta[ $mappedSocialMeta[ $name ] ] = esc_html( strval( $value ) );
					break;
			}
		}

		return $meta;
	}

	/**
	 * Returns the title as it was in V3.
	 *
	 * @since 4.0.0
	 *
	 * @param  int    $postId   The post ID.
	 * @param  string $seoTitle The old SEO title.
	 * @return string           The title.
	 */
	protected function getPostTitle( $postId, $seoTitle = '' ) {
		$post = get_post( $postId );
		if ( ! is_object( $post ) ) {
			return '';
		}

		$postType    = $post->post_type;
		$oldOptions  = get_option( 'aioseo_options_v3' );
		$titleFormat = isset( $oldOptions[ "aiosp_{$postType}_title_format" ] ) ? $oldOptions[ "aiosp_{$postType}_title_format" ] : '';

		$seoTitle = aioseo()->helpers->pregReplace( '/(%post_title%|%page_title%)/', $seoTitle, $titleFormat );

		return aioseo()->helpers->sanitizeOption( aioseo()->migration->helpers->macrosToSmartTags( $seoTitle ) );
	}
}OldOptions.php000066600000014772151146742350007376 0ustar00<?php
namespace AIOSEO\Plugin\Common\Migration;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Updates and holds the old options from V3.
 *
 * @since 4.0.0
 */
class OldOptions {
	/**
	 * The old options from V3.
	 *
	 * @since 4.0.0
	 *
	 * @var array
	 */
	public $oldOptions = [];

	/**
	 * Class constructor.
	 *
	 * @since 4.0.0
	 *
	 * @param array $oldOptions The old options. We pass it in directly via the Importer/Exporter.
	 */
	public function __construct( $oldOptions = [] ) {
		$this->oldOptions = ! empty( $oldOptions ) ? $oldOptions : get_option( 'aioseop_options' );

		if (
			! $this->oldOptions ||
			! is_array( $this->oldOptions ) ||
			! count( $this->oldOptions )
		) {
			return;
		}

		$this->runPreV4Migrations();
		$this->fixSettingValues();
	}

	/**
	 * Runs all pre-V4 migrations to update the old options to the latest state.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	public function runPreV4Migrations() {
		$lastActiveVersion = aioseo()->internalOptions->internal->lastActiveVersion;
		if ( version_compare( $lastActiveVersion, aioseo()->version, '<' ) ) {

			$this->doVersionUpdates( $lastActiveVersion );
			aioseo()->internalOptions->internal->lastActiveVersion = aioseo()->version;
		}
	}

	/**
	 * Runs all pre-V4 version-based migrations.
	 *
	 * @since 4.0.0
	 *
	 * @param  string $oldVersion The old version number to compare against.
	 * @return void
	 */
	protected function doVersionUpdates( $oldVersion ) {
		if ( version_compare( $oldVersion, '3.0', '<' ) ) {
			$this->sitemapExclTerms201905();
		}

		if ( version_compare( $oldVersion, '3.1', '<' ) ) {
			$this->resetFlushRewriteRules201906();
		}

		if (
			version_compare( $oldVersion, '3.2', '<' ) ||
			version_compare( $oldVersion, '3.2.6', '<' )
		) {
			$this->updateSchemaMarkup201907();
		}

		if ( version_compare( $oldVersion, '4.0.0', '<' ) ) {
			$this->updateArchiveNoIndexSettings20200413();
			$this->updateArchiveTitleFormatSettings20200413();
		}
	}

	/**
	 * Converts "excl_categories" to "excl_terms".
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	protected function sitemapExclTerms201905() {
		if (
			empty( $this->oldOptions['modules'] ) ||
			empty( $this->oldOptions['modules']['aiosp_sitemap_options'] )
		) {
			return;
		}

		$options = $this->oldOptions['modules']['aiosp_sitemap_options'];
		if ( ! empty( $options['aiosp_sitemap_excl_categories'] ) ) {
			$options['aiosp_sitemap_excl_terms']['category']['taxonomy'] = 'category';
			$options['aiosp_sitemap_excl_terms']['category']['terms']    = $options['aiosp_sitemap_excl_categories'];
			unset( $options['aiosp_sitemap_excl_categories'] );

			$this->oldOptions['modules']['aiosp_sitemap_options'] = $options;
		}
	}

	/**
	 * Flushes rewrite rules for XML Sitemap URL changes.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	protected function resetFlushRewriteRules201906() {
		add_action( 'shutdown', 'flush_rewrite_rules' );
	}

	/**
	 * Adds a number of schema markup settings.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	protected function updateSchemaMarkup201907() {
		$updateValues = [
			'aiosp_schema_markup'               => '1',
			'aiosp_schema_search_results_page'  => '1',
			'aiosp_schema_social_profile_links' => '',
			'aiosp_schema_site_represents'      => 'organization',
			'aiosp_schema_organization_name'    => '',
			'aiosp_schema_organization_logo'    => '',
			'aiosp_schema_person_user'          => '1',
			'aiosp_schema_phone_number'         => '',
			'aiosp_schema_contact_type'         => 'none',
		];

		if ( isset( $this->oldOptions['aiosp_schema_markup'] ) ) {
			if ( empty( $this->oldOptions['aiosp_schema_markup'] ) || 'off' === $this->oldOptions['aiosp_schema_markup'] ) {
				$updateValues['aiosp_schema_markup'] = '0';
			}
		}
		if ( isset( $this->oldOptions['aiosp_google_sitelinks_search'] ) ) {
			if ( empty( $this->oldOptions['aiosp_google_sitelinks_search'] ) || 'off' === $this->oldOptions['aiosp_google_sitelinks_search'] ) {
				$updateValues['aiosp_schema_search_results_page'] = '0';
			}
		}
		if ( isset( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_profile_links'] ) ) {
			$updateValues['aiosp_schema_social_profile_links'] = $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_profile_links'];
		}
		if ( isset( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_person_or_org'] ) ) {
			if ( 'person' === $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_person_or_org'] ) {
				$updateValues['aiosp_schema_site_represents'] = 'person';
			}
		}
		if ( isset( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_social_name'] ) ) {
			$updateValues['aiosp_schema_organization_name'] = $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_social_name'];
		}

		foreach ( $updateValues as $k => $v ) {
			$this->oldOptions[ $k ] = $v;
		}
	}

	/**
	 * Migrate setting for noindex archives.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	protected function updateArchiveNoIndexSettings20200413() {
		if ( isset( $this->oldOptions['aiosp_archive_noindex'] ) ) {
			$this->oldOptions['aiosp_archive_date_noindex']   = $this->oldOptions['aiosp_archive_noindex'];
			$this->oldOptions['aiosp_archive_author_noindex'] = $this->oldOptions['aiosp_archive_noindex'];
			unset( $this->oldOptions['aiosp_archive_noindex'] );
		}
	}

	/**
	 * Migrate settings for archive title formats.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	protected function updateArchiveTitleFormatSettings20200413() {
		if (
			isset( $this->oldOptions['aiosp_archive_title_format'] ) &&
			empty( $this->oldOptions['aiosp_date_title_format'] )
		) {
			$this->oldOptions['aiosp_date_title_format'] = $this->oldOptions['aiosp_archive_title_format'];
			unset( $this->oldOptions['aiosp_archive_title_format'] );
		}

		if (
			isset( $this->oldOptions['aiosp_archive_title_format'] ) &&
			'%date% | %site_title%' === $this->oldOptions['aiosp_archive_title_format']
		) {
			unset( $this->oldOptions['aiosp_archive_title_format'] );
		}
	}

	/**
	 * Corrects the value of a number of settings in V3 that are illogical.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	protected function fixSettingValues() {
		$settingsToFix = [
			'aiosp_togglekeywords'
		];
		foreach ( $settingsToFix as $settingToFix ) {
			if ( isset( $this->oldOptions[ $settingToFix ] ) ) {
				if ( '1' === (string) $this->oldOptions[ $settingToFix ] ) {
					$this->oldOptions[ $settingToFix ] = '';
					continue;
				}
				$this->oldOptions[ $settingToFix ] = 'on';
			}
		}
	}
}SocialMeta.php000066600000045565151146742350007331 0ustar00<?php
namespace AIOSEO\Plugin\Common\Migration;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use AIOSEO\Plugin\Common\Models;

// phpcs:disable WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound

/**
 * Migrates the Social Meta settings from V3.
 *
 * @since 4.0.0
 */
class SocialMeta {
	/**
	 * The old V3 options.
	 *
	 * @since 4.0.0
	 *
	 * @var array
	 */
	protected $oldOptions = [];

	/**
	 * Class constructor.
	 *
	 * @since 4.0.0
	 */
	public function __construct() {
		$this->oldOptions = aioseo()->migration->oldOptions;

		if ( empty( $this->oldOptions['modules']['aiosp_opengraph_options'] ) ) {
			return;
		}

		$this->migrateHomePageOgTitle();
		$this->migrateHomePageOgDescription();
		$this->migrateTwitterUsername();
		$this->migrateTwitterCardType();
		$this->migrateSocialPostImageSettings();
		$this->migrateDefaultObjectTypes();
		$this->migrateAdvancedSettings();
		$this->migrateProfileSocialUrls();

		if ( ! empty( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_sitename'] ) ) {
			aioseo()->options->social->facebook->general->siteName = aioseo()->helpers->sanitizeOption( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_sitename'] );
		}

		$settings = [
			'aiosp_opengraph_facebook_author' => [ 'type' => 'boolean', 'newOption' => [ 'social', 'facebook', 'general', 'showAuthor' ] ],
			'aiosp_opengraph_twitter_creator' => [ 'type' => 'boolean', 'newOption' => [ 'social', 'twitter', 'general', 'showAuthor' ] ],
		];

		aioseo()->migration->helpers->mapOldToNew( $settings, $this->oldOptions['modules']['aiosp_opengraph_options'] );

		$this->maybeShowOgNotices();
	}

	/**
	 * Check if we need to add a notice about the OG deprecated settings.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function maybeShowOgNotices() {
		$include = [];

		// Check if any of thw following are set to true.
		if ( ! empty( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_generate_descriptions'] ) ) {
			$include[] = __( 'Use Content for Autogenerated Descriptions', 'all-in-one-seo-pack' );
		}

		if ( ! empty( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_description_shortcodes'] ) ) {
			$include[] = __( 'Run Shortcodes in Description', 'all-in-one-seo-pack' );
		}

		if ( ! empty( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_title_shortcodes'] ) ) {
			$include[] = __( 'Run Shortcodes in Title', 'all-in-one-seo-pack' );
		}

		if ( empty( $include ) ) {
			return;
		}

		$content = __( 'Due to some changes in how our Open Graph integration works, your Facebook Titles and Descriptions may have changed. You were using the following options that have been removed:', 'all-in-one-seo-pack' ) . '<ul>'; // phpcs:ignore Generic.Files.LineLength.MaxExceeded

		foreach ( $include as $setting ) {
			$content .= '<li><strong>' . $setting . '</strong></li>';
		}

		$content .= '</ul>';

		$notification = Models\Notification::getNotificationByName( 'v3-migration-deprecated-opengraph' );
		if ( $notification->notification_name ) {
			return;
		}

		Models\Notification::addNotification( [
			'slug'              => uniqid(),
			'notification_name' => 'v3-migration-deprecated-opengraph',
			'title'             => __( 'Review Your Facebook Open Graph Titles and Descriptions', 'all-in-one-seo-pack' ),
			'content'           => $content,
			'type'              => 'warning',
			'level'             => [ 'all' ],
			'button1_label'     => __( 'Learn More', 'all-in-one-seo-pack' ),
			'button1_action'    => aioseo()->helpers->utmUrl( AIOSEO_MARKETING_URL . 'docs/deprecated-opengraph-settings', 'notifications-center', 'v3-migration-deprecated-opengraph' ),
			'start'             => gmdate( 'Y-m-d H:i:s' )
		] );
	}

	/**
	 * Migrates the Open Graph homepage title.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migrateHomePageOgTitle() {
		$showOnFront        = get_option( 'show_on_front' );
		$pageOnFront        = (int) get_option( 'page_on_front' );
		$useHomePageMeta    = ! empty( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_setmeta'] );
		$format             = $this->oldOptions['aiosp_home_page_title_format'];

		// Latest Posts.
		if ( 'posts' === $showOnFront ) {
			$ogTitle = aioseo()->helpers->pregReplace( '#%page_title%#', '#site_title', $format );
			if ( ! $useHomePageMeta ) {
				if ( ! empty( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_hometitle'] ) ) {
					$ogTitle = $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_hometitle'];
				}
				aioseo()->options->social->facebook->homePage->title = aioseo()->helpers->sanitizeOption( aioseo()->migration->helpers->macrosToSmartTags( $ogTitle ) );
				aioseo()->options->social->twitter->homePage->title  = aioseo()->helpers->sanitizeOption( aioseo()->migration->helpers->macrosToSmartTags( $ogTitle ) );

				return;
			}
			$title   = aioseo()->options->searchAppearance->global->siteTitle;
			$ogTitle = $title ? $title : $ogTitle;
			aioseo()->options->social->facebook->homePage->title = aioseo()->helpers->sanitizeOption( $ogTitle );
			aioseo()->options->social->twitter->homePage->title  = aioseo()->helpers->sanitizeOption( $ogTitle );

			return;
		}

		// Static Home Page.
		$post       = 'page' === $showOnFront && $pageOnFront ? aioseo()->helpers->getPost( $pageOnFront ) : '';
		$aioseoPost = Models\Post::getPost( $post->ID );
		$seoTitle   = get_post_meta( $post->ID, '_aioseop_title', true );
		$ogMeta     = get_post_meta( $post->ID, '_aioseop_opengraph_settings', true );

		if ( ! $ogMeta ) {
			return;
		}

		$ogMeta = aioseo()->helpers->maybeUnserialize( $ogMeta );

		$ogTitle = '';
		if ( ! $useHomePageMeta ) {
			if ( empty( $this->oldOptions['aiosp_use_static_home_info'] ) ) {
				$ogTitle = ! empty( $this->oldOptions['aiosp_home_title'] ) ? $this->oldOptions['aiosp_home_title'] : $ogTitle;
				if ( ! empty( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_hometitle'] ) ) {
					$ogTitle = $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_hometitle'];
				}
				if ( ! empty( $ogMeta['aioseop_opengraph_settings_title'] ) ) {
					$ogTitle = $ogMeta['aioseop_opengraph_settings_title'];
				} elseif ( ! empty( $seoTitle ) ) {
					if ( empty( $ogTitle ) ) {
						$ogTitle = $seoTitle;
					} elseif ( empty( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_hometitle'] ) ) {
						$ogTitle = $seoTitle;
					}
				}
			}
		} else {
			if ( empty( $this->oldOptions['aiosp_use_static_home_info'] ) ) {
				$ogTitle = $aioseoPost->title;
				if ( ! empty( $ogMeta['aioseop_opengraph_settings_title'] ) ) {
					$ogTitle = $ogMeta['aioseop_opengraph_settings_title'];
				}
				$ogTitle = ! empty( $this->oldOptions['aiosp_home_title'] ) ? $this->oldOptions['aiosp_home_title'] : $ogTitle;
				if ( ! empty( $seoTitle ) ) {
					$ogTitle = $seoTitle;
				}
			} else {
				$ogTitle = ! empty( $seoTitle ) ? $seoTitle : $ogTitle;
			}
		}

		$ogTitle = aioseo()->helpers->sanitizeOption( aioseo()->migration->helpers->macrosToSmartTags( $ogTitle ) );
		$aioseoPost->set( [
			'post_id'       => $post->ID,
			'og_title'      => $ogTitle,
			'twitter_title' => $ogTitle
		] );
		$aioseoPost->save();
	}

	/**
	 * Migrates the Open Graph homepage description.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migrateHomePageOgDescription() {
		$showOnFront        = get_option( 'show_on_front' );
		$pageOnFront        = (int) get_option( 'page_on_front' );
		$useHomePageMeta    = ! empty( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_setmeta'] );
		$format             = $this->oldOptions['aiosp_description_format'];

		if ( 'posts' === $showOnFront ) {
			$ogDescription = aioseo()->helpers->pregReplace( '#%description%#', '#tagline', $format );
			if ( ! $useHomePageMeta ) {
				if ( ! empty( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_description'] ) ) {
					$ogDescription = $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_description'];
				}
				aioseo()->options->social->facebook->homePage->description = aioseo()->helpers->sanitizeOption( aioseo()->migration->helpers->macrosToSmartTags( $ogDescription ) );
				aioseo()->options->social->twitter->homePage->description = aioseo()->helpers->sanitizeOption( aioseo()->migration->helpers->macrosToSmartTags( $ogDescription ) );

				return;
			}
			$description   = aioseo()->options->searchAppearance->global->metaDescription;
			$ogDescription = $description ? $description : $ogDescription;
			aioseo()->options->social->facebook->homePage->description = aioseo()->helpers->sanitizeOption( $ogDescription );
			aioseo()->options->social->twitter->homePage->description  = aioseo()->helpers->sanitizeOption( $ogDescription );

			return;
		}

		$post           = 'page' === $showOnFront && $pageOnFront ? aioseo()->helpers->getPost( $pageOnFront ) : '';
		$aioseoPost     = Models\Post::getPost( $post->ID );
		$seoDescription = get_post_meta( $post->ID, '_aioseop_description', true );
		$ogMeta         = get_post_meta( $post->ID, '_aioseop_opengraph_settings', true );

		if ( ! $ogMeta ) {
			return;
		}

		$ogMeta = aioseo()->helpers->maybeUnserialize( $ogMeta );

		$ogDescription = '';
		if ( ! $useHomePageMeta ) {
			if ( empty( $this->oldOptions['aiosp_use_static_home_info'] ) ) {
				$ogDescription = ! empty( $this->oldOptions['aiosp_home_description'] ) ? $this->oldOptions['aiosp_home_description'] : $ogDescription;
				if ( ! empty( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_description'] ) ) {
					$ogDescription = $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_description'];
				}
				if ( ! empty( $ogMeta['aioseop_opengraph_settings_desc'] ) ) {
					$ogDescription = $ogMeta['aioseop_opengraph_settings_desc'];
				} elseif ( ! empty( $seoDescription ) ) {
					if ( empty( $ogDescription ) ) {
						$ogDescription = $seoDescription;
					} elseif ( empty( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_description'] ) ) {
						$ogDescription = $seoDescription;
					}
				}
			}
		} else {
			if ( empty( $this->oldOptions['aiosp_use_static_home_info'] ) ) {
				$ogDescription = $aioseoPost->description;
				if ( ! empty( $ogMeta['aioseop_opengraph_settings_desc'] ) ) {
					$ogDescription = $ogMeta['aioseop_opengraph_settings_desc'];
				}
				$ogDescription = ! empty( $this->oldOptions['aiosp_home_description'] ) ? $this->oldOptions['aiosp_home_description'] : $ogDescription;
				if ( ! empty( $seoDescription ) ) {
					$ogDescription = $seoDescription;
				}
			} else {
				$ogDescription = ! empty( $seoDescription ) ? $seoDescription : $ogDescription;
			}
		}

		$ogDescription = aioseo()->helpers->sanitizeOption( aioseo()->migration->helpers->macrosToSmartTags( $ogDescription ) );
		$aioseoPost->set( [
			'post_id'             => $post->ID,
			'og_description'      => $ogDescription,
			'twitter_description' => $ogDescription
		] );
		$aioseoPost->save();
	}

	/**
	 * Migrates the Open Graph default post images.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migrateSocialPostImageSettings() {
		if ( ! empty( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_homeimage'] ) ) {
			$value = esc_url( wp_strip_all_tags( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_homeimage'] ) );
			aioseo()->options->social->facebook->homePage->image = $value;
			aioseo()->options->social->twitter->homePage->image  = $value;
		}

		if ( ! empty( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_defimg'] ) ) {
			$value = aioseo()->helpers->sanitizeOption( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_defimg'] );
			aioseo()->options->social->facebook->general->defaultImageSourcePosts = $value;
			aioseo()->options->social->twitter->general->defaultImageSourcePosts  = $value;
		}

		if (
			! empty( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_dimg'] ) &&
			! preg_match( '/default-user-image.png$/', (string) $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_dimg'] )
		) {
			$value = esc_url( wp_strip_all_tags( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_dimg'] ) );
			aioseo()->options->social->facebook->general->defaultImagePosts = $value;
			aioseo()->options->social->twitter->general->defaultImagePosts  = $value;
		} else {
			aioseo()->options->social->facebook->general->defaultImagePosts = '';
			aioseo()->options->social->twitter->general->defaultImagePosts  = '';
		}

		if (
			! empty( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_dimgwidth'] ) ||
			! empty( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_dimgheight'] )
		) {
			aioseo()->options->social->facebook->general->defaultImageWidthPosts =
				aioseo()->helpers->sanitizeOption( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_dimgwidth'] );
			aioseo()->options->social->facebook->general->defaultImageHeightPosts =
				aioseo()->helpers->sanitizeOption( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_dimgheight'] );
		}

		if ( ! empty( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_meta_key'] ) ) {
			$value = aioseo()->helpers->sanitizeOption( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_meta_key'] );
			aioseo()->options->social->facebook->general->customFieldImagePosts = $value;
			aioseo()->options->social->twitter->general->customFieldImagePosts  = $value;
		}
	}

	/**
	 * Migrates the Twitter username.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migrateTwitterUsername() {
		if (
			! empty( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_twitter_site'] ) &&
			! aioseo()->options->social->profiles->urls->twitterUrl
		) {
			$username = ltrim( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_twitter_site'], '@' );
			aioseo()->options->social->profiles->urls->twitterUrl =
				esc_url( 'https://x.com/' . aioseo()->social->twitter->prepareUsername( aioseo()->helpers->sanitizeOption( $username ), false ) );
		}
	}

	/**
	 * Migrates the Twitter card type.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migrateTwitterCardType() {
		if ( ! empty( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_defcard'] ) ) {
			aioseo()->options->social->twitter->general->defaultCardType =
				aioseo()->helpers->sanitizeOption( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_defcard'] );
			aioseo()->options->social->twitter->homePage->cardType =
				aioseo()->helpers->sanitizeOption( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_defcard'] );
		}
	}

	/**
	 * Migrates the default object types.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migrateDefaultObjectTypes() {
		foreach ( aioseo()->helpers->getPublicPostTypes( true ) as $postType ) {
			$settingName = "aiosp_opengraph_{$postType}_fb_object_type";
			if ( ! in_array( $settingName, array_keys( $this->oldOptions['modules']['aiosp_opengraph_options'] ), true ) ) {
				continue;
			}

			$dynamicOptions = aioseo()->dynamicOptions->noConflict();
			if ( $dynamicOptions->social->facebook->general->postTypes->has( $postType ) ) {
				aioseo()->dynamicOptions->social->facebook->general->postTypes->$postType->objectType =
					aioseo()->helpers->sanitizeOption( $this->oldOptions['modules']['aiosp_opengraph_options'][ $settingName ] );
			}

			if ( 'post' === $postType ) {
				aioseo()->options->social->facebook->homePage->objectType =
					aioseo()->helpers->sanitizeOption( $this->oldOptions['modules']['aiosp_opengraph_options'][ $settingName ] );
			}
		}
	}

	/**
	 * Migrates a number of advanced settings.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migrateAdvancedSettings() {
		$advancedEnabled = false;

		if ( ! empty( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_key'] ) ) {
			$advancedEnabled = true;
			aioseo()->options->social->facebook->advanced->adminId = aioseo()->helpers->sanitizeOption( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_key'] );
		}

		if ( ! empty( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_appid'] ) ) {
			$advancedEnabled = true;
			aioseo()->options->social->facebook->advanced->appId  = aioseo()->helpers->sanitizeOption( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_appid'] );
		}

		if ( ! empty( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_gen_tags'] ) ) {
			$advancedEnabled = true;
			aioseo()->options->social->facebook->advanced->generateArticleTags = true;
		} else {
			aioseo()->options->social->facebook->advanced->generateArticleTags = false;
		}

		if ( ! empty( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_gen_keywords'] ) ) {
			$advancedEnabled = true;
			aioseo()->options->social->facebook->advanced->useKeywordsInTags = true;
		} else {
			aioseo()->options->social->facebook->advanced->useKeywordsInTags = false;
		}

		if ( ! empty( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_gen_categories'] ) ) {
			$advancedEnabled = true;
			aioseo()->options->social->facebook->advanced->useCategoriesInTags = true;
		} else {
			aioseo()->options->social->facebook->advanced->useCategoriesInTags = false;
		}

		if ( ! empty( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_gen_post_tags'] ) ) {
			$advancedEnabled = true;
			aioseo()->options->social->facebook->advanced->usePostTagsInTags = true;
		} else {
			aioseo()->options->social->facebook->advanced->usePostTagsInTags = false;
		}

		aioseo()->options->social->facebook->advanced->enable = $advancedEnabled;
	}

	/**
	 * Migrates the social URLs for the author users.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migrateProfileSocialUrls() {
		$records = aioseo()->core->db
			->start( aioseo()->core->db->db->usermeta, true )
			->select( '*' )
			->where( 'meta_key', 'facebook' )
			->run()
			->result();

		if ( count( $records ) ) {
			foreach ( $records as $record ) {
				if ( ! empty( $record->user_id ) && ! empty( $record->meta_value ) ) {
					update_user_meta(
						(int) $record->user_id,
						'aioseo_facebook',
						esc_url( $record->meta_value )
					);
				}
			}
		}

		$records = aioseo()->core->db
			->start( aioseo()->core->db->db->usermeta, true )
			->select( '*' )
			->where( 'meta_key', 'twitter' )
			->run()
			->result();

		if ( count( $records ) ) {
			foreach ( $records as $record ) {
				if ( ! empty( $record->user_id ) && ! empty( $record->meta_value ) ) {
					update_user_meta(
						(int) $record->user_id,
						'aioseo_twitter',
						sanitize_text_field( $record->meta_value )
					);
				}
			}
		}
	}
}Wpml.php000066600000010215151146742350006207 0ustar00<?php
namespace AIOSEO\Plugin\Common\Migration;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Migrates the WPML settings from V3.
 *
 * @since 4.0.0
 */
class Wpml {
	/**
	 * Class constructor.
	 *
	 * @since 4.0.0
	 */
	public function __construct() {
		// If the tables don't exist (could happen), return early.
		if ( ! aioseo()->core->db->tableExists( 'icl_strings' ) && ! aioseo()->core->db->tableExists( 'icl_string_translations' ) ) {
			return;
		}

		$strings = [
			'[aioseop_options]aiosp_home_title'       => '[aioseo_options_localized]searchAppearance_global_siteTitle',
			'[aioseop_options]aiosp_home_description' => '[aioseo_options_localized]searchAppearance_global_metaDescription',
			'[aioseop_options]aiosp_home_keywords'    => '[aioseo_options_localized]searchAppearance_global_keywords'
		];

		try {
			$v3Results = aioseo()->core->db->start( 'icl_strings' )
				->where( 'context', 'admin_texts_aioseop_options' )
				->whereIn( 'name', array_keys( $strings ) )
				->run()
				->result();

			$v4Results = aioseo()->core->db->start( 'icl_strings' )
				->where( 'context', 'admin_texts_aioseo_options_localized' )
				->whereIn( 'name', array_values( $strings ) )
				->run()
				->result();

			if ( ! empty( $v3Results ) ) {
				foreach ( $v3Results as $result ) {
					$translations = aioseo()->core->db->start( 'icl_string_translations' )
						->where( 'string_id', $result->id )
						->run()
						->result();

					if ( empty( $translations ) ) {
						continue;
					}

					$v4ResultId = null;
					if ( ! empty( $v4Results ) ) {
						foreach ( $v4Results as $r ) {
							if ( $r->name === $strings[ $result->name ] ) {
								$v4ResultId = $r->id;
								break;
							}
						}
					}

					if ( ! $v4ResultId ) {
						$v4ResultId = aioseo()->core->db
							->insert( 'icl_strings' )
							->set( [
								'language'                => $result->language,
								'context'                 => 'admin_texts_aioseo_options_localized',
								'name'                    => $strings[ $result->name ],
								'value'                   => $result->value,
								'string_package_id'       => $result->string_package_id,
								'location'                => $result->location,
								'wrap_tag'                => $result->wrap_tag,
								'type'                    => $result->type,
								'title'                   => $result->title,
								'status'                  => $result->status,
								'gettext_context'         => $result->gettext_context,
								'domain_name_context_md5' => md5( 'admin_texts_aioseo_options_localized' . $strings[ $result->name ] ),
								'translation_priority'    => $result->translation_priority,
								'word_count'              => $result->word_count
							] )
							->run()
							->insertId();
					}

					foreach ( $translations as $translation ) {
						// Check if the translation exists first or we'll get a DB error.
						$v4Translation = aioseo()->core->db->start( 'icl_string_translations' )
							->where( 'string_id', $v4ResultId )
							->where( 'language', $translation->language )
							->run()
							->result();

						if ( ! empty( $v4Translation ) ) {
							aioseo()->core->db->update( 'icl_string_translations' )
								->where( 'string_id', $v4ResultId )
								->where( 'language', $translation->language )
								->set( [
									'value' => $translation->value
								] )
								->run();
							continue;
						}

						aioseo()->core->db
							->insert( 'icl_string_translations' )
							->set( [
								'string_id'           => $v4ResultId,
								'language'            => $translation->language,
								'status'              => $translation->status,
								'value'               => $translation->value,
								'mo_string'           => $translation->mo_string,
								'translator_id'       => $translation->translator_id,
								'translation_service' => $translation->translation_service,
								'batch_id'            => $translation->batch_id,
								'translation_date'    => $translation->translation_date
							] )
							->run();
					}
				}
			}
		} catch ( \Exception $e ) {
			// If there are any errors, let's just abort. We dont' want to do anything more.
		}
	}
}Helpers.php000066600000020076151146742350006700 0ustar00<?php
namespace AIOSEO\Plugin\Common\Migration;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use AIOSEO\Plugin\Common\Models;

/**
 * Contains a number of helper functions for the V3 migration.
 *
 * @since 4.0.0
 */
class Helpers {
	/**
	 * Maps a list of old settings from V3 to their counterparts in V4.
	 *
	 * @since 4.0.0
	 *
	 * @param  array $mappings      The old settings, mapped to their new settings.
	 * @param  array $group         The old settings group.
	 * @param  bool  $convertMacros Whether to convert the old V3 macros to V4 smart tags.
	 * @return void
	 */
	public function mapOldToNew( $mappings, $group, $convertMacros = false ) {
		if (
			! is_array( $mappings ) ||
			! is_array( $group ) ||
			! count( $mappings ) ||
			! count( $group )
		) {
			return;
		}

		$mainOptions    = aioseo()->options->noConflict();
		$dynamicOptions = aioseo()->dynamicOptions->noConflict();
		foreach ( $mappings as $name => $values ) {
			if ( ! isset( $group[ $name ] ) ) {
				continue;
			}

			$error      = false;
			$options    = ! empty( $values['dynamic'] ) ? $dynamicOptions : $mainOptions;
			$lastOption = '';
			for ( $i = 0; $i < count( $values['newOption'] ); $i++ ) {
				$lastOption = $values['newOption'][ $i ];
				if ( ! $options->has( $lastOption, false ) ) {
					$error = true;
					break;
				}

				if ( count( $values['newOption'] ) - 1 !== $i ) {
					$options = $options->$lastOption;
				}
			}

			if ( $error ) {
				continue;
			}

			switch ( $values['type'] ) {
				case 'boolean':
					if ( ! empty( $group[ $name ] ) ) {
						$options->$lastOption = true;
						break;
					}
					$options->$lastOption = false;
					break;
				case 'integer':
				case 'float':
					$value = aioseo()->helpers->sanitizeOption( $group[ $name ] );
					if ( $value ) {
						$options->$lastOption = $value;
					}
					break;
				default:
					$value = $group[ $name ];
					if ( $convertMacros ) {
						$value = $this->macrosToSmartTags( $value );
					}
					$options->$lastOption = aioseo()->helpers->sanitizeOption( $value );
					break;
			}
		}
	}

	/**
	 * Replaces the macros from V3 with our new Smart Tags from V4.
	 *
	 * @since 4.0.0
	 *
	 * @param  string $string The string.
	 * @return string $string The converted string.
	 */
	public function macrosToSmartTags( $string ) {
		$macros = [
			'%site_title%'             => '#site_title',
			'%blog_title%'             => '#site_title',
			'%site_description%'       => '#tagline',
			'%blog_description%'       => '#tagline',
			'%wp_title%'               => '#post_title',
			'%post_title%'             => '#post_title',
			'%page_title%'             => '#post_title',
			'%post_date%'              => '#post_date',
			'%post_month%'             => '#post_month',
			'%post_year%'              => '#post_year',
			'%date%'                   => '#archive_date',
			'%day%'                    => '#post_day',
			'%month%'                  => '#post_month',
			'%monthnum%'               => '#post_month',
			'%year%'                   => '#post_year',
			'%current_date%'           => '#current_date',
			'%current_day%'            => '#current_day',
			'%current_month%'          => '#current_month',
			'%current_month_i18n%'     => '#current_month',
			'%current_year%'           => '#current_year',
			'%category_title%'         => '#taxonomy_title',
			'%tag%'                    => '#taxonomy_title',
			'%tag_title%'              => '#taxonomy_title',
			'%archive_title%'          => '#archive_title',
			'%taxonomy_title%'         => '#taxonomy_title',
			'%taxonomy_description%'   => '#taxonomy_description',
			'%tag_description%'        => '#taxonomy_description',
			'%category_description%'   => '#taxonomy_description',
			'%author%'                 => '#author_name',
			'%search%'                 => '#search_term',
			'%page%'                   => '#page_number',
			'%site_link%'              => '#site_link',
			'%site_link_raw%'          => '#site_link_alt',
			'%post_link%'              => '#post_link',
			'%post_link_raw%'          => '#post_link_alt',
			'%author_name%'            => '#author_name',
			'%author_link%'            => '#author_link',
			'%image_title%'            => '#image_title',
			'%image_seo_title%'        => '#image_seo_title',
			'%image_seo_description%'  => '#image_seo_description',
			'%post_seo_title%'         => '#post_seo_title',
			'%post_seo_description%'   => '#post_seo_description',
			'%alt_tag%'                => '#alt_tag',
			'%description%'            => '#description',
			// These need to run last so we don't replace other known tags.
			'%.*_title%'               => '#post_title',
			'%[^%]*_author_login%'     => '#author_first_name #author_last_name',
			'%[^%]*_author_nicename%'  => '#author_first_name #author_last_name',
			'%[^%]*_author_firstname%' => '#author_first_name',
			'%[^%]*_author_lastname%'  => '#author_last_name',
		];

		if ( preg_match_all( '#%cf_([^%]*)%#', (string) $string, $matches ) && ! empty( $matches[1] ) ) {
			foreach ( $matches[1] as $name ) {
				if ( preg_match( '#\s#', (string) $name ) ) {
					$notification = Models\Notification::getNotificationByName( 'v3-migration-custom-field' );
					if ( ! $notification->notification_name ) {
						Models\Notification::addNotification( [
							'slug'              => uniqid(),
							'notification_name' => 'v3-migration-custom-field',
							'title'             => __( 'Custom field names with spaces detected', 'all-in-one-seo-pack' ),
							'content'           => sprintf(
								// Translators: 1 - The plugin short name ("AIOSEO"), 2 - Same as previous.
								__( '%1$s has detected that you have one or more custom fields with spaces in their name.
								In order for %2$s to correctly parse these custom fields, their names cannot contain any spaces.', 'all-in-one-seo-pack' ),
								AIOSEO_PLUGIN_SHORT_NAME,
								AIOSEO_PLUGIN_SHORT_NAME
							),
							'type'              => 'warning',
							'level'             => [ 'all' ],
							'button1_label'     => __( 'Remind Me Later', 'all-in-one-seo-pack' ),
							'button1_action'    => 'http://action#notification/v3-migration-custom-field-reminder',
							'start'             => gmdate( 'Y-m-d H:i:s' )
						] );
					}
				} else {
					$string = aioseo()->helpers->pregReplace( "#%cf_$name%#", "#custom_field-$name", $string );
				}
			}
		}

		if ( preg_match_all( '#%tax_([^%]*)%#', (string) $string, $matches ) && ! empty( $matches[1] ) ) {
			foreach ( $matches[1] as $name ) {
				if ( ! preg_match( '#\s#', (string) $name ) ) {
					$string = aioseo()->helpers->pregReplace( "#%tax_$name%#", "#tax_name-$name", $string );
				}
			}
		}

		foreach ( $macros as $macro => $tag ) {
			$string = aioseo()->helpers->pregReplace( "#$macro(?![a-zA-Z0-9_])#im", $tag, $string );
		}

		$string = preg_replace( '/%([a-f0-9]{2}[^%]*)%/i', '#$1#', (string) $string );

		return $string;
	}

	/**
	 * Converts the old comma-separated keywords format to the new JSON format.
	 *
	 * @since 4.0.0
	 *
	 * @param  string $keywords A comma-separated list of keywords.
	 * @return string $keywords The keywords formatted in JSON.
	 */
	public function oldKeywordsToNewKeywords( $keywords ) {
		if ( ! $keywords ) {
			return '';
		}

		$oldKeywords = array_filter( explode( ',', $keywords ) );
		if ( ! is_array( $oldKeywords ) ) {
			return '';
		}

		$keywords = [];
		foreach ( $oldKeywords as $oldKeyword ) {
			$oldKeyword = aioseo()->helpers->sanitizeOption( $oldKeyword );

			$keyword        = new \stdClass();
			$keyword->label = $oldKeyword;
			$keyword->value = $oldKeyword;

			$keywords[] = $keyword;
		}

		return $keywords;
	}

	/**
	 * Resets the plugin so that the migration can run again.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	public static function redoMigration() {
		aioseo()->core->db->delete( 'options' )
			->whereRaw( "`option_name` LIKE 'aioseo_options_internal%'" )
			->run();

		aioseo()->core->cache->delete( 'v3_migration_in_progress_posts' );
		aioseo()->core->cache->delete( 'v3_migration_in_progress_terms' );

		aioseo()->actionScheduler->unschedule( 'aioseo_migrate_post_meta' );
		aioseo()->actionScheduler->unschedule( 'aioseo_migrate_term_meta' );
	}
}RobotsTxt.php000066600000002723151146742350007245 0ustar00<?php
namespace AIOSEO\Plugin\Common\Migration;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

// phpcs:disable WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound

/**
 * Migrates the Robots.txt settings from V3.
 *
 * @since 4.0.0
 */
class RobotsTxt {
	/**
	 * Class constructor.
	 *
	 * @since 4.0.0
	 */
	public function __construct() {
		$oldOptions = aioseo()->migration->oldOptions;

		$rules = aioseo()->options->tools->robots->rules;

		if (
			! empty( $oldOptions['modules']['aiosp_robots_options'] ) &&
			! empty( $oldOptions['modules']['aiosp_robots_options']['aiosp_robots_rules'] )
		) {
			$rules += $this->convertRules( $oldOptions['modules']['aiosp_robots_options']['aiosp_robots_rules'] );
		}

		aioseo()->options->tools->robots->rules = $rules;
	}

	/**
	 * Converts the old Robots.txt rules to the new format.
	 *
	 * @since 4.0.0
	 *
	 * @param  array $oldRules The old rules.
	 * @return array $newRules The converted rules.
	 */
	private function convertRules( $oldRules ) {
		$newRules = [];
		foreach ( $oldRules as $oldRule ) {
			$newRule                = new \stdClass();
			$newRule->userAgent     = aioseo()->helpers->sanitizeOption( $oldRule['agent'] );
			$newRule->rule          = aioseo()->helpers->sanitizeOption( lcfirst( $oldRule['type'] ) );
			$newRule->directoryPath = aioseo()->helpers->sanitizeOption( $oldRule['path'] );

			array_push( $newRules, wp_json_encode( $newRule ) );
		}

		return $newRules;
	}
}GeneralSettings.php000066600000103572151146742350010377 0ustar00<?php
namespace AIOSEO\Plugin\Common\Migration;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use AIOSEO\Plugin\Common\Models;

// phpcs:disable WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound

/**
 * Migrates the General Settings from V3.
 *
 * @since 4.0.0
 */
class GeneralSettings {
	/**
	 * The old V3 options.
	 *
	 * @since 4.0.0
	 *
	 * @var array
	 */
	protected $oldOptions = [];

	/**
	 * Class constructor.
	 *
	 * @since 4.0.0
	 */
	public function __construct() {
		$this->oldOptions = aioseo()->migration->oldOptions;

		$this->migrateSeparatorCharacter();
		$this->setDefaultArticleType();
		$this->migrateHomePageMeta();
		$this->migrateTitleFormats();
		$this->migrateDescriptionFormat();
		$this->migrateNoindexSettings();
		$this->migrateNofollowSettings();
		$this->migratePostSeoColumns();
		$this->migrateSocialUrls();
		$this->migrateSchemaMarkupSettings();
		$this->migrateHomePageKeywords();
		$this->migrateDeprecatedAdvancedOptions();
		$this->migrateRssContentSettings();
		$this->migrateRedirectToParent();
		$this->migrateDisabledPosts();
		$this->migrateNoPaginationForCanonicalUrls();

		$settings = [
			'aiosp_admin_bar'                  => [ 'type' => 'boolean', 'newOption' => [ 'advanced', 'adminBarMenu' ] ],
			'aiosp_google_verify'              => [ 'type' => 'string', 'newOption' => [ 'webmasterTools', 'google' ] ],
			'aiosp_bing_verify'                => [ 'type' => 'string', 'newOption' => [ 'webmasterTools', 'bing' ] ],
			'aiosp_pinterest_verify'           => [ 'type' => 'string', 'newOption' => [ 'webmasterTools', 'pinterest' ] ],
			'aiosp_yandex_verify'              => [ 'type' => 'string', 'newOption' => [ 'webmasterTools', 'yandex' ] ],
			'aiosp_baidu_verify'               => [ 'type' => 'string', 'newOption' => [ 'webmasterTools', 'baidu' ] ],
			'aiosp_schema_site_represents'     => [ 'type' => 'string', 'newOption' => [ 'searchAppearance', 'global', 'schema', 'siteRepresents' ] ],
			'aiosp_schema_organization_name'   => [ 'type' => 'string', 'newOption' => [ 'searchAppearance', 'global', 'schema', 'organizationName' ] ],
			'aiosp_schema_person_manual_name'  => [ 'type' => 'string', 'newOption' => [ 'searchAppearance', 'global', 'schema', 'personName' ] ],
			'aiosp_schema_organization_logo'   => [ 'type' => 'string', 'newOption' => [ 'searchAppearance', 'global', 'schema', 'organizationLogo' ] ],
			'aiosp_schema_person_manual_image' => [ 'type' => 'string', 'newOption' => [ 'searchAppearance', 'global', 'schema', 'personLogo' ] ],
			'aiosp_togglekeywords'             => [ 'type' => 'boolean', 'newOption' => [ 'searchAppearance', 'advanced', 'useKeywords' ] ],
			'aiosp_use_categories'             => [ 'type' => 'boolean', 'newOption' => [ 'searchAppearance', 'advanced', 'useCategoriesForMetaKeywords' ] ],
			'aiosp_use_tags_as_keywords'       => [ 'type' => 'boolean', 'newOption' => [ 'searchAppearance', 'advanced', 'useTagsForMetaKeywords' ] ],
			'aiosp_dynamic_postspage_keywords' => [ 'type' => 'boolean', 'newOption' => [ 'searchAppearance', 'advanced', 'dynamicallyGenerateKeywords' ] ],
			'aiosp_run_shortcodes'             => [ 'type' => 'boolean', 'newOption' => [ 'searchAppearance', 'advanced', 'runShortcodes' ] ]
		];

		aioseo()->migration->helpers->mapOldToNew( $settings, aioseo()->migration->oldOptions );
	}

	/**
	 * Migrates the separator character.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migrateSeparatorCharacter() {
		aioseo()->options->searchAppearance->global->separator = '|';
	}

	/**
	 * Set the default posts schema type to Article.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function setDefaultArticleType() {
		if ( aioseo()->dynamicOptions->searchAppearance->postTypes->has( 'post' ) ) {
			aioseo()->dynamicOptions->searchAppearance->postTypes->post->articleType = 'Article';
		}
	}

	/**
	 * Migrates the homepage meta.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migrateHomePageMeta() {
		$this->migrateHomePageTitle();
		$this->migrateHomePageDescription();

		// If the homepage is a static one, we should migrate the meta now.
		$showOnFront = get_option( 'show_on_front' );
		$pageOnFront = (int) get_option( 'page_on_front' );
		if ( 'page' !== $showOnFront || ! $pageOnFront ) {
			return;
		}

		$post       = 'page' === $showOnFront && $pageOnFront ? get_post( $pageOnFront ) : '';
		$aioseoPost = Models\Post::getPost( $post->ID );

		$postMeta = aioseo()->core->db
			->start( 'postmeta' . ' as pm' )
			->select( 'pm.meta_key, pm.meta_value' )
			->where( 'pm.post_id', $post->ID )
			->whereRaw( "`pm`.`meta_key` LIKE '_aioseop_%'" )
			->run()
			->result();

		$mappedMeta = [
			'_aioseop_nofollow'           => 'robots_nofollow',
			'_aioseop_sitemap_priority'   => 'priority',
			'_aioseop_sitemap_frequency'  => 'frequency',
			'_aioseop_keywords'           => 'keywords',
			'_aioseop_opengraph_settings' => '',
		];

		$meta = [
			'post_id' => $post->ID,
		];

		foreach ( $postMeta as $record ) {
			$name  = $record->meta_key;
			$value = $record->meta_value;

			if ( ! in_array( $name, array_keys( $mappedMeta ), true ) ) {
				continue;
			}

			switch ( $name ) {
				case '_aioseop_nofollow':
					$meta[ $mappedMeta[ $name ] ] = ! empty( $value );
					if ( ! empty( $value ) ) {
						$meta['robots_default'] = false;
					}
					break;
				case '_aioseop_keywords':
					$meta[ $mappedMeta[ $name ] ] = aioseo()->migration->helpers->oldKeywordsToNewKeywords( $value );
					break;
				case '_aioseop_opengraph_settings':
					$class = new Meta();
					$meta += $class->convertOpenGraphMeta( $value );

					// We'll deal with the OG title/description in the Social Meta migration class.
					if ( isset( $meta['og_title'] ) ) {
						unset( $meta['og_title'] );
					}
					if ( isset( $meta['og_description'] ) ) {
						unset( $meta['og_description'] );
					}
					break;
				default:
					$meta[ $mappedMeta[ $name ] ] = aioseo()->helpers->sanitizeOption( $value );
					break;
			}
		}

		$aioseoPost->set( $meta );
		$aioseoPost->save();
	}

	/**
	 * Migrates the homepage title.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migrateHomePageTitle() {
		$showOnFront   = get_option( 'show_on_front' );
		$pageOnFront   = (int) get_option( 'page_on_front' );

		$homePageTitle = ! empty( $this->oldOptions['aiosp_home_title'] ) ? $this->oldOptions['aiosp_home_title'] : '';
		$format        = $this->oldOptions['aiosp_home_page_title_format'];

		if ( 'posts' === $showOnFront ) {
			$homePageTitle = $homePageTitle ? $homePageTitle : get_bloginfo( 'name' );
			$title         = empty( $format ) ? $homePageTitle : aioseo()->helpers->pregReplace( '#%page_title%#', $homePageTitle, $format );
			$title         = aioseo()->migration->helpers->macrosToSmartTags( $title );
			aioseo()->options->searchAppearance->global->siteTitle = aioseo()->helpers->sanitizeOption( $title );

			return;
		}

		// Set the setting globally regardless of what happens below.
		if ( ! empty( $homePageTitle ) ) {
			$title = aioseo()->migration->helpers->macrosToSmartTags( aioseo()->helpers->pregReplace( '#%page_title%#', $homePageTitle, $format ) );
			aioseo()->options->searchAppearance->global->siteTitle = aioseo()->helpers->sanitizeOption( $title );
		}

		$post       = 'page' === $showOnFront && $pageOnFront ? get_post( $pageOnFront ) : '';
		$metaTitle  = get_post_meta( $post->ID, '_aioseop_title', true );

		$homePageTitle = '';
		if ( empty( $this->oldOptions['aiosp_use_static_home_info'] ) ) {
			$homePageTitle = ! empty( $this->oldOptions['aiosp_home_title'] ) ? $this->oldOptions['aiosp_home_title'] : '#site_title';
			$homePageTitle = ! empty( $metaTitle ) ? $metaTitle : $homePageTitle;
			$homePageTitle = empty( $format ) ? $homePageTitle : aioseo()->helpers->pregReplace( '#%page_title%#', $homePageTitle, $format );
			$homePageTitle = aioseo()->migration->helpers->macrosToSmartTags( $homePageTitle );
		} else {
			if ( ! empty( $metaTitle ) ) {
				$homePageTitle = empty( $format ) ? $metaTitle : aioseo()->helpers->pregReplace( '#%page_title%#', $metaTitle, $format );
				$homePageTitle = aioseo()->migration->helpers->macrosToSmartTags( $homePageTitle );
			}
		}

		$aioseoPost = Models\Post::getPost( $post->ID );
		$aioseoPost->set( [
			'post_id' => $post->ID,
			'title'   => aioseo()->helpers->sanitizeOption( $homePageTitle )
		] );
		$aioseoPost->save();

		$this->maybeShowHomePageTitleNotice( $post );
	}

	/**
	 * Check if we should display a notice warning users that their homepage title may have changed.
	 *
	 * @since 4.0.0
	 *
	 * @param  \WP_Post $post The post object.
	 * @return void
	 */
	private function maybeShowHomePageTitleNotice( $post ) {
		$metaTitle     = get_post_meta( $post->ID, '_aioseop_title', true );
		$homePageTitle = ! empty( $this->oldOptions['aiosp_home_title'] ) ? $this->oldOptions['aiosp_home_title'] : '';

		if (
			empty( $this->oldOptions['aiosp_use_static_home_info'] ) &&
			$metaTitle &&
			( trim( $homePageTitle ) !== trim( $metaTitle ) )
		) {
			$this->showHomePageSettingsNotice();
		}
	}

	/**
	 * Migrates the homepage description.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migrateHomePageDescription() {
		$showOnFront         = get_option( 'show_on_front' );
		$pageOnFront         = (int) get_option( 'page_on_front' );

		$homePageDescription = ! empty( $this->oldOptions['aiosp_home_description'] ) ? $this->oldOptions['aiosp_home_description'] : '';
		$format              = $this->oldOptions['aiosp_description_format'];

		if ( 'posts' === $showOnFront ) {
			// If the description had the page_title macro, we want to replace it with the actual page title itself.
			$homePageDescription = $homePageDescription ? $homePageDescription : get_bloginfo( 'description' );
			$homePageTitle       = ! empty( $this->oldOptions['aiosp_home_title'] ) ? $this->oldOptions['aiosp_home_title'] : get_bloginfo( 'name' );
			$format              = aioseo()->helpers->pregReplace( '#%page_title%#', $homePageTitle, $format );
			$description         = empty( $format ) ? $homePageDescription : aioseo()->helpers->pregReplace( '#%description%#', $homePageDescription, $format );
			$description         = aioseo()->migration->helpers->macrosToSmartTags( $description );
			aioseo()->options->searchAppearance->global->metaDescription = aioseo()->helpers->sanitizeOption( $description );

			return;
		}

		// Set the setting globally regardless of what happens below.
		if ( ! empty( $homePageDescription ) ) {
			$homePageTitle = ! empty( $this->oldOptions['aiosp_home_title'] ) ? $this->oldOptions['aiosp_home_title'] : get_bloginfo( 'name' );
			$format        = aioseo()->helpers->pregReplace( '#%page_title%#', $homePageTitle, $format );
			$description   = aioseo()->migration->helpers->macrosToSmartTags( aioseo()->helpers->pregReplace( '#%description%#', $homePageDescription, $format ) );
			aioseo()->options->searchAppearance->global->metaDescription = aioseo()->helpers->sanitizeOption( $description );
		}

		$post             = 'page' === $showOnFront && $pageOnFront ? get_post( $pageOnFront ) : '';
		$metaDescription  = get_post_meta( $post->ID, '_aioseop_description', true );

		$homePageDescription = '';
		if ( empty( $this->oldOptions['aiosp_use_static_home_info'] ) ) {
			$homePageDescription = ! empty( $this->oldOptions['aiosp_home_description'] ) ? $this->oldOptions['aiosp_home_description'] : '';
			$homePageDescription = ! empty( $metaDescription ) ? $metaDescription : $homePageDescription;
		} else {
			if ( ! empty( $metaDescription ) ) {
				$homePageDescription = empty( $format ) ? $metaDescription : aioseo()->helpers->pregReplace( '#%description%#', $metaDescription, $format );
				$homePageDescription = aioseo()->migration->helpers->macrosToSmartTags( $homePageDescription );
			}
		}

		$homePageDescription = empty( $format ) ? $homePageDescription : aioseo()->helpers->pregReplace( '#(%description%|%page_title%)#', $homePageDescription, $format );
		$homePageDescription = aioseo()->migration->helpers->macrosToSmartTags( $homePageDescription );

		$aioseoPost = Models\Post::getPost( $post->ID );
		$aioseoPost->set( [
			'post_id'     => $post->ID,
			'description' => aioseo()->helpers->sanitizeOption( $homePageDescription )
		] );
		$aioseoPost->save();

		$this->maybeShowHomePageDescriptionNotice( $post );
	}

		/**
	 * Check if we should display a notice warning users that their homepage title may have changed.
	 *
	 * @since 4.0.0
	 *
	 * @param  \WP_Post $post The post object.
	 * @return void
	 */
	private function maybeShowHomePageDescriptionNotice( $post ) {
		$metaDescription     = get_post_meta( $post->ID, '_aioseop_description', true );
		$homePageDescription = ! empty( $this->oldOptions['aiosp_home_description'] ) ? $this->oldOptions['aiosp_home_description'] : '';

		if (
			empty( $this->oldOptions['aiosp_use_static_home_info'] ) &&
			$metaDescription &&
			( trim( $homePageDescription ) !== trim( $metaDescription ) )
		) {
			$this->showHomePageSettingsNotice();
		}
	}

	/**
	 * Shows the homepage settings notice.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function showHomePageSettingsNotice() {
		$notification = Models\Notification::getNotificationByName( 'v3-migration-homepage-settings' );
		if ( $notification->notification_name ) {
			return;
		}

		Models\Notification::addNotification( [
			'slug'              => uniqid(),
			'notification_name' => 'v3-migration-homepage-settings',
			'title'             => __( 'Review Your Homepage Title & Description', 'all-in-one-seo-pack' ),
			'content'           => sprintf(
				// Translators: 1 - All in One SEO.
				__( 'Due to a bug in the previous version of %1$s, your homepage title and description may have changed. Please take a minute to review your homepage settings to verify that they are correct.', 'all-in-one-seo-pack' ), // phpcs:ignore Generic.Files.LineLength.MaxExceeded
				AIOSEO_PLUGIN_NAME
			),
			'type'              => 'warning',
			'level'             => [ 'all' ],
			'button1_label'     => __( 'Review Now', 'all-in-one-seo-pack' ),
			'button1_action'    => 'http://route#aioseo-search-appearance&aioseo-scroll=home-page-settings&aioseo-highlight=home-page-settings:global-settings',
			'start'             => gmdate( 'Y-m-d H:i:s' )
		] );
	}

	/**
	 * Migrates the title formats.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migrateTitleFormats() {
		if ( ! empty( $this->oldOptions['aiosp_archive_title_format'] ) ) {
			$archives = array_keys( aioseo()->dynamicOptions->searchAppearance->archives->all() );
			$format   = aioseo()->helpers->sanitizeOption( aioseo()->migration->helpers->macrosToSmartTags( $this->oldOptions['aiosp_archive_title_format'] ) );
			foreach ( $archives as $archive ) {
				aioseo()->dynamicOptions->searchAppearance->archives->$archive->title = $format;
			}
		}

		$settings = [
			'aiosp_post_title_format'       => [ 'type' => 'string', 'newOption' => [ 'searchAppearance', 'postTypes', 'post', 'title' ], 'dynamic' => true ],
			'aiosp_page_title_format'       => [ 'type' => 'string', 'newOption' => [ 'searchAppearance', 'postTypes', 'page', 'title' ], 'dynamic' => true ],
			'aiosp_attachment_title_format' => [ 'type' => 'string', 'newOption' => [ 'searchAppearance', 'postTypes', 'attachment', 'title' ], 'dynamic' => true ],
			'aiosp_category_title_format'   => [ 'type' => 'string', 'newOption' => [ 'searchAppearance', 'taxonomies', 'category', 'title' ], 'dynamic' => true ],
			'aiosp_tag_title_format'        => [ 'type' => 'string', 'newOption' => [ 'searchAppearance', 'taxonomies', 'post_tag', 'title' ], 'dynamic' => true ],
			'aiosp_date_title_format'       => [ 'type' => 'string', 'newOption' => [ 'searchAppearance', 'archives', 'date', 'title' ] ],
			'aiosp_author_title_format'     => [ 'type' => 'string', 'newOption' => [ 'searchAppearance', 'archives', 'author', 'title' ] ],
			'aiosp_search_title_format'     => [ 'type' => 'string', 'newOption' => [ 'searchAppearance', 'archives', 'search', 'title' ] ],
			'aiosp_paged_format'            => [ 'type' => 'string', 'newOption' => [ 'searchAppearance', 'advanced', 'pagedFormat' ] ]
		];

		foreach ( $this->oldOptions as $name => $value ) {
			if (
				! in_array( $name, array_keys( $settings ), true ) &&
				preg_match( '#aiosp_(.*)_title_format#', (string) $name, $slug )
			) {
				if ( empty( $slug[1] ) ) {
					continue;
				}

				$objectSlug = aioseo()->helpers->pregReplace( '#_tax#', '', $slug[1] );
				if ( in_array( $objectSlug, aioseo()->helpers->getPublicPostTypes( true ), true ) ) {
					$settings[ $name ] = [ 'type' => 'string', 'newOption' => [ 'searchAppearance', 'postTypes', $objectSlug, 'title' ], 'dynamic' => true ];
					continue;
				}
				if ( in_array( $objectSlug, aioseo()->helpers->getPublicTaxonomies( true ), true ) ) {
					$settings[ $name ] = [ 'type' => 'string', 'newOption' => [ 'searchAppearance', 'taxonomies', $objectSlug, 'title' ], 'dynamic' => true ];
				}
			}
		}

		aioseo()->migration->helpers->mapOldToNew( $settings, $this->oldOptions, true );

		// Check if any of the title formats were empty and register a notification if so.
		$found = false;
		foreach ( $settings as $k => $v ) {
			if ( 'aiosp_home_page_title_format' === $k ) {
				continue;
			}

			if ( isset( $this->oldOptions[ $k ] ) && empty( $this->oldOptions[ $k ] ) ) {
				$found = true;
				break;
			}
		}

		if ( ! $found ) {
			Models\Notification::deleteNotificationByName( 'v3-migration-title-formats-blank' );

			return;
		}

		$notification = Models\Notification::getNotificationByName( 'v3-migration-title-formats-blank' );
		if ( $notification->notification_name ) {
			return;
		}

		$p1 = sprintf(
			// Translators: 1 - The plugin short name ("AIOSEO"), 2 - The plugin short name ("AIOSEO"), 3 - Opening link tag, 4 - Closing link tag.
			__( '%1$s migrated all your title formats, some of which were blank. If you were purposely using blank formats in the previous version of %2$s and want WordPress to handle your titles, you can safely dismiss this message. For more information, check out our documentation on %3$sblank title formats%4$s.', 'all-in-one-seo-pack' ), // phpcs:ignore Generic.Files.LineLength.MaxExceeded
			AIOSEO_PLUGIN_SHORT_NAME,
			AIOSEO_PLUGIN_SHORT_NAME,
			'<a href="' . aioseo()->helpers->utmUrl( AIOSEO_MARKETING_URL . '/docs/blank-title-formats-detected', 'notifications-center', 'v3-migration-title-formats-blank' ) . '">',
			'</a>'
		);

		Models\Notification::addNotification( [
			'slug'              => uniqid(),
			'notification_name' => 'v3-migration-title-formats-blank',
			'title'             => __( 'Blank Title Formats Detected', 'all-in-one-seo-pack' ),
			'content'           => $p1,
			'type'              => 'warning',
			'level'             => [ 'all' ],
			'button1_label'     => __( 'Learn More', 'all-in-one-seo-pack' ),
			'button1_action'    => aioseo()->helpers->utmUrl( AIOSEO_MARKETING_URL . '/docs/blank-title-formats-detected', 'notifications-center', 'v3-migration-title-formats-blank' ),
			'start'             => gmdate( 'Y-m-d H:i:s' )
		] );
	}

	/**
	 * Migrates the description format.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migrateDescriptionFormat() {
		if (
			! empty( $this->oldOptions['aiosp_generate_descriptions'] ) &&
			empty( $this->oldOptions['aiosp_skip_excerpt'] )
		) {
			foreach ( aioseo()->helpers->getPublicPostTypes() as $postType ) {
				if ( empty( $postType['supports']['excerpt'] ) ) {
					continue;
				}

				if ( aioseo()->dynamicOptions->searchAppearance->postTypes->has( $postType['name'] ) ) {
					aioseo()->dynamicOptions->searchAppearance->postTypes->{$postType['name']}->metaDescription = '#post_excerpt';
				}
			}
		}

		if (
			empty( $this->oldOptions['aiosp_description_format'] ) ||
			'%description%' === trim( $this->oldOptions['aiosp_description_format'] )
		) {
			return;
		}

		$deprecatedOptions = aioseo()->internalOptions->internal->deprecatedOptions;
		array_push( $deprecatedOptions, 'descriptionFormat' );
		aioseo()->internalOptions->internal->deprecatedOptions = $deprecatedOptions;

		$format = aioseo()->migration->helpers->macrosToSmartTags( $this->oldOptions['aiosp_description_format'] );
		aioseo()->options->deprecated->searchAppearance->global->descriptionFormat = aioseo()->helpers->sanitizeOption( $format );
	}

	/**
	 * Migrates the noindex settings.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migrateNoindexSettings() {
		if ( ! isset( $this->oldOptions['aiosp_cpostnoindex'] ) && ! isset( $this->oldOptions['aiosp_tax_noindex'] ) ) {
			return;
		}

		$noindexedPostTypes = is_array( $this->oldOptions['aiosp_cpostnoindex'] ) ? $this->oldOptions['aiosp_cpostnoindex'] : explode( ', ', $this->oldOptions['aiosp_cpostnoindex'] );
		foreach ( array_intersect( aioseo()->helpers->getPublicPostTypes( true ), $noindexedPostTypes ) as $postType ) {
			if ( aioseo()->dynamicOptions->noConflict()->searchAppearance->postTypes->has( $postType ) ) {
				aioseo()->dynamicOptions->searchAppearance->postTypes->$postType->show = false;
				aioseo()->dynamicOptions->searchAppearance->postTypes->$postType->advanced->robotsMeta->default = false;
				aioseo()->dynamicOptions->searchAppearance->postTypes->$postType->advanced->robotsMeta->noindex = true;
			}
		}

		$noindexedTaxonomies = isset( $this->oldOptions['aiosp_tax_noindex'] ) ? (array) $this->oldOptions['aiosp_tax_noindex'] : [];
		if ( ! empty( $this->oldOptions['aiosp_category_noindex'] ) ) {
			$noindexedTaxonomies[] = 'category';
		}

		if ( ! empty( $this->oldOptions['aiosp_tags_noindex'] ) ) {
			$noindexedTaxonomies[] = 'post_tag';
		}

		if ( ! empty( $noindexedTaxonomies ) ) {
			foreach ( array_intersect( aioseo()->helpers->getPublicTaxonomies( true ), $noindexedTaxonomies ) as $taxonomy ) {
				if ( aioseo()->dynamicOptions->noConflict()->searchAppearance->taxonomies->has( $taxonomy ) ) {
					aioseo()->dynamicOptions->searchAppearance->taxonomies->$taxonomy->show = false;
					aioseo()->dynamicOptions->searchAppearance->taxonomies->$taxonomy->advanced->robotsMeta->default = false;
					aioseo()->dynamicOptions->searchAppearance->taxonomies->$taxonomy->advanced->robotsMeta->noindex = true;
				}
			}
		}

		if ( ! empty( $this->oldOptions['aiosp_archive_date_noindex'] ) ) {
			aioseo()->options->searchAppearance->archives->date->show = false;
			aioseo()->options->searchAppearance->archives->date->advanced->robotsMeta->default = false;
			aioseo()->options->searchAppearance->archives->date->advanced->robotsMeta->noindex = true;
		}

		if ( ! empty( $this->oldOptions['aiosp_archive_author_noindex'] ) ) {
			aioseo()->options->searchAppearance->archives->author->show = false;
			aioseo()->options->searchAppearance->archives->author->advanced->robotsMeta->default = false;
			aioseo()->options->searchAppearance->archives->author->advanced->robotsMeta->noindex = true;
		}

		if ( ! empty( $this->oldOptions['aiosp_search_noindex'] ) ) {
			aioseo()->options->searchAppearance->archives->search->show = false;
			aioseo()->options->searchAppearance->archives->search->advanced->robotsMeta->default = false;
			aioseo()->options->searchAppearance->archives->search->advanced->robotsMeta->noindex = true;
		} else {
			// We need to do this as V4 will noindex the search page otherwise.
			aioseo()->options->searchAppearance->archives->search->show = true;
			aioseo()->options->searchAppearance->archives->search->advanced->robotsMeta->default = true;
			aioseo()->options->searchAppearance->archives->search->advanced->robotsMeta->noindex = false;
		}

		if ( ! empty( $this->oldOptions['aiosp_paginated_noindex'] ) ) {
			aioseo()->options->searchAppearance->advanced->globalRobotsMeta->default          = false;
			aioseo()->options->searchAppearance->advanced->globalRobotsMeta->noindexPaginated = true;
		}
	}

	/**
	 * Migrates the nofollow settings.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migrateNofollowSettings() {
		if ( ! empty( $this->oldOptions['aiosp_cpostnofollow'] ) ) {
			foreach ( array_intersect( aioseo()->helpers->getPublicPostTypes( true ), $this->oldOptions['aiosp_cpostnofollow'] ) as $postType ) {
				if ( aioseo()->dynamicOptions->noConflict()->searchAppearance->postTypes->has( $postType ) ) {
					aioseo()->dynamicOptions->searchAppearance->postTypes->$postType->advanced->robotsMeta->default  = false;
					aioseo()->dynamicOptions->searchAppearance->postTypes->$postType->advanced->robotsMeta->nofollow = true;
				}
			}
		}

		if ( ! empty( $this->oldOptions['aiosp_paginated_nofollow'] ) ) {
			aioseo()->options->searchAppearance->advanced->globalRobotsMeta->nofollowPaginated = true;
		}
	}

	/**
	 * Migrates the post SEO columns.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migratePostSeoColumns() {
		if ( ! isset( $this->oldOptions['aiosp_posttypecolumns'] ) ) {
			return;
		}

		$publicPostTypes = aioseo()->helpers->getPublicPostTypes( true );
		$postTypes       = array_intersect( (array) $this->oldOptions['aiosp_posttypecolumns'], $publicPostTypes );

		aioseo()->options->advanced->postTypes->included = array_values( $postTypes );
		if ( count( $publicPostTypes ) !== count( $postTypes ) ) {
			aioseo()->options->advanced->postTypes->all = false;
		}
	}

	/**
	 * Migrates the schema social URLs.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migrateSocialUrls() {
		if ( ! empty( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_facebook_publisher'] ) ) {
			aioseo()->options->social->profiles->urls->facebookPageUrl = esc_url( wp_strip_all_tags( $this->oldOptions['modules']['aiosp_opengraph_options']['aiosp_opengraph_facebook_publisher'] ) );
			aioseo()->options->social->profiles->sameUsername->enable = false;
		}

		if ( empty( $this->oldOptions['aiosp_schema_social_profile_links'] ) ) {
			return;
		}

		$socialUrls = aioseo()->helpers->pregReplace( '/\s/', '\r\n', $this->oldOptions['aiosp_schema_social_profile_links'] );
		$socialUrls = array_filter( explode( '\r\n', $socialUrls ) );

		if ( ! count( $socialUrls ) ) {
			return;
		}

		$supportedNetworks = [
			'facebook.com'   => 'facebookPageUrl',
			'twitter.com'    => 'twitterUrl',
			'instagram.com'  => 'instagramUrl',
			'tiktok.com'     => 'tiktokUrl',
			'pinterest.com'  => 'pinterestUrl',
			'youtube.com'    => 'youtubeUrl',
			'linkedin.com'   => 'linkedinUrl',
			'tumblr.com'     => 'tumblrUrl',
			'yelp.com'       => 'yelpPageUrl',
			'soundcloud.com' => 'soundCloudUrl',
			'wikipedia.org'  => 'wikipediaUrl',
			'myspace.com'    => 'myspaceUrl',
			'wordpress.org'  => 'wordpressUrl',
			'bsky.app'       => 'blueskyUrl',
			'threads.net'    => 'threadsUrl'
		];

		$found = false;
		foreach ( $supportedNetworks as $url => $settingName ) {
			$url = aioseo()->helpers->escapeRegex( $url );
			foreach ( $socialUrls as $socialUrl ) {
				if ( preg_match( "/.*$url.*/", (string) $socialUrl ) ) {
					aioseo()->options->social->profiles->urls->$settingName = esc_url( wp_strip_all_tags( $socialUrl ) );
					$found = true;
				}
			}
		}

		if ( $found ) {
			aioseo()->options->social->profiles->sameUsername->enable = false;
		}
	}

	/**
	 * Migrates the Schema Markup settings in the General Settings menu.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migrateSchemaMarkupSettings() {
		$this->migrateSchemaPhoneNumber();

		if (
			isset( $this->oldOptions['aiosp_schema_markup'] ) &&
			empty( $this->oldOptions['aiosp_schema_markup'] )
		) {
			$deprecatedOptions = aioseo()->internalOptions->internal->deprecatedOptions;
			array_push( $deprecatedOptions, 'enableSchemaMarkup' );
			aioseo()->internalOptions->internal->deprecatedOptions = $deprecatedOptions;
			aioseo()->options->deprecated->searchAppearance->global->schema->enableSchemaMarkup = false;
		}

		if ( ! empty( $this->oldOptions['aiosp_schema_person_user'] ) ) {
			if ( -1 === (int) $this->oldOptions['aiosp_schema_person_user'] ) {
				aioseo()->options->searchAppearance->global->schema->person = 'manual';
			} else {
				aioseo()->options->searchAppearance->global->schema->person = intval( $this->oldOptions['aiosp_schema_person_user'] );
			}
		}
	}

	/**
	 * Migrates the schema phone number.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migrateSchemaPhoneNumber() {
		if ( empty( $this->oldOptions['aiosp_schema_phone_number'] ) ) {
			return;
		}

		$phoneNumber = aioseo()->helpers->sanitizeOption( $this->oldOptions['aiosp_schema_phone_number'] );
		if ( ! preg_match( '#\+\d+#', (string) $phoneNumber ) ) {
			$notification = Models\Notification::getNotificationByName( 'v3-migration-schema-number' );
			if ( $notification->notification_name ) {
				return;
			}

			Models\Notification::addNotification( [
				'slug'              => uniqid(),
				'notification_name' => 'v3-migration-schema-number',
				'title'             => __( 'Invalid Phone Number for Knowledge Graph', 'all-in-one-seo-pack' ),
				'content'           => sprintf(
					// Translators: 1 - The phone number.
					__( 'The phone number that you previously entered for your Knowledge Graph schema markup is invalid. As it needs to be internationally formatted, please enter it (%1$s) again with the country code, e.g. +1 (555) 555-1234.', 'all-in-one-seo-pack' ), // phpcs:ignore Generic.Files.LineLength.MaxExceeded
					"<strong>$phoneNumber</strong>"
				),
				'type'              => 'warning',
				'level'             => [ 'all' ],
				'button1_label'     => __( 'Fix Now', 'all-in-one-seo-pack' ),
				'button1_action'    => 'http://route#aioseo-search-appearance&aioseo-scroll=schema-graph-phone&aioseo-highlight=schema-graph-phone:global-settings',
				'button2_label'     => __( 'Remind Me Later', 'all-in-one-seo-pack' ),
				'button2_action'    => 'http://action#notification/v3-migration-schema-number-reminder',
				'start'             => gmdate( 'Y-m-d H:i:s' )
			] );

			return;
		}
		aioseo()->options->searchAppearance->global->schema->phone = $phoneNumber;
	}

	/**
	 * Migrates the homepage keywords.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migrateHomePageKeywords() {
		if ( ! empty( $this->oldOptions['aiosp_home_keywords'] ) ) {
			aioseo()->options->searchAppearance->global->keywords = aioseo()->migration->helpers->oldKeywordsToNewKeywords( $this->oldOptions['aiosp_home_keywords'] );
		}
	}

	/**
	 * Migrates the deprecated V3 advanced General Settings options.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migrateDeprecatedAdvancedOptions() {
		$deprecatedOptions = aioseo()->internalOptions->internal->deprecatedOptions;

		if ( empty( $this->oldOptions['aiosp_generate_descriptions'] ) ) {
			array_push( $deprecatedOptions, 'autogenerateDescriptions' );
			aioseo()->options->deprecated->searchAppearance->advanced->autogenerateDescriptions = false;
		} else {
			if ( ! empty( $this->oldOptions['aiosp_skip_excerpt'] ) ) {
				array_push( $deprecatedOptions, 'useContentForAutogeneratedDescriptions' );
				aioseo()->options->deprecated->searchAppearance->advanced->useContentForAutogeneratedDescriptions = true;
			}
		}

		aioseo()->internalOptions->internal->deprecatedOptions = $deprecatedOptions;
	}

	/**
	 * Migrates the RSS content settings.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migrateRssContentSettings() {
		if ( isset( $this->oldOptions['aiosp_rss_content_before'] ) ) {
			aioseo()->options->rssContent->before = esc_html( aioseo()->migration->helpers->macrosToSmartTags( $this->oldOptions['aiosp_rss_content_before'] ) );
		}

		if ( isset( $this->oldOptions['aiosp_rss_content_after'] ) ) {
			aioseo()->options->rssContent->after = esc_html( aioseo()->migration->helpers->macrosToSmartTags( $this->oldOptions['aiosp_rss_content_after'] ) );
		}
	}

	/**
	 * Migrates the Redirect Attachment to Parent setting.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migrateRedirectToParent() {
		if ( isset( $this->oldOptions['aiosp_redirect_attachement_parent'] ) ) {
			if ( ! empty( $this->oldOptions['aiosp_redirect_attachement_parent'] ) ) {
				aioseo()->dynamicOptions->searchAppearance->postTypes->attachment->redirectAttachmentUrls = 'attachment_parent';
			} else {
				aioseo()->dynamicOptions->searchAppearance->postTypes->attachment->redirectAttachmentUrls = 'disabled';
			}
		}
	}

	/**
	 * Migrates the excluded posts.
	 *
	 * @since 4.0.0
	 *
	 * @return void
	 */
	private function migrateDisabledPosts() {
		if ( empty( $this->oldOptions['aiosp_ex_pages'] ) ) {
			return;
		}

		$deprecatedOptions = aioseo()->internalOptions->internal->deprecatedOptions;
		if ( ! in_array( 'excludePosts', $deprecatedOptions, true ) ) {
			array_push( $deprecatedOptions, 'excludePosts' );
			aioseo()->internalOptions->internal->deprecatedOptions = $deprecatedOptions;
		}

		$excludedPosts = aioseo()->options->deprecated->searchAppearance->advanced->excludePosts;
		$pages         = explode( ',', $this->oldOptions['aiosp_ex_pages'] );
		if ( count( $pages ) ) {
			foreach ( $pages as $page ) {
				$page = trim( $page );
				$id   = intval( $page );
				if ( ! $id ) {
					$post = get_page_by_path( $page, OBJECT, aioseo()->helpers->getPublicPostTypes( true ) );
					if ( $post && is_object( $post ) ) {
						$id = $post->ID;
					}
				}

				if ( $id ) {
					$post = get_post( $id );
					if ( ! is_object( $post ) ) {
						continue;
					}

					$excludedPost        = new \stdClass();
					$excludedPost->value = $id;
					$excludedPost->type  = $post->post_type;
					$excludedPost->label = $post->post_title;
					$excludedPost->link  = get_permalink( $id );

					array_push( $excludedPosts, wp_json_encode( $excludedPost ) );
				}
			}
		}
		aioseo()->options->deprecated->searchAppearance->advanced->excludePosts = $excludedPosts;
	}

	/**
	 * Migrates the deprecated "No Pagination for Canonical URLs" setting.
	 *
	 * @since 4.5.9
	 *
	 * @return void
	 */
	private function migrateNoPaginationForCanonicalUrls() {
		if ( empty( $this->oldOptions['aiosp_no_paged_canonical_links'] ) ) {
			return;
		}

		$deprecatedOptions = aioseo()->internalOptions->deprecatedOptions;
		if ( ! in_array( 'noPaginationForCanonical', $deprecatedOptions, true ) ) {
			$deprecatedOptions[]                         = 'noPaginationForCanonical';
			aioseo()->internalOptions->deprecatedOptions = $deprecatedOptions;
		}

		aioseo()->options->deprecated->searchAppearance->advanced->noPaginationForCanonical = true;
	}
}