This commit is contained in:
2024-05-20 15:37:46 +03:00
commit 00b7dbd0b7
10404 changed files with 3285853 additions and 0 deletions

View File

@ -0,0 +1,34 @@
<?php
/**
* WPSEO plugin file.
*
* @package WPSEO\Admin\Import\Plugins
*/
/**
* Class WPSEO_Import_Plugins_Detector.
*
* Class with functionality to detect whether we should import from another SEO plugin.
*/
class WPSEO_Import_Plugins_Detector {
/**
* Plugins we need to import from.
*
* @var array
*/
public $needs_import = [];
/**
* Detects whether we need to import anything.
*/
public function detect() {
foreach ( WPSEO_Plugin_Importers::get() as $importer_class ) {
$importer = new $importer_class();
$detect = new WPSEO_Import_Plugin( $importer, 'detect' );
if ( $detect->status->status ) {
$this->needs_import[ $importer_class ] = $importer->get_plugin_name();
}
}
}
}

View File

@ -0,0 +1,63 @@
<?php
/**
* WPSEO plugin file.
*
* @package WPSEO\Admin\Import\Plugins
*/
/**
* Class WPSEO_Import_Plugin.
*
* Class with functionality to import Yoast SEO settings from other plugins.
*/
class WPSEO_Import_Plugin {
/**
* Holds the status of and message about imports.
*
* @var WPSEO_Import_Status
*/
public $status;
/**
* Class with functionality to import meta data from other plugins.
*
* @var WPSEO_Plugin_Importer
*/
protected $importer;
/**
* Import class constructor.
*
* @param WPSEO_Plugin_Importer $importer The importer that needs to perform this action.
* @param string $action The action to perform.
*/
public function __construct( WPSEO_Plugin_Importer $importer, $action ) {
$this->importer = $importer;
switch ( $action ) {
case 'cleanup':
$this->status = $this->importer->run_cleanup();
break;
case 'import':
$this->status = $this->importer->run_import();
break;
case 'detect':
default:
$this->status = $this->importer->run_detect();
}
$this->status->set_msg( $this->complete_msg( $this->status->get_msg() ) );
}
/**
* Convenience function to replace %s with plugin name in import message.
*
* @param string $msg Message string.
*
* @return string Returns message with plugin name instead of replacement variables.
*/
protected function complete_msg( $msg ) {
return sprintf( $msg, $this->importer->get_plugin_name() );
}
}

View File

@ -0,0 +1,123 @@
<?php
/**
* WPSEO plugin file.
*
* @package WPSEO\Admin\Import
*/
/**
* Class WPSEO_Import_Settings.
*
* Class with functionality to import the Yoast SEO settings.
*/
class WPSEO_Import_Settings {
/**
* Nonce action key.
*
* @var string
*/
const NONCE_ACTION = 'wpseo-import-settings';
/**
* Holds the import status instance.
*
* @var WPSEO_Import_Status
*/
public $status;
/**
* Holds the old WPSEO version.
*
* @var string
*/
private $old_wpseo_version;
/**
* Class constructor.
*/
public function __construct() {
$this->status = new WPSEO_Import_Status( 'import', false );
}
/**
* Imports the data submitted by the user.
*
* @return void
*/
public function import() {
check_admin_referer( self::NONCE_ACTION );
if ( ! WPSEO_Capability_Utils::current_user_can( 'wpseo_manage_options' ) ) {
return;
}
if ( ! isset( $_POST['settings_import'] ) || ! is_string( $_POST['settings_import'] ) ) {
return;
}
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Reason: The raw content will be parsed afterwards.
$content = wp_unslash( $_POST['settings_import'] );
if ( empty( $content ) ) {
return;
}
$this->parse_options( $content );
}
/**
* Parse the options.
*
* @param string $raw_options The content to parse.
*
* @return void
*/
protected function parse_options( $raw_options ) {
$options = parse_ini_string( $raw_options, true, INI_SCANNER_RAW );
if ( is_array( $options ) && $options !== [] ) {
$this->import_options( $options );
return;
}
$this->status->set_msg( __( 'Settings could not be imported:', 'wordpress-seo' ) . ' ' . __( 'No settings found.', 'wordpress-seo' ) );
}
/**
* Parse the option group and import it.
*
* @param string $name Name string.
* @param array $option_group Option group data.
* @param array $options Options data.
*/
protected function parse_option_group( $name, $option_group, $options ) {
// Make sure that the imported options are cleaned/converted on import.
$option_instance = WPSEO_Options::get_option_instance( $name );
if ( is_object( $option_instance ) && method_exists( $option_instance, 'import' ) ) {
$option_instance->import( $option_group, $this->old_wpseo_version, $options );
}
}
/**
* Imports the options if found.
*
* @param array $options The options parsed from the provided settings.
*/
protected function import_options( $options ) {
if ( isset( $options['wpseo']['version'] ) && $options['wpseo']['version'] !== '' ) {
$this->old_wpseo_version = $options['wpseo']['version'];
}
foreach ( $options as $name => $option_group ) {
$this->parse_option_group( $name, $option_group, $options );
}
$this->status->set_msg( __( 'Settings successfully imported.', 'wordpress-seo' ) );
$this->status->set_status( true );
// Reset the cached option values.
WPSEO_Options::clear_cache();
}
}

View File

@ -0,0 +1,131 @@
<?php
/**
* WPSEO plugin file.
*
* @package WPSEO\Admin\Import
*/
/**
* Class WPSEO_ImportStatus.
*
* Holds the status of and message about imports.
*/
class WPSEO_Import_Status {
/**
* The import status.
*
* @var bool
*/
public $status = false;
/**
* The import message.
*
* @var string
*/
private $msg = '';
/**
* The type of action performed.
*
* @var string
*/
private $action;
/**
* WPSEO_Import_Status constructor.
*
* @param string $action The type of import action.
* @param bool $status The status of the import.
* @param string $msg Extra messages about the status.
*/
public function __construct( $action, $status, $msg = '' ) {
$this->action = $action;
$this->status = $status;
$this->msg = $msg;
}
/**
* Get the import message.
*
* @return string Message about current status.
*/
public function get_msg() {
if ( $this->msg !== '' ) {
return $this->msg;
}
if ( $this->status === false ) {
/* translators: %s is replaced with the name of the plugin we're trying to find data from. */
return __( '%s data not found.', 'wordpress-seo' );
}
return $this->get_default_success_message();
}
/**
* Get the import action.
*
* @return string Import action type.
*/
public function get_action() {
return $this->action;
}
/**
* Set the import action, set status to false.
*
* @param string $action The type of action to set as import action.
*
* @return void
*/
public function set_action( $action ) {
$this->action = $action;
$this->status = false;
}
/**
* Sets the importer status message.
*
* @param string $msg The message to set.
*
* @return void
*/
public function set_msg( $msg ) {
$this->msg = $msg;
}
/**
* Sets the importer status.
*
* @param bool $status The status to set.
*
* @return WPSEO_Import_Status The current object.
*/
public function set_status( $status ) {
$this->status = (bool) $status;
return $this;
}
/**
* Returns a success message depending on the action.
*
* @return string Returns a success message for the current action.
*/
private function get_default_success_message() {
switch ( $this->action ) {
case 'import':
/* translators: %s is replaced with the name of the plugin we're importing data from. */
return __( '%s data successfully imported.', 'wordpress-seo' );
case 'cleanup':
/* translators: %s is replaced with the name of the plugin we're removing data from. */
return __( '%s data successfully removed.', 'wordpress-seo' );
case 'detect':
default:
/* translators: %s is replaced with the name of the plugin we've found data from. */
return __( '%s data found.', 'wordpress-seo' );
}
}
}

View File

