<?php
/**
 * The AIO SEO Import Class
 *
 * @since      0.9.0
 * @package    RankMath
 * @subpackage RankMath\Admin\Importers
 * @author     Rank Math <support@rankmath.com>
 */

namespace RankMath\Admin\Importers;

use RankMath\Helper;
use RankMath\Admin\Admin_Helper;
use RankMath\Redirections\Redirection;
use RankMath\Helpers\DB;

defined( 'ABSPATH' ) || exit;

/**
 * AIOSEO class.
 */
class AIOSEO extends Plugin_Importer {

	/**
	 * The plugin name.
	 *
	 * @var string
	 */
	protected $plugin_name = 'All In One SEO Pack';

	/**
	 * Plugin options meta key.
	 *
	 * @var string
	 */
	protected $meta_key = '_aioseop_';

	/**
	 * Option keys to import and clean.
	 *
	 * @var array
	 */
	protected $option_keys = [ 'aioseo_options' ];

	/**
	 * Choices keys to import.
	 *
	 * @var array
	 */
	protected $choices = [ 'settings', 'postmeta', 'termmeta', 'usermeta', 'redirections', 'locations' ];

	/**
	 * AIOSEO settings.
	 *
	 * @var array
	 */
	private $aio_settings = [];

	/**
	 * Get the actions which can be performed for the plugin.
	 *
	 * @return array
	 */
	public function get_choices() {
		$choices = [
			'settings' => esc_html__( 'Import Settings', 'rank-math' ) . Admin_Helper::get_tooltip( esc_html__( 'Import AIO SEO plugin settings, global meta, sitemap settings, etc.', 'rank-math' ) ),
			'postmeta' => esc_html__( 'Import Post Meta', 'rank-math' ) . Admin_Helper::get_tooltip( esc_html__( 'Import meta information of your posts/pages like the titles, descriptions, robots meta, OpenGraph info, etc.', 'rank-math' ) ),
			'usermeta' => esc_html__( 'Import Author Meta', 'rank-math' ) . Admin_Helper::get_tooltip( esc_html__( 'Import Social URLs of your author archive pages.', 'rank-math' ) ),
		];

		if ( DB::check_table_exists( 'aioseo_terms' ) ) {
			$choices['termmeta'] = esc_html__( 'Import Term Meta', 'rank-math' ) . Admin_Helper::get_tooltip( esc_html__( 'Import meta information of your terms like the titles, descriptions, robots meta, OpenGraph info, etc.', 'rank-math' ) );
		}

		if ( DB::check_table_exists( 'aioseo_redirects' ) ) {
			$choices['redirections'] = esc_html__( 'Import Redirections', 'rank-math' ) . Admin_Helper::get_tooltip( esc_html__( 'Import all the redirections you have already set up in AIO SEO Premium.', 'rank-math' ) );
		}

		if ( ! empty( $this->get_location_ids( true ) ) ) {
			$choices['locations'] = esc_html__( 'Import Locations', 'rank-math' ) . Admin_Helper::get_tooltip( esc_html__( 'Import Locations Settings.', 'rank-math' ) );
		}

		return $choices;
	}

	/**
	 * Convert Yoast / AIO SEO variables if needed.
	 *
	 * @param string $string Value to convert.
	 * @return string
	 */
	public function convert_variables( $string ) {
		$string = str_replace( '#site_title', '%sitename%', $string );
		$string = str_replace( '#tagline', '%sitedesc%', $string );
		$string = str_replace( '#separator_sa', '%sep%', $string );
		$string = str_replace( '#post_title', '%title%', $string );
		$string = str_replace( '#post_excerpt', '%excerpt%', $string );
		$string = str_replace( '#post_content', '%excerpt%', $string );
		$string = str_replace( '#taxonomy_description', '%term_description%', $string );
		$string = str_replace( '#category_description', '%term_description%', $string );
		$string = str_replace( '#taxonomy_title', '%term%', $string );
		$string = str_replace( '#category', '%term%', $string );
		$string = str_replace( '#author_first_name #author_last_name', '%name%', $string );
		$string = str_replace( '#current_year', '%currentyear%', $string );
		$string = str_replace( '#current_date', '%currentdate%', $string );
		$string = str_replace( '#current_day', '%currentday%', $string );
		$string = str_replace( '#current_month', '%currentmonth%', $string );
		$string = str_replace( '#post_date', '%date%', $string );
		$string = str_replace( '#search_term', '%search_query%', $string );
		$string = str_replace( '#author_link', '%AUTHORLINK%', $string );
		$string = str_replace( '#post_link', '%POSTLINK%', $string );
		$string = str_replace( '#site_link', '%BLOGLINK%', $string );
		$string = str_replace( '#author_name', '%name%', $string );
		$string = str_replace( '#author_bio', '%user_description%', $string );
		$string = str_replace( '#archive_date', '%date%', $string );
		$string = str_replace( '#breadcrumb_archive_post_type_name', '%s', $string );
		$string = str_replace( '#breadcrumb_search_string', '%s', $string );

		return $string;
	}

	/**
	 * Import settings of plugin.
	 *
	 * @return bool
	 */
	protected function settings() {
		$this->get_settings();
		$this->aio_settings = json_decode( get_option( 'aioseo_options' ), true );

		$this->general_settings();
		$this->sitemap_settings();
		$this->titles_settings();
		$this->pro_settings();
		$this->update_settings();

		return true;
	}

	/**
	 * Imports redirections data.
	 *
	 * @return array
	 */
	protected function redirections() {
		$count        = 0;
		$table        = DB::query_builder( 'aioseo_redirects' );
		$redirections = $table->select( '*' )->get();

		if ( empty( $redirections ) ) {
			return compact( 'count' );
		}

		Helper::update_modules( [ 'redirections' => 'on' ] );
		foreach ( $redirections as $redirection ) {
			if ( false !== $this->save_redirection( (array) $redirection ) ) {
				$count++;
			}
		}

		return compact( 'count' );
	}

	/**
	 * Save redirection.
	 *
	 * @param array $redirection Redirection object.
	 *
	 * @return mixed
	 */
	private function save_redirection( $redirection ) {
		if (
			empty( $redirection['source_url'] ) ||
			empty( $redirection['type'] ) ||
			! in_array( $redirection['type'], [ '301', '302', '307', '410', '451' ], true )
		) {
			return false;
		}

		$item = Redirection::from(
			[
				'sources'     => [
					[
						'ignore'     => ! empty( $redirection['ignore_case'] ) ? 'case' : '',
						'pattern'    => $redirection['source_url'],
						'comparison' => isset( $redirection['source_url_match'] ) && 'regex' === $redirection['source_url_match'] ? 'regex' : 'exact',
					],
				],
				'url_to'      => isset( $redirection['target_url'] ) ? $redirection['target_url'] : '',
				'header_code' => isset( $redirection['type'] ) ? $redirection['type'] : '301',
				'status'      => empty( $redirection['enabled'] ) ? 'inactive' : 'active',
			]
		);

		return $item->save();
	}

	/**
	 * Import General Settings.
	 */
	private function general_settings() {
		if ( ! empty( $this->aio_settings['rssContent'] ) ) {
			$hash = [
				'before' => 'rss_before_content',
				'after'  => 'rss_after_content',
			];
			$this->replace( $hash, $this->aio_settings['rssContent'], $this->settings, 'convert_variables' );
		}

		if ( ! empty( $this->aio_settings['breadcrumbs'] ) ) {
			$hash = [
				'enable'             => 'breadcrumbs',
				'separator'          => 'breadcrumbs_separator',
				'homepageLabel'      => 'breadcrumbs_home_label',
				'breadcrumbPrefix'   => 'breadcrumbs_prefix',
				'archiveFormat'      => 'breadcrumbs_archive_format',
				'searchResultFormat' => 'breadcrumbs_search_format',
				'errorFormat404'     => 'breadcrumbs_404_label',
				'showCurrentItem'    => 'breadcrumbs_remove_post_title',
			];
			$this->replace( $hash, $this->aio_settings['breadcrumbs'], $this->settings, 'convert_variables' );
			$this->replace( [ 'homepageLink' => 'breadcrumbs_home' ], $this->aio_settings['breadcrumbs'], $this->settings, 'convert_bool' );
		}

		if ( ! empty( $this->aio_settings['webmasterTools'] ) ) {
			$hash = [
				'google'    => 'google_verify',
				'bing'      => 'bing_verify',
				'baidu'     => 'baidu_verify',
				'yandex'    => 'yandex_verify',
				'pinterest' => 'pinterest_verify',
			];
			$this->replace( $hash, $this->aio_settings['webmasterTools'], $this->settings );
		}
	}

	/**
	 * Sitemap settings.
	 */
	private function sitemap_settings() {
		if ( empty( $this->aio_settings['sitemap'] ) ) {
			return;
		}

		$sitemap_settings = $this->aio_settings['sitemap'];
		$general          = ! empty( $sitemap_settings['general'] ) ? $sitemap_settings['general'] : [];
		if ( empty( $general ) ) {
			return;
		}

		// Sitemap.
		if ( isset( $general['enable'] ) ) {
			Helper::update_modules( [ 'sitemap' => 'on' ] );
		}

		$this->sitemap['items_per_page'] = $general['linksPerIndex'];

		$all = ! empty( $general['postTypes']['all'] );
		foreach ( Helper::get_accessible_post_types() as $post_type ) {
			$this->sitemap[ "pt_{$post_type}_sitemap" ] = $all || in_array( $post_type, $general['postTypes']['included'], true ) ? 'on' : 'off';
		}

		$all = ! empty( $general['taxonomies']['all'] );
		foreach ( Helper::get_accessible_taxonomies() as $taxonomy => $object ) {
			$this->sitemap[ "tax_{$taxonomy}_sitemap" ] = $all || in_array( $taxonomy, $general['taxonomies']['included'], true ) ? 'on' : 'off';
		}

		if ( ! empty( $general['advancedSettings'] ) ) {
			$this->sitemap_advanced_settings( $general['advancedSettings'] );
		}

		// HTML Sitemap.
		if ( isset( $sitemap_settings['html'] ) ) {
			$this->html_sitemap_settings( $sitemap_settings['html'] );
		}
	}

	/**
	 * Import Pro Settings.
	 */
	private function pro_settings() {
		$settings = get_option( 'aioseo_options_pro' );
		if ( empty( $settings ) ) {
			return;
		}

		$settings = json_decode( $settings, true );
		$this->news_sitemap_settings( $settings );
		$this->video_sitemap_settings( $settings );
		$this->image_seo_settings( $settings );
		$this->local_seo_settings( $settings );
	}

	/**
	 * Import Local SEO Settings.
	 *
	 * @param array $settings Pro Settings.
	 */
	private function local_seo_settings( $settings ) {
		if ( empty( $settings['localBusiness'] ) ) {
			return;
		}

		Helper::update_modules( [ 'local-seo' => 'on' ] );
		$local_settings = $settings['localBusiness'];
		$business       = $local_settings['locations']['business'];

		$hash = [
			'name'         => 'knowledgegraph_name',
			'image'        => 'knowledgegraph_logo',
			'businessType' => 'local_business_type',
		];
		$this->replace( $hash, $business, $this->titles );
		$this->titles['url'] = $business['urls']['website'];

		// Street Address.
		$address = [];
		$hash    = [
			'streetLine1' => 'streetAddress',
			'city'        => 'addressLocality',
			'state'       => 'addressRegion',
			'zipCode'     => 'postalCode',
			'country'     => 'addressCountry',
		];
		$this->replace( $hash, $business['address'], $address );
		if ( ! empty( $business['address']['streetLine2'] ) ) {
			$address['streetAddress'] = $address['streetAddress'] . ', ' . $business['address']['streetLine2'];
		}
		$this->titles['local_address'] = $address;

		if ( ! empty( $business['contact'] ) ) {
			$this->titles['email'] = $business['contact']['email'];

			$this->titles['phone_numbers'][] = [
				'type'   => 'customer support',
				'number' => $business['contact']['phone'],
			];
		}

		if ( ! empty( $business['payment'] ) ) {
			$this->titles['price_range'] = $business['payment']['priceRange'];
		}

		if ( ! empty( $local_settings['openingHours'] ) ) {
			$this->add_opening_hours( $local_settings['openingHours'] );
		}
	}