@ -0,0 +1,325 @@
<?php
/**
* This file holds the abstract class for dealing with imports from other plugins.
*
* @package WPSEO\Admin\Import\Plugins
*/
/**
* Class WPSEO_Plugin_Importer.
*
* Class with functionality to import meta data from other plugins.
*/
abstract class WPSEO_Plugin_Importer {
/**
* Holds the import status object.
*
* @var WPSEO_Import_Status
*/
protected $status;
/**
* The plugin name.
*
* @var string
*/
protected $plugin_name;
/**
* Meta key, used in SQL LIKE clause for delete query.
*
* @var string
*/
protected $meta_key;
/**
* Array of meta keys to detect and import.
*
* @var array
*/
protected $clone_keys;
/**
* Class constructor.
*/
public function __construct() {}
/**
* Returns the string for the plugin we're importing from.
*
* @return string Plugin name.
*/
public function get_plugin_name() {
return $this->plugin_name;
}
/**
* Imports the settings and post meta data from another SEO plugin.
*
* @return WPSEO_Import_Status Import status object.
*/
public function run_import() {
$this->status = new WPSEO_Import_Status( 'import', false );
if ( ! $this->detect() ) {
return $this->status;
}
$this->status->set_status( $this->import() );
// Flush the entire cache, as we no longer know what's valid and what's not.
wp_cache_flush();
return $this->status;
}
/**
* Handles post meta data to import.
*
* @return bool Import success status.
*/
protected function import() {
return $this->meta_keys_clone( $this->clone_keys );
}
/**
* Removes the plugin data from the database.
*
* @return WPSEO_Import_Status Import status object.
*/
public function run_cleanup() {
$this->status = new WPSEO_Import_Status( 'cleanup', false );
if ( ! $this->detect() ) {
return $this->status;
}
return $this->status->set_status( $this->cleanup() );
}
/**
* Removes the plugin data from the database.
*
* @return bool Cleanup status.
*/
protected function cleanup() {
global $wpdb;
if ( empty( $this->meta_key ) ) {
return true;
}
$wpdb->query(
$wpdb->prepare(
"DELETE FROM {$wpdb->postmeta} WHERE meta_key LIKE %s",
$this->meta_key
)
);
$result = $wpdb->__get( 'result' );
if ( ! $result ) {
$this->cleanup_error_msg();
}
return $result;
}
/**
* Sets the status message for when a cleanup has gone bad.
*
* @return void
*/
protected function cleanup_error_msg() {
/* translators: %s is replaced with the plugin's name. */
$this->status->set_msg( sprintf( __( 'Cleanup of %s data failed.', 'wordpress-seo' ), $this->plugin_name ) );
}
/**
* Detects whether an import for this plugin is needed.
*
* @return WPSEO_Import_Status Import status object.
*/
public function run_detect() {
$this->status = new WPSEO_Import_Status( 'detect', false );
if ( ! $this->detect() ) {
return $this->status;
}
return $this->status->set_status( true );
}
/**
* Detects whether there is post meta data to import.
*
* @return bool Boolean indicating whether there is something to import.
*/
protected function detect() {
global $wpdb;
$meta_keys = wp_list_pluck( $this->clone_keys, 'old_key' );
$result = $wpdb->get_var(
$wpdb->prepare(
"SELECT COUNT(*) AS `count`
FROM {$wpdb->postmeta}
WHERE meta_key IN ( " . implode( ', ', array_fill( 0, count( $meta_keys ), '%s' ) ) . ' )',
$meta_keys
)
);
if ( $result === '0' ) {
return false;
}
return true;
}
/**
* Helper function to clone meta keys and (optionally) change their values in bulk.
*
* @param string $old_key The existing meta key.
* @param string $new_key The new meta key.
* @param array $replace_values An array, keys old value, values new values.
*
* @return bool Clone status.
*/
protected function meta_key_clone( $old_key, $new_key, $replace_values = [] ) {
global $wpdb;
// First we create a temp table with all the values for meta_key.
$result = $wpdb->query(
$wpdb->prepare(
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.SchemaChange -- This is intentional + temporary.
"CREATE TEMPORARY TABLE tmp_meta_table SELECT * FROM {$wpdb->postmeta} WHERE meta_key = %s",
$old_key
)
);
if ( $result === false ) {
$this->set_missing_db_rights_status();
return false;
}
// Delete all the values in our temp table for posts that already have data for $new_key.
$wpdb->query(
$wpdb->prepare(
"DELETE FROM tmp_meta_table WHERE post_id IN ( SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = %s )",
WPSEO_Meta::$meta_prefix . $new_key
)
);
/*
* We set meta_id to NULL so on re-insert into the postmeta table, MYSQL can set
* new meta_id's and we don't get duplicates.
*/
$wpdb->query( 'UPDATE tmp_meta_table SET meta_id = NULL' );
// Now we rename the meta_key.
$wpdb->query(
$wpdb->prepare(
'UPDATE tmp_meta_table SET meta_key = %s',
WPSEO_Meta::$meta_prefix . $new_key
)
);
$this->meta_key_clone_replace( $replace_values );
// With everything done, we insert all our newly cloned lines into the postmeta table.
$wpdb->query( "INSERT INTO {$wpdb->postmeta} SELECT * FROM tmp_meta_table" );
// Now we drop our temporary table.
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.SchemaChange -- This is intentional + a temporary table.
$wpdb->query( 'DROP TEMPORARY TABLE IF EXISTS tmp_meta_table' );
return true;
}
/**
* Clones multiple meta keys.
*
* @param array $clone_keys The keys to clone.
*
* @return bool Success status.
*/
protected function meta_keys_clone( $clone_keys ) {
foreach ( $clone_keys as $clone_key ) {
$result = $this->meta_key_clone( $clone_key['old_key'], $clone_key['new_key'], isset( $clone_key['convert'] ) ? $clone_key['convert'] : [] );
if ( ! $result ) {
return false;
}
}
return true;
}
/**
* Sets the import status to false and returns a message about why it failed.
*/
protected function set_missing_db_rights_status() {
$this->status->set_status( false );
/* translators: %s is replaced with Yoast SEO. */
$this->status->set_msg( sprintf( __( 'The %s importer functionality uses temporary database tables. It seems your WordPress install does not have the capability to do this, please consult your hosting provider.', 'wordpress-seo' ), 'Yoast SEO' ) );
}
/**
* Helper function to search for a key in an array and maybe save it as a meta field.
*
* @param string $plugin_key The key in the $data array to check.
* @param string $yoast_key The identifier we use in our meta settings.
* @param array $data The array of data for this post to sift through.
* @param int $post_id The post ID.
*
* @return void
*/
protected function import_meta_helper( $plugin_key, $yoast_key, $data, $post_id ) {
if ( ! empty( $data[ $plugin_key ] ) ) {
$this->maybe_save_post_meta( $yoast_key, $data[ $plugin_key ], $post_id );
}
}
/**
* Saves a post meta value if it doesn't already exist.
*
* @param string $new_key The key to save.
* @param mixed $value The value to set the key to.
* @param int $post_id The Post to save the meta for.
*/
protected function maybe_save_post_meta( $new_key, $value, $post_id ) {
// Big. Fat. Sigh. Mostly used for _yst_is_cornerstone, but might be useful for other hidden meta's.
$key = WPSEO_Meta::$meta_prefix . $new_key;
$wpseo_meta = true;
if ( substr( $new_key, 0, 1 ) === '_' ) {
$key = $new_key;
$wpseo_meta = false;
}
$existing_value = get_post_meta( $post_id, $key, true );
if ( empty( $existing_value ) ) {
if ( $wpseo_meta ) {
WPSEO_Meta::set_value( $new_key, $value, $post_id );
return;
}
update_post_meta( $post_id, $new_key, $value );
}
}
/**
* Replaces values in our temporary table according to our settings.
*
* @param array $replace_values Key value pair of values to replace with other values.
*
* @return void
*/
protected function meta_key_clone_replace( $replace_values ) {
global $wpdb;
// Now we replace values if needed.
if ( is_array( $replace_values ) && $replace_values !== [] ) {
foreach ( $replace_values as $old_value => $new_value ) {
$wpdb->query(
$wpdb->prepare(
'UPDATE tmp_meta_table SET meta_value = %s WHERE meta_value = %s',
$new_value,
$old_value
)
);
}
}
}
}

View File

@ -0,0 +1,239 @@
<?php
/**
* File with the class to handle data from All in One SEO Pack, versions 4 and up.
*
* @package WPSEO\Admin\Import\Plugins
*/
use Yoast\WP\SEO\Actions\Importing\Aioseo\Aioseo_Cleanup_Action;
use Yoast\WP\SEO\Actions\Importing\Aioseo\Aioseo_Posts_Importing_Action;
/**
* Class with functionality to import & clean All in One SEO Pack post metadata, versions 4 and up.
*/
class WPSEO_Import_AIOSEO_V4 extends WPSEO_Plugin_Importer {
/**
* The plugin name.
*
* @var string
*/
protected $plugin_name = 'All In One SEO Pack';
/**
* Meta key, used in SQL LIKE clause for delete query.
*
* @var string
*/
protected $meta_key = '_aioseo_%';
/**
* Array of meta keys to detect and import.
*
* @var array
*/
protected $clone_keys = [
[
'old_key' => '_aioseo_title',
'new_key' => 'title',
],
[
'old_key' => '_aioseo_description',
'new_key' => 'metadesc',
],
[
'old_key' => '_aioseo_og_title',
'new_key' => 'opengraph-title',
],
[
'old_key' => '_aioseo_og_description',
'new_key' => 'opengraph-description',
],
[
'old_key' => '_aioseo_twitter_title',
'new_key' => 'twitter-title',
],
[
'old_key' => '_aioseo_twitter_description',
'new_key' => 'twitter-description',
],
];
/**
* Mapping between the AiOSEO replace vars and the Yoast replace vars.
*
* @var array
*
* @see https://yoast.com/help/list-available-snippet-variables-yoast-seo/
*/
protected $replace_vars = [
// They key is the AiOSEO replace var, the value is the Yoast replace var (see class-wpseo-replace-vars).
'#author_first_name' => '%%author_first_name%%',
'#author_last_name' => '%%author_last_name%%',
'#author_name' => '%%name%%',
'#categories' => '%%category%%',
'#current_date' => '%%currentdate%%',
'#current_day' => '%%currentday%%',
'#current_month' => '%%currentmonth%%',
'#current_year' => '%%currentyear%%',
'#permalink' => '%%permalink%%',
'#post_content' => '%%post_content%%',
'#post_date' => '%%date%%',
'#post_day' => '%%post_day%%',
'#post_month' => '%%post_month%%',
'#post_title' => '%%title%%',
'#post_year' => '%%post_year%%',
'#post_excerpt_only' => '%%excerpt_only%%',
'#post_excerpt' => '%%excerpt%%',
'#separator_sa' => '%%sep%%',
'#site_title' => '%%sitename%%',
'#tagline' => '%%sitedesc%%',
'#taxonomy_title' => '%%category_title%%',
];
/**
* Replaces the AiOSEO variables in our temporary table with Yoast variables (replace vars).
*
* @param array $replace_values Key value pair of values to replace with other values. This is only used in the base class but not here.
* That is because this class doesn't have any `convert` keys in `$clone_keys`.
* For that reason, we're overwriting the base class' `meta_key_clone_replace()` function without executing that base functionality.
*
* @return void
*/
protected function meta_key_clone_replace( $replace_values ) {
global $wpdb;
// At this point we're already looping through all the $clone_keys (this happens in meta_keys_clone() in the abstract class).
// Now, we'll also loop through the replace_vars array, which holds the mappings between the AiOSEO variables and the Yoast variables.
// We'll replace all the AiOSEO variables in the temporary table with their Yoast equivalents.
foreach ( $this->replace_vars as $aioseo_variable => $yoast_variable ) {
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Reason: We need this query and this is done at many other places as well, for example class-import-rankmath.
$wpdb->query(
$wpdb->prepare(
'UPDATE tmp_meta_table SET meta_value = REPLACE( meta_value, %s, %s )',
$aioseo_variable,
$yoast_variable
)
);
}
// The AiOSEO custom fields take the form of `#custom_field-myfield`.
// These should be mapped to %%cf_myfield%%.
$meta_values_with_custom_fields = $this->get_meta_values_with_custom_field_or_taxonomy( $wpdb, 'custom_field' );
$unique_custom_fields = $this->get_unique_custom_fields_or_taxonomies( $meta_values_with_custom_fields, 'custom_field' );
$this->replace_custom_field_or_taxonomy_replace_vars( $unique_custom_fields, $wpdb, 'custom_field', 'cf' );
// Map `#tax_name-{tax-slug}` to `%%ct_{tax-slug}%%``.
$meta_values_with_custom_taxonomies = $this->get_meta_values_with_custom_field_or_taxonomy( $wpdb, 'tax_name' );
$unique_custom_taxonomies = $this->get_unique_custom_fields_or_taxonomies( $meta_values_with_custom_taxonomies, 'tax_name' );
$this->replace_custom_field_or_taxonomy_replace_vars( $unique_custom_taxonomies, $wpdb, 'tax_name', 'ct' );
}
/**
* Filters out all unique custom fields/taxonomies/etc. used in an AiOSEO replace var.
*
* @param string[] $meta_values An array of all the meta values that
* contain one or more AIOSEO custom field replace vars
* (in the form `#custom_field-xyz`).
* @param string $aioseo_prefix The AiOSEO prefix to use
* (e.g. `custom-field` for custom fields or `tax_name` for custom taxonomies).
*
* @return string[] An array of all the unique custom fields/taxonomies/etc. used in the replace vars.
* E.g. `xyz` in the above example.
*/
protected function get_unique_custom_fields_or_taxonomies( $meta_values, $aioseo_prefix ) {
$unique_custom_fields_or_taxonomies = [];
foreach ( $meta_values as $meta_value ) {
// Find all custom field replace vars, store them in `$matches`.
\preg_match_all(
"/#$aioseo_prefix-([\w-]+)/",
$meta_value,
$matches
);
/*
* `$matches[1]` contain the captured matches of the
* first capturing group (the `([\w-]+)` in the regex above).
*/
$custom_fields_or_taxonomies = $matches[1];
foreach ( $custom_fields_or_taxonomies as $custom_field_or_taxonomy ) {
$unique_custom_fields_or_taxonomies[ \trim( $custom_field_or_taxonomy ) ] = 1;
}
}
return \array_keys( $unique_custom_fields_or_taxonomies );
}
/**
* Replaces every AIOSEO custom field/taxonomy/etc. replace var with the Yoast version.
*
* E.g. `#custom_field-xyz` becomes `%%cf_xyz%%`.
*
* @param string[] $unique_custom_fields_or_taxonomies An array of unique custom fields to replace the replace vars of.
* @param wpdb $wpdb The WordPress database object.
* @param string $aioseo_prefix The AiOSEO prefix to use
* (e.g. `custom-field` for custom fields or `tax_name` for custom taxonomies).
* @param string $yoast_prefix The Yoast prefix to use (e.g. `cf` for custom fields).
*/
protected function replace_custom_field_or_taxonomy_replace_vars( $unique_custom_fields_or_taxonomies, $wpdb, $aioseo_prefix, $yoast_prefix ) {
foreach ( $unique_custom_fields_or_taxonomies as $unique_custom_field_or_taxonomy ) {
$aioseo_variable = "#{$aioseo_prefix}-{$unique_custom_field_or_taxonomy}";
$yoast_variable = "%%{$yoast_prefix}_{$unique_custom_field_or_taxonomy}%%";
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$wpdb->query(
$wpdb->prepare(
'UPDATE tmp_meta_table SET meta_value = REPLACE( meta_value, %s, %s )',
$aioseo_variable,
$yoast_variable
)
);
}
}
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
/**
* Retrieve all the meta values from the temporary meta table that contain
* at least one AiOSEO custom field replace var.
*
* @param wpdb $wpdb The WordPress database object.
* @param string $aioseo_prefix The AiOSEO prefix to use
* (e.g. `custom-field` for custom fields or `tax_name` for custom taxonomies).
*
* @return string[] All meta values that contain at least one AioSEO custom field replace var.
*/
protected function get_meta_values_with_custom_field_or_taxonomy( $wpdb, $aioseo_prefix ) {
return $wpdb->get_col(
$wpdb->prepare(
'SELECT meta_value FROM tmp_meta_table WHERE meta_value LIKE %s',
"%#$aioseo_prefix-%"
)
);
}
// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
/**
* Detects whether there is AIOSEO data to import by looking whether the AIOSEO data have been cleaned up.
*
* @return bool Boolean indicating whether there is something to import.
*/
protected function detect() {
$aioseo_cleanup_action = YoastSEO()->classes->get( Aioseo_Cleanup_Action::class );
return ( $aioseo_cleanup_action->get_total_unindexed() > 0 );
}
/**
* Import AIOSEO post data from their custom indexable table. Not currently used.
*
* @return void
*/
protected function import() {
// This is overriden from the import.js and never run.
$aioseo_posts_import_action = YoastSEO()->classes->get( Aioseo_Posts_Importing_Action::class );
$aioseo_posts_import_action->index();
}
}

View File

@ -0,0 +1,108 @@
<?php
/**
* File with the class to handle data from All in One SEO Pack, versions 3 and under.
*
* @package WPSEO\Admin\Import\Plugins
*/
/**
* Class with functionality to import & clean All in One SEO Pack post metadata, versions 3 and under.
*/
class WPSEO_Import_AIOSEO extends WPSEO_Plugin_Importer {
/**
* The plugin name.
*
* @var string
*/
protected $plugin_name = 'All In One SEO Pack';
/**
* Meta key, used in SQL LIKE clause for delete query.
*
* @var string
*/
protected $meta_key = '_aioseop_%';
/**
* OpenGraph keys to import.
*
* @var array
*/
protected $import_keys = [
'aioseop_opengraph_settings_title' => 'opengraph-title',
'aioseop_opengraph_settings_desc' => 'opengraph-description',
'aioseop_opengraph_settings_customimg' => 'opengraph-image',
'aioseop_opengraph_settings_customimg_twitter' => 'twitter-image',
];
/**
* Array of meta keys to detect and import.
*
* @var array
*/
protected $clone_keys = [
[
'old_key' => '_aioseop_title',
'new_key' => 'title',
],
[
'old_key' => '_aioseop_description',
'new_key' => 'metadesc',
],
[
'old_key' => '_aioseop_noindex',
'new_key' => 'meta-robots-noindex',
'convert' => [ 'on' => 1 ],
],
[
'old_key' => '_aioseop_nofollow',
'new_key' => 'meta-robots-nofollow',
'convert' => [ 'on' => 1 ],
],
];
/**
* Import All In One SEO meta values.
*
* @return bool Import success status.
*/
protected function import() {
$status = parent::import();
if ( $status ) {
$this->import_opengraph();
}
return $status;
}
/**
* Imports the OpenGraph and Twitter settings for all posts.
*
* @return bool
*/
protected function import_opengraph() {
$query_posts = new WP_Query( 'post_type=any&meta_key=_aioseop_opengraph_settings&order=ASC&fields=ids&nopaging=true' );
if ( ! empty( $query_posts->posts ) ) {
foreach ( array_values( $query_posts->posts ) as $post_id ) {
$this->import_post_opengraph( $post_id );
}
}
return true;
}
/**
* Imports the OpenGraph and Twitter settings for a single post.
*
* @param int $post_id Post ID.
*/
private function import_post_opengraph( $post_id ) {
$meta = get_post_meta( $post_id, '_aioseop_opengraph_settings', true );
$meta = maybe_unserialize( $meta );
foreach ( $this->import_keys as $old_key => $new_key ) {
$this->maybe_save_post_meta( $new_key, $meta[ $old_key ], $post_id );
}
}
}

View File

@ -0,0 +1,42 @@
<?php
/**
* File with the class to handle data from Ultimate SEO.
*
* @package WPSEO\Admin\Import\Plugins
*/
/**
* Class with functionality to import & clean Ultimate SEO post metadata.
*/
class WPSEO_Import_Greg_SEO extends WPSEO_Plugin_Importer {
/**
* The plugin name.
*
* @var string
*/
protected $plugin_name = "Greg's High Performance SEO";
/**
* Meta key, used in SQL LIKE clause for delete query.
*
* @var string
*/
protected $meta_key = '_ghpseo_%';
/**
* Array of meta keys to detect and import.
*
* @var array
*/
protected $clone_keys = [
[
'old_key' => '_ghpseo_alternative_description',
'new_key' => 'metadesc',
],
[
'old_key' => '_ghpseo_secondary_title',
'new_key' => 'title',
],
];
}

View File

@ -0,0 +1,54 @@
<?php
/**
* File with the class to handle data from HeadSpace.
*
* @package WPSEO\Admin\Import\Plugins
*/
/**
* Class WPSEO_Import_HeadSpace.
*
* Class with functionality to import & clean HeadSpace SEO post metadata.
*/
class WPSEO_Import_HeadSpace extends WPSEO_Plugin_Importer {
/**
* The plugin name.
*
* @var string
*/
protected $plugin_name = 'HeadSpace SEO';
/**
* Meta key, used in SQL LIKE clause for delete query.
*
* @var string
*/
protected $meta_key = '_headspace_%';
/**
* Array of meta keys to detect and import.
*
* @var array
*/
protected $clone_keys = [
[
'old_key' => '_headspace_description',
'new_key' => 'metadesc',
],
[
'old_key' => '_headspace_page_title',
'new_key' => 'title',
],
[
'old_key' => '_headspace_noindex',
'new_key' => 'meta-robots-noindex',
'convert' => [ 'on' => 1 ],
],
[
'old_key' => '_headspace_nofollow',
'new_key' => 'meta-robots-nofollow',
'convert' => [ 'on' => 1 ],
],
];
}

View File

@ -0,0 +1,40 @@
<?php
/**
* File with the class to handle data from Jetpack's Advanced SEO settings.
*
* @package WPSEO\Admin\Import\Plugins
*/
/**
* Class WPSEO_Import_Jetpack_SEO.
*
* Class with functionality to import & clean Jetpack SEO post metadata.
*/
class WPSEO_Import_Jetpack_SEO extends WPSEO_Plugin_Importer {
/**
* The plugin name.
*
* @var string
*/
protected $plugin_name = 'Jetpack';
/**
* Meta key, used in SQL LIKE clause for delete query.
*
* @var string
*/
protected $meta_key = 'advanced_seo_description';
/**
* Array of meta keys to detect and import.
*
* @var array
*/
protected $clone_keys = [
[
'old_key' => 'advanced_seo_description',
'new_key' => 'metadesc',
],
];
}

View File

@ -0,0 +1,138 @@
<?php
/**
* File with the class to handle data from Platinum SEO Pack.
*
* @package WPSEO\Admin\Import\Plugins
*/
/**
* Class with functionality to import & clean Ultimate SEO post metadata.
*/
class WPSEO_Import_Platinum_SEO extends WPSEO_Plugin_Importer {
/**
* The plugin name.
*
* @var string
*/
protected $plugin_name = 'Platinum SEO Pack';
/**
* Meta key, used in SQL LIKE clause for delete query.
*
* @var string
*/
protected $meta_key = 'title';
/**
* Array of meta keys to detect and import.
*
* @var array
*/
protected $clone_keys = [
[
'old_key' => 'description',
'new_key' => 'metadesc',
],
[
'old_key' => 'title',
'new_key' => 'title',
],
];
/**
* Runs the import of post meta keys stored by Platinum SEO Pack.
*
* @return bool
*/
protected function import() {
$return = parent::import();
if ( $return ) {
$this->import_robots_meta();
}
return $return;
}
/**
* Cleans up all the meta values Platinum SEO pack creates.
*
* @return bool
*/
protected function cleanup() {
$this->meta_key = 'title';
parent::cleanup();
$this->meta_key = 'description';
parent::cleanup();
$this->meta_key = 'metarobots';
parent::cleanup();
return true;
}
/**
* Finds all the robotsmeta fields to import and deals with them.
*
* There are four potential values that Platinum SEO stores:
* - index,folllow
* - index,nofollow
* - noindex,follow
* - noindex,nofollow
*
* We only have to deal with the latter 3, the first is our default.
*
* @return void
*/
protected function import_robots_meta() {
$this->import_by_meta_robots( 'index,nofollow', [ 'nofollow' ] );
$this->import_by_meta_robots( 'noindex,follow', [ 'noindex' ] );
$this->import_by_meta_robots( 'noindex,nofollow', [ 'noindex', 'nofollow' ] );
}
/**
* Imports the values for all index, nofollow posts.
*
* @param string $value The meta robots value to find posts for.
* @param array $metas The meta field(s) to save.
*
* @return void
*/
protected function import_by_meta_robots( $value, $metas ) {
$posts = $this->find_posts_by_robots_meta( $value );
if ( ! $posts ) {
return;
}
foreach ( $posts as $post_id ) {
foreach ( $metas as $meta ) {
$this->maybe_save_post_meta( 'meta-robots-' . $meta, 1, $post_id );
}
}
}
/**
* Finds posts by a given meta robots value.
*
* @param string $meta_value Robots meta value.
*
* @return array|bool Array of Post IDs on success, false on failure.
*/
protected function find_posts_by_robots_meta( $meta_value ) {
$posts = get_posts(
[
'post_type' => 'any',
'meta_key' => 'robotsmeta',
'meta_value' => $meta_value,
'order' => 'ASC',
'fields' => 'ids',
'nopaging' => true,
]
);
if ( empty( $posts ) ) {
return false;
}
return $posts;
}
}

View File

@ -0,0 +1,39 @@
<?php
/**
* File with the class to handle data from Premium SEO Pack.
*
* @package WPSEO\Admin\Import\Plugins
*/
/**
* Class with functionality to import & clean Premium SEO Pack post metadata.
*/
class WPSEO_Import_Premium_SEO_Pack extends WPSEO_Import_Squirrly {
/**
* The plugin name.
*
* @var string
*/
protected $plugin_name = 'Premium SEO Pack';
/**
* WPSEO_Import_Premium_SEO_Pack constructor.
*/
public function __construct() {
parent::__construct();
global $wpdb;
$this->table_name = $wpdb->prefix . 'psp';
$this->meta_key = '';
}
/**
* Returns the query to return an identifier for the posts to import.
*
* @return string
*/
protected function retrieve_posts_query() {
return "SELECT URL AS identifier FROM {$this->table_name} WHERE blog_id = %d";
}
}

View File

@ -0,0 +1,175 @@
<?php
/**
* File with the class to handle data from RankMath.
*
* @package WPSEO\Admin\Import\Plugins
*/
/**
* Class with functionality to import RankMath post metadata.
*/
class WPSEO_Import_RankMath extends WPSEO_Plugin_Importer {
/**
* The plugin name.
*
* @var string
*/
protected $plugin_name = 'RankMath';
/**
* Meta key, used in SQL LIKE clause for delete query.
*
* @var string
*/
protected $meta_key = 'rank_math_%';
/**
* Array of meta keys to detect and import.
*
* @var array
*/
protected $clone_keys = [
[
'old_key' => 'rank_math_description',
'new_key' => 'metadesc',
],
[
'old_key' => 'rank_math_title',
'new_key' => 'title',
],
[
'old_key' => 'rank_math_canonical_url',
'new_key' => 'canonical',
],
[
'old_key' => 'rank_math_primary_category',
'new_key' => 'primary_category',
],
[
'old_key' => 'rank_math_facebook_title',
'new_key' => 'opengraph-title',
],
[
'old_key' => 'rank_math_facebook_description',
'new_key' => 'opengraph-description',
],
[
'old_key' => 'rank_math_facebook_image',
'new_key' => 'opengraph-image',
],
[
'old_key' => 'rank_math_facebook_image_id',
'new_key' => 'opengraph-image-id',
],
[
'old_key' => 'rank_math_twitter_title',
'new_key' => 'twitter-title',
],
[
'old_key' => 'rank_math_twitter_description',
'new_key' => 'twitter-description',
],
[
'old_key' => 'rank_math_twitter_image',
'new_key' => 'twitter-image',
],
[
'old_key' => 'rank_math_twitter_image_id',
'new_key' => 'twitter-image-id',
],
[
'old_key' => 'rank_math_focus_keyword',
'new_key' => 'focuskw',
],
];
/**
* Handles post meta data to import.
*
* @return bool Import success status.
*/
protected function import() {
global $wpdb;
// Replace % with %% as their variables are the same except for that.
$wpdb->query( "UPDATE $wpdb->postmeta SET meta_value = REPLACE( meta_value, '%', '%%' ) WHERE meta_key IN ( 'rank_math_description', 'rank_math_title' )" );
$this->import_meta_robots();
$return = $this->meta_keys_clone( $this->clone_keys );
// Return %% to % so our import is non-destructive.
$wpdb->query( "UPDATE $wpdb->postmeta SET meta_value = REPLACE( meta_value, '%%', '%' ) WHERE meta_key IN ( 'rank_math_description', 'rank_math_title' )" );
if ( $return ) {
$this->import_settings();
}
return $return;
}
/**
* RankMath stores robots meta quite differently, so we have to parse it out.
*/
private function import_meta_robots() {
global $wpdb;
$post_metas = $wpdb->get_results( "SELECT post_id, meta_value FROM $wpdb->postmeta WHERE meta_key = 'rank_math_robots'" );
foreach ( $post_metas as $post_meta ) {
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- Reason: We can't control the form in which Rankmath sends the data.
$robots_values = unserialize( $post_meta->meta_value );
foreach ( [ 'noindex', 'nofollow' ] as $directive ) {
$directive_key = array_search( $directive, $robots_values, true );
if ( $directive_key !== false ) {
update_post_meta( $post_meta->post_id, '_yoast_wpseo_meta-robots-' . $directive, 1 );
unset( $robots_values[ $directive_key ] );
}
}
if ( count( $robots_values ) > 0 ) {
$value = implode( ',', $robots_values );
update_post_meta( $post_meta->post_id, '_yoast_wpseo_meta-robots-adv', $value );
}
}
}
/**
* Imports some of the RankMath settings.
*/
private function import_settings() {
$settings = [
'title_separator' => 'separator',
'homepage_title' => 'title-home-wpseo',
'homepage_description' => 'metadesc-home-wpseo',
'author_archive_title' => 'title-author-wpseo',
'date_archive_title' => 'title-archive-wpseo',
'search_title' => 'title-search-wpseo',
'404_title' => 'title-404-wpseo',
'pt_post_title' => 'title-post',
'pt_page_title' => 'title-page',
];
$options = get_option( 'rank-math-options-titles' );
foreach ( $settings as $import_setting_key => $setting_key ) {
if ( ! empty( $options[ $import_setting_key ] ) ) {
$value = $options[ $import_setting_key ];
// Make sure replace vars work.
$value = str_replace( '%', '%%', $value );
WPSEO_Options::set( $setting_key, $value );
}
}
}
/**
* Removes the plugin data from the database.
*
* @return bool Cleanup status.
*/
protected function cleanup() {
$return = parent::cleanup();
if ( $return ) {
global $wpdb;
$wpdb->query( "DELETE FROM $wpdb->options WHERE option_name LIKE 'rank-math-%'" );
$wpdb->query( "DELETE FROM $wpdb->options WHERE option_name LIKE '%rank_math%'" );
}
return $return;
}
}

View File

@ -0,0 +1,94 @@
<?php
/**
* File with the class to handle data from SEO Framework.
*
* @package WPSEO\Admin\Import\Plugins
*/
/**
* Class with functionality to import & clean SEO Framework post metadata.
*/
class WPSEO_Import_SEO_Framework extends WPSEO_Plugin_Importer {
/**
* The plugin name.
*
* @var string
*/
protected $plugin_name = 'The SEO Framework';
/**
* Meta key, used in SQL LIKE clause for delete query.
*
* @var string
*/
protected $meta_key = '_genesis_%';
/**
* Array of meta keys to detect and import.
*
* @var array
*/
protected $clone_keys = [
[
'old_key' => '_genesis_description',
'new_key' => 'metadesc',
],
[
'old_key' => '_genesis_title',
'new_key' => 'title',
],
[
'old_key' => '_genesis_noindex',
'new_key' => 'meta-robots-noindex',
],
[
'old_key' => '_genesis_nofollow',
'new_key' => 'meta-robots-nofollow',
],
[
'old_key' => '_genesis_canonical_uri',
'new_key' => 'canonical',
],
[
'old_key' => '_open_graph_title',
'new_key' => 'opengraph-title',
],
[
'old_key' => '_open_graph_description',
'new_key' => 'opengraph-description',
],
[
'old_key' => '_social_image_url',
'new_key' => 'opengraph-image',
],
[
'old_key' => '_twitter_title',
'new_key' => 'twitter-title',
],
[
'old_key' => '_twitter_description',
'new_key' => 'twitter-description',
],
];
/**
* Removes all the metadata set by the SEO Framework plugin.
*
* @return bool
*/
protected function cleanup() {
$set1 = parent::cleanup();
$this->meta_key = '_social_image_%';
$set2 = parent::cleanup();
$this->meta_key = '_twitter_%';
$set3 = parent::cleanup();
$this->meta_key = '_open_graph_%';
$set4 = parent::cleanup();
return ( $set1 || $set2 || $set3 || $set4 );
}
}

View File

@ -0,0 +1,175 @@
<?php
/**
* File with the class to handle data from SEOPressor.
*
* @package WPSEO\Admin\Import\Plugins
*/
/**
* Class WPSEO_Import_SEOPressor.
*
* Class with functionality to import & clean SEOPressor post metadata.
*/
class WPSEO_Import_SEOPressor extends WPSEO_Plugin_Importer {
/**
* The plugin name.
*
* @var string
*/
protected $plugin_name = 'SEOpressor';
/**
* Meta key, used in SQL LIKE clause for delete query.
*
* @var string
*/
protected $meta_key = '_seop_settings';
/**
* Array of meta keys to detect and import.
*
* @var array
*/
protected $clone_keys = [
[
'old_key' => '_seop_settings',
],
];
/**
* Imports the post meta values to Yoast SEO.
*
* @return bool Import success status.
*/
protected function import() {
// Query for all the posts that have an _seop_settings meta set.
$query_posts = new WP_Query( 'post_type=any&meta_key=_seop_settings&order=ASC&fields=ids&nopaging=true' );
foreach ( $query_posts->posts as $post_id ) {
$this->import_post_focus_keywords( $post_id );
$this->import_seopressor_post_settings( $post_id );
}
return true;
}
/**
* Removes all the post meta fields SEOpressor creates.
*
* @return bool Cleanup status.
*/
protected function cleanup() {
global $wpdb;
// If we get to replace the data, let's do some proper cleanup.
return $wpdb->query( "DELETE FROM {$wpdb->postmeta} WHERE meta_key LIKE '_seop_%'" );
}
/**
* Imports the data. SEOpressor stores most of the data in one post array, this loops over it.
*
* @param int $post_id Post ID.
*
* @return void
*/
private function import_seopressor_post_settings( $post_id ) {
$settings = get_post_meta( $post_id, '_seop_settings', true );
foreach (
[
'fb_description' => 'opengraph-description',
'fb_title' => 'opengraph-title',
'fb_type' => 'og_type',
'fb_img' => 'opengraph-image',
'meta_title' => 'title',
'meta_description' => 'metadesc',
'meta_canonical' => 'canonical',
'tw_description' => 'twitter-description',
'tw_title' => 'twitter-title',
'tw_image' => 'twitter-image',
] as $seopressor_key => $yoast_key ) {
$this->import_meta_helper( $seopressor_key, $yoast_key, $settings, $post_id );
}
if ( isset( $settings['meta_rules'] ) ) {
$this->import_post_robots( $settings['meta_rules'], $post_id );
}
}
/**
* Imports the focus keywords, and stores them for later use.
*
* @param int $post_id Post ID.
*
* @return void
*/
private function import_post_focus_keywords( $post_id ) {
// Import the focus keyword.
$focuskw = trim( get_post_meta( $post_id, '_seop_kw_1', true ) );
$this->maybe_save_post_meta( 'focuskw', $focuskw, $post_id );
// Import additional focus keywords for use in premium.
$focuskw2 = trim( get_post_meta( $post_id, '_seop_kw_2', true ) );
$focuskw3 = trim( get_post_meta( $post_id, '_seop_kw_3', true ) );
$focus_keywords = [];
if ( ! empty( $focuskw2 ) ) {
$focus_keywords[] = $focuskw2;
}
if ( ! empty( $focuskw3 ) ) {
$focus_keywords[] = $focuskw3;
}
if ( $focus_keywords !== [] ) {
$this->maybe_save_post_meta( 'focuskeywords', WPSEO_Utils::format_json_encode( $focus_keywords ), $post_id );
}
}
/**
* Retrieves the SEOpressor robot value and map this to Yoast SEO values.
*
* @param string $meta_rules The meta rules taken from the SEOpressor settings array.
* @param int $post_id The post id of the current post.
*
* @return void
*/
private function import_post_robots( $meta_rules, $post_id ) {
$seopressor_robots = explode( '#|#|#', $meta_rules );
$robot_value = $this->get_robot_value( $seopressor_robots );
// Saving the new meta values for Yoast SEO.
$this->maybe_save_post_meta( 'meta-robots-noindex', $robot_value['index'], $post_id );
$this->maybe_save_post_meta( 'meta-robots-nofollow', $robot_value['follow'], $post_id );
$this->maybe_save_post_meta( 'meta-robots-adv', $robot_value['advanced'], $post_id );
}
/**
* Gets the robot config by given SEOpressor robots value.
*
* @param array $seopressor_robots The value in SEOpressor that needs to be converted to the Yoast format.
*
* @return array The robots values in Yoast format.
*/
private function get_robot_value( $seopressor_robots ) {
$return = [
'index' => 2,
'follow' => 0,
'advanced' => '',
];
if ( in_array( 'noindex', $seopressor_robots, true ) ) {
$return['index'] = 1;
}
if ( in_array( 'nofollow', $seopressor_robots, true ) ) {
$return['follow'] = 1;
}
foreach ( [ 'noarchive', 'nosnippet', 'noimageindex' ] as $needle ) {
if ( in_array( $needle, $seopressor_robots, true ) ) {
$return['advanced'] .= $needle . ',';
}
}
$return['advanced'] = rtrim( $return['advanced'], ',' );
return $return;
}
}

View File

@ -0,0 +1,151 @@
<?php
/**
* File with the class to handle data from Smartcrawl SEO.
*
* @package WPSEO\Admin\Import\Plugins
*/
/**
* Class with functionality to import & clean Smartcrawl SEO post metadata.
*/
class WPSEO_Import_Smartcrawl_SEO extends WPSEO_Plugin_Importer {
/**
* The plugin name.
*
* @var string
*/
protected $plugin_name = 'Smartcrawl SEO';
/**
* Meta key, used in SQL LIKE clause for delete query.
*
* @var string
*/
protected $meta_key = '_wds_%';
/**
* Array of meta keys to detect and import.
*
* @var array
*/
protected $clone_keys = [
[
'old_key' => '_wds_metadesc',
'new_key' => 'metadesc',
],
[
'old_key' => '_wds_title',
'new_key' => 'title',
],
[
'old_key' => '_wds_canonical',
'new_key' => 'canonical',
],
[
'old_key' => '_wds_focus-keywords',
'new_key' => 'focuskw',
],
[
'old_key' => '_wds_meta-robots-noindex',
'new_key' => 'meta-robots-noindex',
],
[
'old_key' => '_wds_meta-robots-nofollow',
'new_key' => 'meta-robots-nofollow',
],
];
/**
* Used for importing Twitter and Facebook meta's.
*
* @var array
*/
protected $social_keys = [];
/**
* Handles post meta data to import.
*
* @return bool Import success status.
*/
protected function import() {
$return = parent::import();
if ( $return ) {
$this->import_opengraph();
$this->import_twitter();
}
return $return;
}
/**
* Imports the OpenGraph meta keys saved by Smartcrawl.
*
* @return bool Import status.
*/
protected function import_opengraph() {
$this->social_keys = [
'title' => 'opengraph-title',
'description' => 'opengraph-description',
'images' => 'opengraph-image',
];
return $this->post_find_import( '_wds_opengraph' );
}
/**
* Imports the Twitter meta keys saved by Smartcrawl.
*
* @return bool Import status.
*/
protected function import_twitter() {
$this->social_keys = [
'title' => 'twitter-title',
'description' => 'twitter-description',
];
return $this->post_find_import( '_wds_twitter' );
}
/**
* Imports a post's serialized post meta values.
*
* @param int $post_id Post ID.
* @param string $key The meta key to import.
*
* @return void
*/
protected function import_serialized_post_meta( $post_id, $key ) {
$data = get_post_meta( $post_id, $key, true );
$data = maybe_unserialize( $data );
foreach ( $this->social_keys as $key => $meta_key ) {
if ( ! isset( $data[ $key ] ) ) {
return;
}
$value = $data[ $key ];
if ( is_array( $value ) ) {
$value = $value[0];
}
$this->maybe_save_post_meta( $meta_key, $value, $post_id );
}
}
/**
* Finds all the posts with a certain meta key and imports its values.
*
* @param string $key The meta key to search for.
*
* @return bool Import status.
*/
protected function post_find_import( $key ) {
$query_posts = new WP_Query( 'post_type=any&meta_key=' . $key . '&order=ASC&fields=ids&nopaging=true' );
if ( empty( $query_posts->posts ) ) {
return false;
}
foreach ( array_values( $query_posts->posts ) as $post_id ) {
$this->import_serialized_post_meta( $post_id, $key );
}
return true;
}
}

View File

@ -0,0 +1,224 @@
<?php
/**
* File with the class to handle data from Squirrly.
*
* @package WPSEO\Admin\Import\Plugins
*/
/**
* Class with functionality to import & clean Squirrly post metadata.
*/
class WPSEO_Import_Squirrly extends WPSEO_Plugin_Importer {
/**
* The plugin name.
*
* @var string
*/
protected $plugin_name = 'Squirrly SEO';
/**
* Holds the name of the table Squirrly uses to store data.
*
* @var string
*/
protected $table_name;
/**
* Meta key, used in SQL LIKE clause for delete query.
*
* @var string
*/
protected $meta_key = '_sq_post_keyword';
/**
* Data to import from (and the target to field) the serialized array stored in the SEO field in the Squirrly table.
*
* @var array
*/
protected $seo_field_keys = [
'noindex' => 'meta-robots-noindex',
'nofollow' => 'meta-robots-nofollow',
'title' => 'title',
'description' => 'metadesc',
'canonical' => 'canonical',
'cornerstone' => '_yst_is_cornerstone',
'tw_media' => 'twitter-image',
'tw_title' => 'twitter-title',
'tw_description' => 'twitter-description',
'og_title' => 'opengraph-title',
'og_description' => 'opengraph-description',
'og_media' => 'opengraph-image',
'focuskw' => 'focuskw',
];
/**
* WPSEO_Import_Squirrly constructor.
*/
public function __construct() {
parent::__construct();
global $wpdb;
$this->table_name = $wpdb->prefix . 'qss';
}
/**
* Imports the post meta values to Yoast SEO.
*
* @return bool Import success status.
*/
protected function import() {
$results = $this->retrieve_posts();
foreach ( $results as $post ) {
$return = $this->import_post_values( $post->identifier );
if ( ! $return ) {
return false;
}
}
return true;
}
/**
* Retrieve the posts from the Squirrly Database.
*
* @return array Array of post IDs from the DB.
*/
protected function retrieve_posts() {
global $wpdb;
return $wpdb->get_results(
$wpdb->prepare(
$this->retrieve_posts_query(),
get_current_blog_id()
)
);
}
/**
* Returns the query to return an identifier for the posts to import.
*
* @return string Query to get post ID's from the DB.
*/
protected function retrieve_posts_query() {
return "SELECT post_id AS identifier FROM {$this->table_name} WHERE blog_id = %d";
}
/**
* Removes the DB table and the post meta field Squirrly creates.
*
* @return bool Cleanup status.
*/
protected function cleanup() {
global $wpdb;
// If we can clean, let's clean.
$wpdb->query( "DROP TABLE {$this->table_name}" );
// This removes the post meta field for the focus keyword from the DB.
parent::cleanup();
// If we can still see the table, something went wrong.
if ( $this->detect() ) {
$this->cleanup_error_msg();
return false;
}
return true;
}
/**
* Detects whether there is post meta data to import.
*
* @return bool Boolean indicating whether there is something to import.
*/
protected function detect() {
global $wpdb;
$result = $wpdb->get_var( "SHOW TABLES LIKE '{$this->table_name}'" );
if ( is_wp_error( $result ) || is_null( $result ) ) {
return false;
}
return true;
}
/**
* Imports the data of a post out of Squirrly's DB table.
*
* @param mixed $post_identifier Post identifier, can be ID or string.
*
* @return bool Import status.
*/
private function import_post_values( $post_identifier ) {
$data = $this->retrieve_post_data( $post_identifier );
if ( ! $data ) {
return false;
}
if ( ! is_numeric( $post_identifier ) ) {
$post_id = url_to_postid( $post_identifier );
}
if ( is_numeric( $post_identifier ) ) {
$post_id = (int) $post_identifier;
$data['focuskw'] = $this->maybe_add_focus_kw( $post_identifier );
}
foreach ( $this->seo_field_keys as $squirrly_key => $yoast_key ) {
$this->import_meta_helper( $squirrly_key, $yoast_key, $data, $post_id );
}
return true;
}
/**
* Retrieves the Squirrly SEO data for a post from the DB.
*
* @param int $post_identifier Post ID.
*
* @return array|bool Array of data or false.
*/
private function retrieve_post_data( $post_identifier ) {
global $wpdb;
if ( is_numeric( $post_identifier ) ) {
$post_identifier = (int) $post_identifier;
$query_where = 'post_id = %d';
}
if ( ! is_numeric( $post_identifier ) ) {
$query_where = 'URL = %s';
}
$replacements = [
get_current_blog_id(),
$post_identifier,
];
$data = $wpdb->get_var(
$wpdb->prepare(
"SELECT seo FROM {$this->table_name} WHERE blog_id = %d AND " . $query_where,
$replacements
)
);
if ( ! $data || is_wp_error( $data ) ) {
return false;
}
$data = maybe_unserialize( $data );
return $data;
}
/**
* Squirrly stores the focus keyword in post meta.
*
* @param int $post_id Post ID.
*
* @return string The focus keyword.
*/
private function maybe_add_focus_kw( $post_id ) {
$focuskw = get_post_meta( $post_id, '_sq_post_keyword', true );
if ( $focuskw ) {
$focuskw = json_decode( $focuskw );
return $focuskw->keyword;
}
return '';
}
}

View File

@ -0,0 +1,64 @@
<?php
/**
* File with the class to handle data from Ultimate SEO.
*
* @package WPSEO\Admin\Import\Plugins
*/
/**
* Class with functionality to import & clean Ultimate SEO post metadata.
*/
class WPSEO_Import_Ultimate_SEO extends WPSEO_Plugin_Importer {
/**
* The plugin name.
*
* @var string
*/
protected $plugin_name = 'Ultimate SEO';
/**
* Meta key, used in SQL LIKE clause for delete query.
*
* @var string
*/
protected $meta_key = '_su_%';
/**
* Array of meta keys to detect and import.
*
* @var array
*/
protected $clone_keys = [
[
'old_key' => '_su_description',
'new_key' => 'metadesc',
],
[
'old_key' => '_su_title',
'new_key' => 'title',
],
[
'old_key' => '_su_og_title',
'new_key' => 'opengraph-title',
],
[
'old_key' => '_su_og_description',
'new_key' => 'opengraph-description',
],
[
'old_key' => '_su_og_image',
'new_key' => 'opengraph-image',
],
[
'old_key' => '_su_meta_robots_noindex',
'new_key' => 'meta-robots-noindex',
'convert' => [ 'on' => 1 ],
],
[
'old_key' => '_su_meta_robots_nofollow',
'new_key' => 'meta-robots-nofollow',
'convert' => [ 'on' => 1 ],
],
];
}

View File

@ -0,0 +1,138 @@
<?php
/**
* File with the class to handle data from WooThemes SEO.
*
* @package WPSEO\Admin\Import\Plugins
*/
/**
* Class WPSEO_Import_WooThemes_SEO
*
* Class with functionality to import & clean WooThemes SEO post metadata.
*/
class WPSEO_Import_WooThemes_SEO extends WPSEO_Plugin_Importer {
/**
* The plugin name.
*
* @var string
*/
protected $plugin_name = 'WooThemes SEO';
/**
* Meta key, used in SQL LIKE clause for delete query.
*
* @var string
*/
protected $meta_key = 'seo_title';
/**
* Array of meta keys to detect and import.
*
* @var array
*/
protected $clone_keys = [
[
'old_key' => 'seo_description',
'new_key' => 'metadesc',
],
[
'old_key' => 'seo_title',
'new_key' => 'title',
],
[
'old_key' => 'seo_noindex',
'new_key' => 'meta-robots-noindex',
],
[
'old_key' => 'seo_follow',
'new_key' => 'meta-robots-nofollow',
],
];
/**
* Holds the meta fields we can delete after import.
*
* @var array
*/
protected $cleanup_metas = [
'seo_follow',
'seo_noindex',
'seo_title',
'seo_description',
'seo_keywords',
];
/**
* Holds the options we can delete after import.
*
* @var array
*/
protected $cleanup_options = [
'seo_woo_archive_layout',
'seo_woo_single_layout',
'seo_woo_page_layout',
'seo_woo_wp_title',
'seo_woo_meta_single_desc',
'seo_woo_meta_single_key',
'seo_woo_home_layout',
];
/**
* Cleans up the WooThemes SEO settings.
*
* @return bool Cleanup status.
*/
protected function cleanup() {
$result = $this->cleanup_meta();
if ( $result ) {
$this->cleanup_options();
}
return $result;
}
/**
* Removes the Woo Options from the database.
*
* @return void
*/
private function cleanup_options() {
foreach ( $this->cleanup_options as $option ) {
delete_option( $option );
}
}
/**
* Removes the post meta fields from the database.
*
* @return bool Cleanup status.
*/
private function cleanup_meta() {
foreach ( $this->cleanup_metas as $key ) {
$result = $this->cleanup_meta_key( $key );
if ( ! $result ) {
return false;
}
}
return true;
}
/**
* Removes a single meta field from the postmeta table in the database.
*
* @param string $key The meta_key to delete.
*
* @return bool Cleanup status.
*/
private function cleanup_meta_key( $key ) {
global $wpdb;
$wpdb->query(
$wpdb->prepare(
"DELETE FROM {$wpdb->postmeta} WHERE meta_key = %s",
$key
)
);
return $wpdb->__get( 'result' );
}
}

View File

@ -0,0 +1,82 @@
<?php
/**
* File with the class to handle data from WP Meta SEO.
*
* @package WPSEO\Admin\Import\Plugins
*/
/**
* Class with functionality to import & clean WP Meta SEO post metadata.
*/
class WPSEO_Import_WP_Meta_SEO extends WPSEO_Plugin_Importer {
/**
* The plugin name.
*
* @var string
*/
protected $plugin_name = 'WP Meta SEO';
/**
* Meta key, used in SQL LIKE clause for delete query.
*
* @var string
*/
protected $meta_key = '_metaseo_%';
/**
* Array of meta keys to detect and import.
*
* @var array
*/
protected $clone_keys = [
[
'old_key' => '_metaseo_metadesc',
'new_key' => 'metadesc',
],
[
'old_key' => '_metaseo_metatitle',
'new_key' => 'title',
],
[
'old_key' => '_metaseo_metaopengraph-title',
'new_key' => 'opengraph-title',
],
[
'old_key' => '_metaseo_metaopengraph-desc',
'new_key' => 'opengraph-description',
],
[
'old_key' => '_metaseo_metaopengraph-image',
'new_key' => 'opengraph-image',
],
[
'old_key' => '_metaseo_metatwitter-title',
'new_key' => 'twitter-title',
],
[
'old_key' => '_metaseo_metatwitter-desc',
'new_key' => 'twitter-description',
],
[
'old_key' => '_metaseo_metatwitter-image',
'new_key' => 'twitter-image',
],
[
'old_key' => '_metaseo_metaindex',
'new_key' => 'meta-robots-noindex',
'convert' => [
'index' => 0,
'noindex' => 1,
],
],
[
'old_key' => '_metaseo_metafollow',
'new_key' => 'meta-robots-nofollow',
'convert' => [
'follow' => 0,
'nofollow' => 1,
],
],
];
}

View File

@ -0,0 +1,299 @@
<?php
/**
* File with the class to handle data from wpSEO.de.
*
* @package WPSEO\Admin\Import\Plugins
*/
/**
* Class WPSEO_Import_WPSEO.
*
* Class with functionality to import & clean wpSEO.de post metadata.
*/
class WPSEO_Import_WPSEO extends WPSEO_Plugin_Importer {
/**
* The plugin name.
*
* @var string
*/
protected $plugin_name = 'wpSEO.de';
/**
* Meta key, used in SQL LIKE clause for delete query.
*
* @var string
*/
protected $meta_key = '_wpseo_edit_%';
/**
* Array of meta keys to detect and import.
*
* @var array
*/
protected $clone_keys = [
[
'old_key' => '_wpseo_edit_description',
'new_key' => 'metadesc',
],
[
'old_key' => '_wpseo_edit_title',
'new_key' => 'title',
],
[
'old_key' => '_wpseo_edit_canonical',
'new_key' => 'canonical',
],
[
'old_key' => '_wpseo_edit_og_title',
'new_key' => 'opengraph-title',
],
[
'old_key' => '_wpseo_edit_og_description',
'new_key' => 'opengraph-description',
],
[
'old_key' => '_wpseo_edit_og_image',
'new_key' => 'opengraph-image',
],
[
'old_key' => '_wpseo_edit_twittercard_title',
'new_key' => 'twitter-title',
],
[
'old_key' => '_wpseo_edit_twittercard_description',
'new_key' => 'twitter-description',
],
[
'old_key' => '_wpseo_edit_twittercard_image',
'new_key' => 'twitter-image',
],
];
/**
* The values 1 - 6 are the configured values from wpSEO. This array will map the values of wpSEO to our values.
*
* There are some double array like 1-6 and 3-4. The reason is they only set the index value. The follow value is
* the default we use in the cases there isn't a follow value present.
*
* @var array
*/
private $robot_values = [
// In wpSEO: index, follow.
1 => [
'index' => 2,
'follow' => 0,
],
// In wpSEO: index, nofollow.
2 => [
'index' => 2,
'follow' => 1,
],
// In wpSEO: noindex.
3 => [
'index' => 1,
'follow' => 0,
],
// In wpSEO: noindex, follow.
4 => [
'index' => 1,
'follow' => 0,
],
// In wpSEO: noindex, nofollow.
5 => [
'index' => 1,
'follow' => 1,
],
// In wpSEO: index.
6 => [
'index' => 2,
'follow' => 0,
],
];
/**
* Imports wpSEO settings.
*
* @return bool Import success status.
*/
protected function import() {
$status = parent::import();
if ( $status ) {
$this->import_post_robots();
$this->import_taxonomy_metas();
}
return $status;
}
/**
* Removes wpseo.de post meta's.
*
* @return bool Cleanup status.
*/
protected function cleanup() {
$this->cleanup_term_meta();
$result = $this->cleanup_post_meta();
return $result;
}
/**
* Detects whether there is post meta data to import.
*
* @return bool Boolean indicating whether there is something to import.
*/
protected function detect() {
if ( parent::detect() ) {
return true;
}
global $wpdb;
$count = $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->options} WHERE option_name LIKE 'wpseo_category_%'" );
if ( $count !== '0' ) {
return true;
}
return false;
}
/**
* Imports the robot values from WPSEO plugin. These have to be converted to the Yoast format.
*
* @return void
*/
private function import_post_robots() {
$query_posts = new WP_Query( 'post_type=any&meta_key=_wpseo_edit_robots&order=ASC&fields=ids&nopaging=true' );
if ( ! empty( $query_posts->posts ) ) {
foreach ( array_values( $query_posts->posts ) as $post_id ) {
$this->import_post_robot( $post_id );
}
}
}
/**
* Gets the wpSEO robot value and map this to Yoast SEO values.
*
* @param int $post_id The post id of the current post.
*
* @return void
*/
private function import_post_robot( $post_id ) {
$wpseo_robots = get_post_meta( $post_id, '_wpseo_edit_robots', true );
$robot_value = $this->get_robot_value( $wpseo_robots );
// Saving the new meta values for Yoast SEO.
$this->maybe_save_post_meta( 'meta-robots-noindex', $robot_value['index'], $post_id );
$this->maybe_save_post_meta( 'meta-robots-nofollow', $robot_value['follow'], $post_id );
}
/**
* Imports the taxonomy metas from wpSEO.
*
* @return void
*/
private function import_taxonomy_metas() {
$terms = get_terms( get_taxonomies(), [ 'hide_empty' => false ] );
$tax_meta = get_option( 'wpseo_taxonomy_meta' );
foreach ( $terms as $term ) {
$this->import_taxonomy_description( $tax_meta, $term->taxonomy, $term->term_id );
$this->import_taxonomy_robots( $tax_meta, $term->taxonomy, $term->term_id );
}
update_option( 'wpseo_taxonomy_meta', $tax_meta );
}
/**
* Imports the meta description to Yoast SEO.
*
* @param array $tax_meta The array with the current metadata.
* @param string $taxonomy String with the name of the taxonomy.
* @param string $term_id The ID of the current term.
*
* @return void
*/
private function import_taxonomy_description( &$tax_meta, $taxonomy, $term_id ) {
$description = get_option( 'wpseo_' . $taxonomy . '_' . $term_id, false );
if ( $description !== false ) {
// Import description.
$tax_meta[ $taxonomy ][ $term_id ]['wpseo_desc'] = $description;
}
}
/**
* Imports the robot value to Yoast SEO.
*
* @param array $tax_meta The array with the current metadata.
* @param string $taxonomy String with the name of the taxonomy.
* @param string $term_id The ID of the current term.
*
* @return void
*/
private function import_taxonomy_robots( &$tax_meta, $taxonomy, $term_id ) {
$wpseo_robots = get_option( 'wpseo_' . $taxonomy . '_' . $term_id . '_robots', false );
if ( $wpseo_robots === false ) {
return;
}
// The value 1, 2 and 6 are the index values in wpSEO.
$new_robot_value = 'noindex';
if ( in_array( (int) $wpseo_robots, [ 1, 2, 6 ], true ) ) {
$new_robot_value = 'index';
}
$tax_meta[ $taxonomy ][ $term_id ]['wpseo_noindex'] = $new_robot_value;
}
/**
* Deletes the wpSEO taxonomy meta data.
*
* @param string $taxonomy String with the name of the taxonomy.
* @param string $term_id The ID of the current term.
*
* @return void
*/
private function delete_taxonomy_metas( $taxonomy, $term_id ) {
delete_option( 'wpseo_' . $taxonomy . '_' . $term_id );
delete_option( 'wpseo_' . $taxonomy . '_' . $term_id . '_robots' );
}
/**
* Gets the robot config by given wpSEO robots value.
*
* @param string $wpseo_robots The value in wpSEO that needs to be converted to the Yoast format.
*
* @return string The correct robot value.
*/
private function get_robot_value( $wpseo_robots ) {
if ( array_key_exists( $wpseo_robots, $this->robot_values ) ) {
return $this->robot_values[ $wpseo_robots ];
}
return $this->robot_values[1];
}
/**
* Deletes wpSEO postmeta from the database.
*
* @return bool Cleanup status.
*/
private function cleanup_post_meta() {
global $wpdb;
// If we get to replace the data, let's do some proper cleanup.
return $wpdb->query( "DELETE FROM {$wpdb->postmeta} WHERE meta_key LIKE '_wpseo_edit_%'" );
}
/**
* Cleans up the wpSEO term meta.
*
* @return void
*/
private function cleanup_term_meta() {
$terms = get_terms( get_taxonomies(), [ 'hide_empty' => false ] );
foreach ( $terms as $term ) {
$this->delete_taxonomy_metas( $term->taxonomy, $term->term_id );
}
}
}