	/**
	 * Import Opening Hours Settings.
	 *
	 * @param array $opening_hours Opening Hours.
	 */
	private function add_opening_hours( $opening_hours ) {
		$data = [];
		foreach ( $opening_hours['days'] as $day => $opening_hour ) {
			if ( ! empty( $opening_hour['closed'] ) ) {
				continue;
			}

			$data[] = [
				'day'  => ucfirst( $day ),
				'time' => $opening_hour['openTime'] . '-' . $opening_hour['closeTime'],
			];
		}

		$this->titles['opening_hours'] = $data;
	}

	/**
	 * Import Image SEO Settings.
	 *
	 * @param array $settings Pro Settings.
	 */
	private function image_seo_settings( $settings ) {
		if ( empty( $settings['image']['format'] ) ) {
			return;
		}

		Helper::update_modules( [ 'image-seo' => 'on' ] );
		$format = $settings['image']['format'];
		if ( ! empty( $format['title'] ) ) {
			$this->settings['add_img_title'] = $this->convert_variables( $format['title'] );
		}

		if ( ! empty( $format['altTag'] ) ) {
			$this->settings['add_img_title'] = $this->convert_variables( $format['altTag'] );
		}
	}

	/**
	 * Import Video Sitemap Settings.
	 *
	 * @param array $settings Pro Settings.
	 */
	private function video_sitemap_settings( $settings ) {
		if ( empty( $settings['sitemap']['video'] ) ) {
			return;
		}
		$video_settings = $settings['sitemap']['video'];
		if ( ! empty( $video_settings['enable'] ) ) {
			Helper::update_modules( [ 'video-sitemap' => 'on' ] );
		}

		$this->sitemap['video_sitemap_post_type'] = $video_settings['postTypes']['all'] ? array_keys( Helper::get_accessible_post_types() ) : $video_settings['postTypes']['included'];
	}

	/**
	 * Import News Sitemap Settings.
	 *
	 * @param array $settings Pro Settings.
	 */
	private function news_sitemap_settings( $settings ) {
		if ( empty( $settings['sitemap']['news'] ) ) {
			return;
		}
		$news_settings = $settings['sitemap']['news'];
		if ( ! empty( $news_settings['enable'] ) ) {
			Helper::update_modules( [ 'news-sitemap' => 'on' ] );
		}

		$this->sitemap['news_sitemap_publication_name'] = ! empty( $news_settings['publicationName'] ) ? $news_settings['publicationName'] : '';
		$this->sitemap['news_sitemap_post_type']        = $news_settings['postTypes']['all'] ? array_keys( Helper::get_accessible_post_types() ) : $news_settings['postTypes']['included'];
	}

	/**
	 * Import Sitemap Advanced Settings.
	 *
	 * @param array $settings Sitemap Settings.
	 */
	private function sitemap_advanced_settings( $settings ) {
		if ( ! empty( $settings['excludePosts'] ) ) {
			$exclude_posts = [];
			foreach ( $settings['excludePosts'] as $exclude_post ) {
				$exclude_post    = json_decode( $exclude_post, true );
				$exclude_posts[] = ! empty( $exclude_post['value'] ) ? $exclude_post['value'] : '';
			}

			$this->sitemap['exclude_posts'] = implode( ', ', $exclude_posts );
		}

		if ( ! empty( $settings['excludeTerms'] ) ) {
			$exclude_terms = [];
			foreach ( $settings['excludeTerms'] as $exclude_term ) {
				$exclude_term    = json_decode( $exclude_term, true );
				$exclude_terms[] = ! empty( $exclude_term['value'] ) ? $exclude_term['value'] : '';
			}

			$this->sitemap['exclude_terms'] = $exclude_terms;
		}

		$this->sitemap['include_images'] = ! empty( $settings['excludeImages'] ) ? 'off' : 'on';
	}

	/**
	 * Import HTML Sitemap Settings.
	 *
	 * @param array $settings HTML Settings.
	 */
	private function html_sitemap_settings( $settings ) {
		if ( empty( $settings ) ) {
			return;
		}

		$this->sitemap['html_sitemap']         = $settings['enable'] ? 'on' : 'off';
		$this->sitemap['html_sitemap_display'] = empty( $settings['pageUrl'] ) ? 'shortcode' : 'page';
		if ( ! empty( $settings['pageUrl'] ) ) {
			$page = get_page_by_path( basename( $settings['pageUrl'] ) );
			if ( ! empty( $page ) ) {
				$this->sitemap['html_sitemap_page'] = $page->ID;
			} else {
				// Create a new page with the sitemap page url.
				$this->sitemap['html_sitemap_page'] = wp_insert_post(
					[
						'post_title'   => __( 'HTML Sitemap', 'rank-math' ),
						'post_content' => '',
						'post_status'  => 'publish',
						'post_type'    => 'page',
						'post_name'    => basename( $settings['pageUrl'] ),
					]
				);
			}
		}

		if ( ! empty( $settings['postTypes']['all'] ) ) {
			$post_types = Helper::get_accessible_post_types();
			$post_types = array_keys( $post_types );
			foreach ( $post_types as $post_type ) {
				$this->sitemap[ 'pt_' . $post_type . '_html_sitemap' ] = in_array( $post_type, $settings['postTypes']['included'], true ) ? 'on' : 'off';
			}
		} else {
			foreach ( $settings['postTypes']['included'] as $post_type ) {
				$this->sitemap[ 'pt_' . $post_type . '_html_sitemap' ] = 'on';
			}
		}

		if ( ! empty( $settings['taxonomies']['all'] ) ) {
			$taxonomies = Helper::get_accessible_taxonomies();
			$taxonomies = array_keys( $taxonomies );
			foreach ( $taxonomies as $taxonomy ) {
				$this->sitemap[ 'tax_' . $taxonomy . '_html_sitemap' ] = in_array( $taxonomy, $settings['taxonomies']['included'], true ) ? 'on' : 'off';
			}
		} else {
			foreach ( $settings['taxonomies']['included'] as $taxonomy ) {
				$this->sitemap[ 'tax_' . $taxonomy . '_html_sitemap' ] = 'on';
			}
		}

	}

	/**
	 * Import Titles & Meta Settings.
	 */
	private function titles_settings() {
		$settings = $this->aio_settings['searchAppearance'];
		$hash     = [
			'separator'       => 'title_separator',
			'siteTitle'       => 'homepage_title',
			'metaDescription' => 'homepage_description',
		];

		$this->replace( $hash, $settings['global'], $this->titles, 'convert_variables' );

		$this->titles['noindex_empty_taxonomies'] = $settings['advanced']['noIndexEmptyCat'];
		$this->titles['knowledgegraph_type']      = 'organization' === $settings['global']['schema']['siteRepresents'] ? 'company' : 'person';
		$this->titles['knowledgegraph_name']      = $settings['global']['schema']['organizationName'];
		$this->titles['knowledgegraph_logo']      = $settings['global']['schema']['organizationLogo'];

		$robots = $this->get_robots_data( $settings['advanced']['globalRobotsMeta'] );

		$this->titles['robots_global']          = $robots['robots'];
		$this->titles['advanced_robots_global'] = $robots['advanced_robots'];

		$this->social_settings();
		$this->archive_settings();
		$this->post_types_settings();
		$this->taxonomies_settings();
	}

	/**
	 * Import Social Settings.
	 */
	private function social_settings() {
		if ( empty( $this->aio_settings['social'] ) ) {
			return;
		}

		$hash = [
			'adminId'   => 'facebook_admin_id',
			'appId'     => 'facebook_app_id',
			'authorUrl' => 'facebook_author_urls',
		];
		$this->replace( $hash, $this->aio_settings['social']['facebook']['advanced'], $this->titles );

		$hash = [
			'title'       => 'homepage_facebook_title',
			'description' => 'homepage_facebook_description',
			'image'       => 'homepage_facebook_image',
		];
		$this->replace( $hash, $this->aio_settings['social']['facebook']['homePage'], $this->titles );

		$profiles        = $this->aio_settings['social']['profiles'];
		$profile_urls    = $profiles['urls'];
		$fb_url          = $profile_urls['facebookPageUrl'];
		$tw_url          = $profile_urls['twitterUrl'];
		$additional_urls = $profiles['additionalUrls'];

		$profile_urls = array_map(
			function( $url ) use ( $fb_url, $tw_url ) {
				return $url !== $fb_url && $url !== $tw_url ? $url : false;
			},
			$profile_urls
		);

		$urls = array_filter( array_values( $profile_urls ) );
		array_merge( $urls, explode( "\n", $additional_urls ) );

		$this->titles['social_additional_profiles'] = implode( PHP_EOL, $urls );
		$this->titles['social_url_facebook']        = $fb_url;
		$this->titles['twitter_author_names']       = str_replace( 'https://twitter.com/', '', $tw_url );
	}

	/**
	 * Archive settings.
	 */
	private function archive_settings() {
		$settings = $this->aio_settings['searchAppearance']['archives'];
		$author   = $settings['author'];
		$hash     = [
			'title'           => 'author_archive_title',
			'metaDescription' => 'author_archive_description',
		];
		$this->replace( $hash, $author, $this->titles, 'convert_variables' );
		$this->titles['disable_author_archives'] = $author['show'] ? 'off' : 'on';
		$this->titles['author_add_meta_box']     = $author['advanced']['showMetaBox'];
		$this->titles['author_custom_robots']    = ! $author['advanced']['robotsMeta']['default'];
		$robots                                  = $this->get_robots_data( $author['advanced']['robotsMeta'] );
		$this->titles['author_robots']           = $robots['robots'];
		$this->titles['author_advanced_robots']  = $robots['advanced_robots'];

		$date = $settings['date'];
		$hash = [
			'title'           => 'date_archive_title',
			'metaDescription' => 'date_archive_description',
		];
		$this->replace( $hash, $date, $this->titles, 'convert_variables' );
		$this->titles['disable_date_archives'] = $date['show'] ? 'off' : 'on';
		$robots                                = $this->get_robots_data( $date['advanced']['robotsMeta'] );
		$this->titles['date_archive_robots']   = $robots['robots'];
		$this->titles['date_advanced_robots']  = $robots['advanced_robots'];

		$this->titles['search_title'] = $this->convert_variables( $settings['search']['title'] );
	}

	/**
	 * Post Types settings.
	 */
	private function post_types_settings() {
		$settings = $this->aio_settings['searchAppearance']['dynamic']['postTypes'];
		foreach ( Helper::get_accessible_post_types() as $post_type ) {
			if ( empty( $settings[ $post_type ] ) ) {
				continue;
			}

			$hash = [
				'title'           => "pt_{$post_type}_title",
				'metaDescription' => "pt_{$post_type}_description",
				'customFields'    => "pt_{$post_type}_analyze_fields",
			];
			$this->replace( $hash, $settings[ $post_type ], $this->titles, 'convert_variables' );

			if ( ! empty( $settings[ $post_type ]['schemaType'] ) ) {
				$schema_type = strtolower( $settings[ $post_type ]['schemaType'] );
				if ( in_array( $schema_type, [ 'article', 'book', 'course', 'dataset', 'event', 'jobposting', 'movie', 'music', 'person', 'product', 'recipe', 'restaurant', 'service', 'software', 'video' ], true ) ) {
					$this->titles[ "pt_{$post_type}_default_rich_snippet" ] = $schema_type;
					$this->titles[ "pt_{$post_type}_default_article_type" ] = $settings[ $post_type ]['articleType'];
				}
			}

			$robots = $settings[ $post_type ]['advanced']['robotsMeta'];
			if ( ! empty( $robots['default'] ) ) {
				$this->titles[ "pt_{$post_type}_custom_robots" ] = 'off';
				continue;
			}

			$robots = $this->get_robots_data( $robots );
			$this->titles[ "pt_{$post_type}_custom_robots" ]   = 'on';
			$this->titles[ "pt_{$post_type}_robots" ]          = $robots['robots'];
			$this->titles[ "pt_{$post_type}_advanced_robots" ] = $robots['advanced_robots'];
		}
	}