View File

@ -0,0 +1,47 @@
<?php
/**
* WPSEO plugin file.
*
* @package WPSEO\Admin\Import\Plugins
*/
/**
* Class WPSEO_Plugin_Importers.
*
* Object which contains all importers.
*/
class WPSEO_Plugin_Importers {
/**
* List of supported importers.
*
* @var array
*/
private static $importers = [
'WPSEO_Import_AIOSEO',
'WPSEO_Import_AIOSEO_V4',
'WPSEO_Import_Greg_SEO',
'WPSEO_Import_HeadSpace',
'WPSEO_Import_Jetpack_SEO',
'WPSEO_Import_WP_Meta_SEO',
'WPSEO_Import_Platinum_SEO',
'WPSEO_Import_Premium_SEO_Pack',
'WPSEO_Import_RankMath',
'WPSEO_Import_SEOPressor',
'WPSEO_Import_SEO_Framework',
'WPSEO_Import_Smartcrawl_SEO',
'WPSEO_Import_Squirrly',
'WPSEO_Import_Ultimate_SEO',
'WPSEO_Import_WooThemes_SEO',
'WPSEO_Import_WPSEO',
];
/**
* Returns an array of importers available.
*
* @return array Available importers.
*/
public static function get() {
return self::$importers;
}
}