	/**
	 * Taxonomies settings.
	 */
	private function taxonomies_settings() {
		if ( ! isset( $this->aio_settings['searchAppearance']['dynamic']['taxonomies'] ) ) {
			return;
		}

		$settings = $this->aio_settings['searchAppearance']['dynamic']['taxonomies'];
		foreach ( Helper::get_accessible_taxonomies() as $taxonomy => $tax_obj ) {
			if ( empty( $settings[ $taxonomy ] ) ) {
				continue;
			}

			$hash = [
				'title'           => "tax_{$taxonomy}_title",
				'metaDescription' => "tax_{$taxonomy}_description",
			];
			$this->replace( $hash, $settings[ $taxonomy ], $this->titles, 'convert_variables' );

			$robots                                   = $this->get_robots_data( $settings[ $taxonomy ]['advanced']['robotsMeta'] );
			$this->titles[ "tax_{$taxonomy}_robots" ] = $robots['robots'];
			$this->titles[ "tax_{$taxonomy}_advanced_robots" ] = $robots['advanced_robots'];
			$this->titles[ "tax_{$taxonomy}_add_meta_box" ]    = ! empty( $settings[ $taxonomy ]['show'] ) ? 'on' : '';
		}
	}

	/**
	 * Function to get Robots data.
	 *
	 * @param  array $aioseo_robots AIOSEO robots.
	 * @return array Robots data.
	 */
	private function get_robots_data( $aioseo_robots ) {
		$robots          = [];
		$advanced_robots = [];
		$keys            = [
			'maxSnippet'      => 'max-snippet',
			'maxVideoPreview' => 'max-video-preview',
			'maxImagePreview' => 'max-image-preview',
		];
		foreach ( $aioseo_robots as $key => $value ) {
			if ( in_array( $key, [ 'noindex', 'nofollow', 'noarchive', 'noimageindex', 'nosnippet' ], true ) && $value ) {
				$robots[] = $key;
			}

			if ( in_array( $key, [ 'maxSnippet', 'maxVideoPreview', 'maxImagePreview' ], true ) && $value ) {
				$advanced_robots[ $keys[ $key ] ] = $value;
			}
		}
		$robots[] = ! in_array( 'noindex', $robots, true ) ? 'index' : '';

		return [
			'robots'          => $robots,
			'advanced_robots' => $advanced_robots,
		];
	}

	/**
	 * Import post meta of plugin.
	 *
	 * @return array
	 */
	protected function postmeta() {
		$this->set_pagination( $this->get_posts( true ) );
		$posts = $this->get_posts();

		foreach ( $posts as $post ) {
			$post_id = (int) $post->post_id;
			$post    = (array) $post;
			$hash    = [
				'title'                    => 'rank_math_title',
				'description'              => 'rank_math_description',
				'canonical_url'            => 'rank_math_canonical_url',
				'og_title'                 => 'rank_math_facebook_title',
				'og_description'           => 'rank_math_facebook_description',
				'og_image_custom_url'      => 'rank_math_facebook_image',
				'twitter_title'            => 'rank_math_twitter_title',
				'twitter_description'      => 'rank_math_twitter_description',
				'twitter_image_custom_url' => 'rank_math_twitter_image',
			];
			$this->replace_meta( $hash, $post, $post_id, 'post', 'convert_variables' );
			$this->replace_meta( [ 'twitter_use_og' => 'rank_math_twitter_use_facebook' ], $post, $post_id, 'post', 'convert_bool' );
			$this->set_object_robots( $post_id, $post, 'post' );
			$this->set_keywords( $post_id, $post, 'post' );
			$this->add_schema_data( $post_id, $post );
		}

		return $this->get_pagination_arg();
	}

	/**
	 * Import term meta of plugin.
	 *
	 * @return array
	 */
	protected function termmeta() {
		$this->set_pagination( $this->get_terms( true ) );
		$terms = $this->get_terms();

		foreach ( $terms as $term ) {
			$term_id = $term->term_id;
			$term    = (array) $term;
			$hash    = [
				'title'                    => 'rank_math_title',
				'description'              => 'rank_math_description',
				'canonical_url'            => 'rank_math_canonical_url',
				'og_title'                 => 'rank_math_facebook_title',
				'og_description'           => 'rank_math_facebook_description',
				'og_image_custom_url'      => 'rank_math_facebook_image',
				'twitter_title'            => 'rank_math_twitter_title',
				'twitter_description'      => 'rank_math_twitter_description',
				'twitter_image_custom_url' => 'rank_math_twitter_image',
			];
			$this->replace_meta( $hash, $term, $term_id, 'term', 'convert_variables' );
			$this->replace_meta( [ 'twitter_use_og' => 'rank_math_twitter_use_facebook' ], $term, $term_id, 'term', 'convert_bool' );
			$this->set_object_robots( $term_id, $term, 'term' );
			$this->set_keywords( $term_id, $term, 'term' );
		}

		return [ 'count' => count( $terms ) ];
	}

	/**
	 * Import user meta of plugin.
	 *
	 * @return array
	 */
	protected function usermeta() {
		$this->set_pagination( $this->get_user_ids( true ) );
		$user_ids = $this->get_user_ids();

		$hash = [
			'wpseo_title'    => 'rank_math_title',
			'wpseo_desc'     => 'rank_math_description',
			'wpseo_metadesc' => 'rank_math_description',
		];

		foreach ( $user_ids as $user ) {
			$userid = $user->ID;

			$facebook_url = get_user_meta( $userid, 'aioseo_facebook_page_url', true );
			if ( $facebook_url ) {
				update_user_meta( $userid, 'facebook', $facebook_url );
			}

			$twitter_url = get_user_meta( $userid, 'aioseo_twitter_url', true );
			if ( $twitter_url ) {
				update_user_meta( $userid, 'twitter', str_replace( 'https://twitter.com/', '', $twitter_url ) );
			}

			$social_urls = [];
			foreach ( [ 'aioseo_instagram_url', 'aioseo_pinterest_url', 'aioseo_youtube_url', 'aioseo_linkedin_url', 'aioseo_tumblr_url', 'aioseo_yelp_page_url', 'aioseo_sound_cloud_url', 'aioseo_wikipedia_url', 'aioseo_myspace_url' ] as $key ) {
				$social_urls[] = get_user_meta( $userid, $key, true );
			}

			$additional_urls = get_user_meta( 4, 'aioseo_profiles_additional_urls', true );
			if ( $additional_urls ) {
				$social_urls = array_merge( $social_urls, explode( "\n", $additional_urls ) );
			}

			if ( ! empty( $social_urls ) ) {
				update_user_meta( $userid, 'additional_profile_urls', implode( ' ', array_filter( $social_urls ) ) );
			}
		}

		return $this->get_pagination_arg();
	}

	/**
	 * Deactivate plugin action.
	 */
	protected function deactivate() {
		if ( is_plugin_active( $this->get_plugin_file() ) ) {
			deactivate_plugins( $this->get_plugin_file() );
			deactivate_plugins( 'aioseo-image-seo/aioseo-image-seo.php' );
			deactivate_plugins( 'aioseo-local-business/aioseo-local-business.php' );
			deactivate_plugins( 'aioseo-news-sitemap/aioseo-news-sitemap.php' );
			deactivate_plugins( 'aioseo-video-sitemap/aioseo-video-sitemap.php' );
			deactivate_plugins( 'aioseo-local-business/aioseo-local-business.php' );
			deactivate_plugins( 'aioseo-redirects/aioseo-redirects.php' );
		}

		return true;
	}

	/**
	 * Get all post IDs of all allowed post types only.
	 *
	 * @param bool $count If we need count only for pagination purposes.
	 * @return int|array
	 */
	private function get_posts( $count = false ) {
		$paged = $this->get_pagination_arg( 'page' );
		$table = DB::query_builder( 'aioseo_posts' );

		return $count ? absint( $table->selectCount( 'ID', 'total' )->getVar() ) :
			$table->select( '*' )->page( $paged - 1, $this->items_per_page )->get();
	}

	/**
	 * Get all post IDs of all allowed post types only.
	 *
	 * @param bool $count If we need count only for pagination purposes.
	 * @return int|array
	 */
	private function get_terms( $count = false ) {
		$paged = $this->get_pagination_arg( 'page' );
		$table = DB::query_builder( 'aioseo_terms' );

		return $count ? absint( $table->selectCount( 'ID', 'total' )->getVar() ) :
			$table->select( '*' )->page( $paged - 1, $this->items_per_page )->get();
	}

	/**
	 * Import Schema Data.
	 *
	 * @param int   $post_id Post ID.
	 * @param array $post    Post data.
	 */
	private function add_schema_data( $post_id, $post ) {
		if ( empty( $post['schema_type'] ) || ! in_array( $post['schema_type'], [ 'SoftwareApplication', 'Product', 'Recipe', 'Course' ], true ) ) {
			return;
		}

		$type   = strtolower( $post['schema_type'] );
		$type   = 'softwareapplication' === $type ? 'software' : $type;
		$schema = json_decode( $post['schema_type_options'], true );
		$data   = $this->$type( $schema[ $type ] );
		$schema = [
			'metadata' => [
				'title'                   => $data['@type'],
				'isPrimary'               => true,
				'type'                    => 'template',
				'reviewLocation'          => 'custom',
				'reviewLocationShortcode' => '[rank_math_rich_snippet]',
			],
		] + $data;

		update_post_meta( $post_id, 'rank_math_schema_' . $schema['@type'], $schema );
	}

	/**
	 * Import Software Schema Data.
	 *
	 * @param array $data Software schema data.
	 */
	private function software( $data ) {
		$schema = [
			'@type'               => 'SoftwareApplication',
			'name'                => ! empty( $data['name'] ) ? $data['name'] : '%seo_title%',
			'applicationCategory' => $data['category'],
			'offers'              => [
				'@type'         => 'Offer',
				'price'         => $data['price'],
				'priceCurrency' => $data['currency'],
			],
		];

		if ( ! empty( $data['operatingSystems'] ) ) {
			$operating_system = array_map(
				function( $system ) {
					return $system['value'];
				},
				json_decode( $data['operatingSystems'], true )
			);

			$schema['operatingSystem'] = implode( ', ', $operating_system );
		}

		if ( ! empty( $data['reviews'] ) ) {
			$reviews          = json_decode( $data['reviews'][0], true );
			$schema['review'] = [
				'@type'         => 'Review',
				'datePublished' => '%date(Y-m-dTH:i:sP)%',
				'dateModified'  => '%modified(Y-m-dTH:i:sP)%',
				'author'        => [
					'@type' => 'Person',
					'name'  => '%name%',
				],
				'reviewRating'  => [
					'@type'       => 'Rating',
					'ratingValue' => ! empty( $reviews['rating'] ) ? $reviews['rating'] : '',
				],
			];
		}

		return $schema;
	}

	/**
	 * Import Product Schema Data.
	 *
	 * @param array $data Product schema data.
	 */
	private function product( $data ) {
		return [
			'@type'       => 'Product',
			'name'        => ! empty( $data['name'] ) ? $data['name'] : '%seo_title%',
			'description' => ! empty( $data['description'] ) ? $data['description'] : '%seo_description%',
			'gtin8'       => $data['identifier'],
			'brand'       => [
				'@type' => 'Brand',
				'name'  => $data['brand'],
			],
			'offers'      => [
				'@type'           => 'Offer',
				'price'           => $data['price'],
				'priceCurrency'   => $data['currency'],
				'priceValidUntil' => $data['priceValidUntil'],
				'availability'    => str_replace( 'https://schema.org/', '', $data['availability'] ),
			],
		];
	}

	/**
	 * Import Course Schema Data.
	 *
	 * @param array $data Course schema data.
	 */
	private function course( $data ) {
		return [
			'@type'       => 'Course',
			'name'        => $data['name'],
			'description' => $data['description'],
			'provider'    => [
				'@type' => 'Organization',
				'name'  => $data['provider'],
			],
		];
	}

	/**
	 * Import Recipe Schema Data.
	 *
	 * @param array $data Recipe schema data.
	 */
	private function recipe( $data ) {
		$schema = [
			'@type'          => 'Recipe',
			'name'           => $data['name'],
			'recipeCategory' => $data['dishType'],
			'recipeCuisine'  => $data['cuisineType'],
			'prepTime'       => "PT{$data['preparationTime']}M",
			'cookTime'       => "PT{$data['cookingTime']}M",
			'recipeYield'    => "PT{$data['servings']}M",
			'nutrition'      => [
				'@type'    => 'NutritionInformation',
				'calories' => $data['calories'],
			],
		];

		if ( ! empty( $data['keywords'] ) ) {
			$keywords = array_map(
				function( $keyword ) {
					return $keyword['value'];
				},
				json_decode( $data['keywords'], true )
			);

			$schema['keywords'] = implode( ', ', $keywords );
		}

		if ( ! empty( $data['ingredients'] ) ) {
			$schema['recipeIngredient'] = array_map(
				function( $ingredient ) {
					return $ingredient['value'];
				},
				json_decode( $data['ingredients'], true )
			);
		}

		if ( ! empty( $data['instructions'] ) ) {
			$schema['recipeInstructions'] = [
				'@type'           => 'HowToSection',
				'itemListElement' => [],
			];

			foreach ( $data['instructions'] as $instruction ) {
				$instruction_data = json_decode( $instruction, true );

				$schema['recipeInstructions']['itemListElement'][] = [
					'@type' => 'HowtoStep',
					'text'  => $instruction_data['content'],
				];
			}
		}

		return $schema;
	}

	/**
	 * Set Keywords.
	 *
	 * @param int    $object_id   Object ID.
	 * @param array  $object      Object data.
	 * @param string $object_type Current Object type.
	 */
	private function set_keywords( $object_id, $object, $object_type ) {
		$keywords   = [];
		$keyphrases = json_decode( $object['keyphrases'], true );

		if ( ! empty( $keyphrases['focus']['keyphrase'] ) ) {
			$keywords[] = $keyphrases['focus']['keyphrase'];
		}

		if ( ! empty( $keyphrases['additional'] ) ) {
			foreach ( $keyphrases['additional'] as $keyword ) {
				$keywords[] = $keyword['keyphrase'];
			}
		}

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

		$this->update_meta( $object_type, $object_id, 'rank_math_focus_keyword', implode( ',', $keywords ) );
	}

	/**
	 * Set object robots meta.
	 *
	 * @param int    $object_id   Object ID.
	 * @param array  $object      Object data.
	 * @param string $object_type Current Object type.
	 */
	private function set_object_robots( $object_id, $object, $object_type ) {
		// Early bail if robots data is set in Rank Math plugin.
		if ( ! empty( $this->get_meta( $object_type, $object_id, 'rank_math_robots' ) ) || ! empty( $object['robots_default'] ) ) {
			return;
		}

		// ROBOTS.
		$robots = [];
		foreach ( [ 'robots_noindex', 'robots_noarchive', 'robots_nosnippet', 'robots_nofollow', 'robots_noimageindex' ] as $key ) {
			if ( empty( $object[ $key ] ) ) {
				continue;
			}

			$robots[] = str_replace( 'robots_', '', $key );
		}

		if ( ! in_array( 'noindex', $robots, true ) ) {
			$robots[] = 'index';
		}
		$this->update_meta( $object_type, $object_id, 'rank_math_robots', array_unique( $robots ) );

		$advanced_robots = [];
		$keys            = [
			'robots_max_snippet'      => 'max-snippet',
			'robots_max_videopreview' => 'max-video-preview',
			'robots_max_imagepreview' => 'max-image-preview',
		];
		foreach ( [ 'robots_max_snippet', 'robots_max_videopreview', 'robots_max_imagepreview' ] as $key ) {
			if ( empty( $object[ $key ] ) ) {
				continue;
			}

			$advanced_robots[ $keys[ $key ] ] = $object[ $key ];
		}

		$this->update_meta( $object_type, $object_id, 'rank_math_advanced_robots', array_unique( $advanced_robots ) );
	}

	/**
	 * Replace meta based on key/value hash.
	 *
	 * @param array  $hash        Array of hash for search and replace.
	 * @param array  $source      Array for source where to search.
	 * @param int    $object_id   Object id for destination where to save.
	 * @param string $object_type Object type for destination where to save.
	 * @param bool   $convert     (Optional) Conversion type. Default: false.
	 */
	protected function replace_meta( $hash, $source, $object_id, $object_type, $convert = false ) {
		foreach ( $hash as $search => $replace ) {
			$value = isset( $source[ $search ] ) ? $source[ $search ] : $this->get_meta( $object_type, $object_id, $search );
			if ( ! isset( $value ) ) {
				continue;
			}

			$this->update_meta(
				$object_type,
				$object_id,
				$replace,
				false !== $convert ? $this->$convert( $value ) : $value
			);
		}
	}

	/**
	 * Import Locations data from Yoast Local plugin.
	 *
	 * @return array
	 */
	protected function locations() {
		$this->import_locations_terms();
		$this->set_pagination( $this->get_location_ids( true ) );
		$locations = $this->get_location_ids();
		foreach ( $locations as $location ) {
			$args = (array) $location;
			unset( $args['ID'] );
			$args['post_type'] = 'rank_math_locations';

			$post_id = wp_insert_post( $args );
			if ( is_wp_error( $post_id ) ) {
				continue;
			}

			$post_terms = wp_get_object_terms( $location->ID, 'aioseo-location-category', [ 'fields' => 'slugs' ] );
			if ( ! empty( $post_terms ) && ! is_wp_error( $post_terms ) ) {
				wp_set_object_terms( $post_id, $post_terms, 'rank_math_location_category', false );
			}

			$this->locations_meta( $location->ID, $post_id );
		}

		return $this->get_pagination_arg();
	}

	/**
	 * Import Locations terms.
	 */
	private function import_locations_terms() {
		$terms = get_terms( 'aioseo-location-category' );
		if ( empty( $terms ) || is_wp_error( $terms ) ) {
			return;
		}

		foreach ( $terms as $term ) {
			wp_insert_term( $term->name, 'rank_math_location_category', $term );
		}
	}

	/**
	 * Import Locations metadata.
	 *
	 * @param int $old_post_id Yoast's location id.
	 * @param int $new_post_id Newly created location id.
	 */
	private function locations_meta( $old_post_id, $new_post_id ) {
		$metas = DB::query_builder( 'aioseo_posts' )->where( 'post_id', $old_post_id )->select()->one();
		if ( empty( $metas->local_seo ) ) {
			return;
		}

		$locations_data = json_decode( $metas->local_seo, true );
		$locations_meta = ! empty( $locations_data['locations'] ) ? $locations_data['locations']['business'] : [];
		$opening_hours  = ! empty( $locations_data['openingHours'] ) ? $locations_data['openingHours'] : [];

		$schema = [
			'metadata'   => [
				'type'           => 'template',
				'shortcode'      => uniqid( 's-' ),
				'isPrimary'      => true,
				'title'          => 'Local Business',
				'use_24h_format' => ! empty( $opening_hours['use24hFormat'] ),
				'open247'        => ! empty( $opening_hours['alwaysOpen'] ),
				'timeZone'       => ! empty( $opening_hours['timezone'] ),
			],
			'@type'      => $locations_meta['businessType'],
			'name'       => ! empty( $locations_meta['name'] ) ? $locations_meta['name'] : '%seo_title%',
			'url'        => ! empty( $locations_meta['urls'] ) ? $locations_meta['urls']['website'] : '%url%',
			'address'    => ! empty( $locations_meta['address'] ) ? $this->replace_address( $locations_meta['address'] ) : '',
			'areaServed' => ! empty( $locations_meta['areaServed'] ) ? $locations_meta['areaServed'] : '',
		];

		if ( ! empty( $locations_meta['contact'] ) ) {
			$contact             = $locations_meta['contact'];
			$schema['email']     = ! empty( $contact['email'] ) ? $contact['email'] : '';
			$schema['telephone'] = ! empty( $contact['phone'] ) ? $contact['phone'] : '';
			$schema['faxNumber'] = ! empty( $contact['fax'] ) ? $contact['fax'] : '';
		}

		if ( ! empty( $locations_meta['ids'] ) ) {
			$ids             = $locations_meta['ids'];
			$schema['vatID'] = ! empty( $ids['vat'] ) ? $ids['vat'] : '';
			$schema['taxID'] = ! empty( $ids['tax'] ) ? $ids['tax'] : '';
		}

		if ( ! empty( $locations_meta['payment'] ) ) {
			$payment                   = $locations_meta['payment'];
			$schema['priceRange']      = ! empty( $payment['priceRange'] ) ? $payment['priceRange'] : '';
			$schema['paymentAccepted'] = ! empty( $payment['methods'] ) ? $payment['methods'] : '';

			if ( ! empty( $payment['currenciesAccepted'] ) ) {
				$schema['currenciesAccepted'] = implode(
					', ',
					array_map(
						function( $value ) {
							return $value['value'];
						},
						json_decode( $payment['currenciesAccepted'], true )
					)
				);
			}
		}

		if ( ! empty( $locations_meta['image'] ) ) {
			$schema['logo'] = [
				'@type' => 'ImageObject',
				'url'   => $locations_meta['image'],
			];
		}

		$schema['openingHoursSpecification'] = $this->replace_opening_hours( $opening_hours['days'] );

		update_post_meta( $new_post_id, 'rank_math_schema_' . $schema['@type'], $schema );
	}

	/**
	 * Replace Opening Hours data.
	 *
	 * @param array $opening_hours Opening Hours data.
	 * @return array Processed data.
	 */
	private function replace_opening_hours( $opening_hours ) {
		$data = [];
		$days = [ 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday' ];
		foreach ( $days as $day ) {
			if ( ! empty( $opening_hours[ $day ]['closed'] ) ) {
				continue;
			}

			if ( ! empty( $opening_hours[ $day ]['open24h'] ) ) {
				$opens  = '00:00';
				$closes = '23:59';
			} else {
				$opens  = ! empty( $opening_hours[ $day ]['openTime'] ) ? $opening_hours[ $day ]['openTime'] : '';
				$closes = ! empty( $opening_hours[ $day ]['closeTime'] ) ? $opening_hours[ $day ]['closeTime'] : '';
			}

			if ( ! $opens ) {
				continue;
			}

			$data[ $day ] = [
				'@type'     => 'OpeningHoursSpecification',
				'dayOfWeek' => ucfirst( $day ),
				'opens'     => $opens,
				'closes'    => $closes,
			];
		}

		return array_values( $data );
	}

	/**
	 * Replace Address data.
	 *
	 * @param array $address Address data.
	 * @return array Processed data.
	 */
	private function replace_address( $address ) {
		$data = [
			'@type' => 'PostalAddress',
		];
		$hash = [
			'streetLine1' => 'streetAddress',
			'streetLine2' => 'addressLocality',
			'state'       => 'addressRegion',
			'zipCode'     => 'postalCode',
			'country'     => 'addressCountry',
		];

		foreach ( $hash as $key => $value ) {
			$data[ $value ] = isset( $address[ $key ] ) ? $address[ $key ] : '';
		}

		if ( ! empty( $address['city'] ) ) {
			$data['addressLocality'] = $data['addressLocality'] . ', ' . $address['city'];
		}

		return $data;
	}

	/**
	 * Get all location IDs.
	 *
	 * @param bool $count If we need count only for pagination purposes.
	 * @return int|array
	 */
	private function get_location_ids( $count = false ) {
		$paged = $this->get_pagination_arg( 'page' );
		$table = DB::query_builder( 'posts' )->where( 'post_type', 'aioseo-location' );

		return $count ? absint( $table->selectCount( 'ID', 'total' )->getVar() ) :
			$table->select()->page( $paged - 1, $this->items_per_page )->get();
	}
}
