first commit
This commit is contained in:
@@ -0,0 +1,185 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_TM_ICL20_Migrate_Local {
|
||||
const JOBS_TYPES_DOCUMENTS = 'icl_translation_status';
|
||||
const JOBS_TYPES_STRINGS = 'icl_string_translations';
|
||||
private $progress;
|
||||
private $sitepress;
|
||||
private $status;
|
||||
|
||||
/** @var WPML_TP_Services */
|
||||
private $tp_services;
|
||||
|
||||
/**
|
||||
* WPML_TM_ICL20 constructor.
|
||||
*
|
||||
* @param WPML_TP_Services $tp_services
|
||||
* @param WPML_TM_ICL20_Migration_Status $status
|
||||
* @param WPML_TM_ICL20_Migration_Progress $progress
|
||||
* @param SitePress $sitepress
|
||||
*
|
||||
* @internal param SitePress $sitepress
|
||||
*/
|
||||
public function __construct(
|
||||
WPML_TP_Services $tp_services,
|
||||
WPML_TM_ICL20_Migration_Status $status,
|
||||
WPML_TM_ICL20_Migration_Progress $progress,
|
||||
SitePress $sitepress
|
||||
) {
|
||||
$this->tp_services = $tp_services;
|
||||
$this->status = $status;
|
||||
$this->progress = $progress;
|
||||
$this->sitepress = $sitepress;
|
||||
}
|
||||
|
||||
public function migrate_jobs( $table ) {
|
||||
$result = false;
|
||||
|
||||
$current_service = $this->tp_services->get_current_service();
|
||||
|
||||
if ( $this->status->get_ICL_20_TS_ID() === $current_service->id ) {
|
||||
$step = null;
|
||||
|
||||
if ( self::JOBS_TYPES_DOCUMENTS === $table ) {
|
||||
$step = WPML_TM_ICL20_Migration_Progress::STEP_MIGRATE_JOBS_DOCUMENTS;
|
||||
}
|
||||
if ( self::JOBS_TYPES_STRINGS === $table ) {
|
||||
$step = WPML_TM_ICL20_Migration_Progress::STEP_MIGRATE_JOBS_STRINGS;
|
||||
}
|
||||
|
||||
if ( null !== $step ) {
|
||||
$update = $this->update_table( $table );
|
||||
|
||||
$result = false !== $update;
|
||||
$this->progress->set_completed_step( $step, $result );
|
||||
} else {
|
||||
$this->progress->log_failed_attempt( __METHOD__ . ' - ' . 'Wrong "' . $table . '"' );
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $table
|
||||
*
|
||||
* @return false|int
|
||||
*/
|
||||
private function update_table( $table ) {
|
||||
$wpdb = $this->sitepress->get_wpdb();
|
||||
|
||||
$update = $wpdb->update(
|
||||
$wpdb->prefix . $table,
|
||||
array(
|
||||
'translator_id' => 0,
|
||||
'translation_service' => $this->status->get_ICL_20_TS_ID(),
|
||||
),
|
||||
array(
|
||||
'translation_service' => $this->status->get_ICL_LEGACY_TS_ID(),
|
||||
),
|
||||
array( '%d', '%d' ),
|
||||
array( '%d' )
|
||||
);
|
||||
|
||||
if ( false === $update ) {
|
||||
$this->progress->log_failed_attempt( __METHOD__ . ' - ' . $wpdb->last_error );
|
||||
}
|
||||
|
||||
return $update;
|
||||
}
|
||||
|
||||
public function migrate_project() {
|
||||
$old_index = $this->progress->get_project_to_migrate();
|
||||
// icl_translation_projects
|
||||
$migrated = false;
|
||||
|
||||
if ( $old_index ) {
|
||||
$current_service = $this->tp_services->get_current_service();
|
||||
|
||||
if ( $current_service && null !== $current_service->id ) {
|
||||
$new_index = md5( $current_service->id . serialize( $current_service->custom_fields_data ) );
|
||||
|
||||
$migrated = $this->update_project_index( $old_index, $new_index );
|
||||
}
|
||||
}
|
||||
|
||||
$this->progress->set_completed_step( WPML_TM_ICL20_Migration_Progress::STEP_MIGRATE_LOCAL_PROJECT, $migrated );
|
||||
|
||||
return $migrated;
|
||||
}
|
||||
|
||||
private function update_project_index( $old_service_index, $new_service_index ) {
|
||||
$updated = false;
|
||||
|
||||
$projects = $this->sitepress->get_setting( 'icl_translation_projects', null );
|
||||
|
||||
$old_index_exists = array_key_exists( $old_service_index, $projects );
|
||||
$new_index_does_not_exists = ! array_key_exists( $new_service_index, $projects );
|
||||
|
||||
if ( $projects && $old_index_exists && $new_index_does_not_exists ) {
|
||||
$project = $projects[ $old_service_index ];
|
||||
|
||||
$projects[ $new_service_index ] = $project;
|
||||
unset( $projects[ $old_service_index ] );
|
||||
|
||||
$this->sitepress->set_setting( 'icl_translation_projects', $projects, true );
|
||||
$updated = true;
|
||||
}
|
||||
|
||||
if ( false === $updated ) {
|
||||
$error = '';
|
||||
if ( ! $old_index_exists ) {
|
||||
$error = 'The old project does not exists';
|
||||
}
|
||||
if ( ! $new_index_does_not_exists ) {
|
||||
$error = 'The new project index already exists';
|
||||
}
|
||||
$this->progress->log_failed_attempt( __METHOD__ . ' - ' . $error );
|
||||
}
|
||||
|
||||
return $updated;
|
||||
}
|
||||
|
||||
public function migrate_service( $new_token ) {
|
||||
$current_service = $this->tp_services->get_current_service();
|
||||
|
||||
$migrated = false;
|
||||
|
||||
if ( $current_service ) {
|
||||
$old_index = md5( $current_service->id . serialize( $current_service->custom_fields_data ) );
|
||||
$this->progress->set_project_to_migrate( $old_index );
|
||||
|
||||
$icl20_service_id = $this->status->get_ICL_20_TS_ID();
|
||||
$this->tp_services->select_service(
|
||||
$icl20_service_id,
|
||||
array(
|
||||
'api_token' => $new_token,
|
||||
)
|
||||
);
|
||||
$active_service = $this->tp_services->get_current_service();
|
||||
$migrated = $active_service->id === $icl20_service_id;
|
||||
}
|
||||
|
||||
$this->progress->set_completed_step( WPML_TM_ICL20_Migration_Progress::STEP_MIGRATE_LOCAL_SERVICE, $migrated );
|
||||
|
||||
return $migrated;
|
||||
}
|
||||
|
||||
public function rollback_service() {
|
||||
$current_service = $this->tp_services->get_current_service();
|
||||
|
||||
$rolled_back = false;
|
||||
|
||||
if ( $current_service ) {
|
||||
$this->tp_services->select_service( $this->status->get_ICL_LEGACY_TS_ID() );
|
||||
$active_service = $this->tp_services->get_current_service();
|
||||
$rolled_back = $active_service->id === $this->status->get_ICL_LEGACY_TS_ID();
|
||||
}
|
||||
$this->progress->set_completed_step( WPML_TM_ICL20_Migration_Progress::STEP_MIGRATE_LOCAL_SERVICE, false );
|
||||
|
||||
return $rolled_back;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
class WPML_TM_ICL20_Migrate_Remote {
|
||||
private $container;
|
||||
private $progress;
|
||||
|
||||
/**
|
||||
* WPML_TM_ICL20 constructor.
|
||||
*
|
||||
* @param WPML_TM_ICL20_Migration_Progress $progress
|
||||
* @param WPML_TM_ICL20_Migration_Container $container
|
||||
*/
|
||||
public function __construct(
|
||||
WPML_TM_ICL20_Migration_Progress $progress,
|
||||
WPML_TM_ICL20_Migration_Container $container
|
||||
) {
|
||||
$this->progress = $progress;
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $ts_accesskey
|
||||
* @param int $ts_id
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* Note: `ts_id` (aka `website_id`) = `website_id`
|
||||
*
|
||||
* @link https://onthegosystems.myjetbrains.com/youtrack/issue/icldev-2322
|
||||
*/
|
||||
public function acknowledge_icl( $ts_id, $ts_accesskey ) {
|
||||
$result = false;
|
||||
try {
|
||||
$result = $this->container->get_acknowledge()->acknowledge_icl( $ts_id, $ts_accesskey );
|
||||
} catch ( WPML_TM_ICL20MigrationException $ex ) {
|
||||
$this->progress->log_failed_attempt( __METHOD__ . ' - ' . $ex->getCode() . ': ' . $ex->getMessage() );
|
||||
}
|
||||
|
||||
if ( $result ) {
|
||||
$this->progress->set_completed_step( WPML_TM_ICL20_Migration_Progress::STEP_ICL_ACK, true );
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
$this->progress->set_completed_step( WPML_TM_ICL20_Migration_Progress::STEP_ICL_ACK, false );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $ts_accesskey
|
||||
* @param int $ts_id
|
||||
*
|
||||
* @return string|null
|
||||
*
|
||||
* Note: `ts_id` (aka `website_id`) = `website_id`
|
||||
*
|
||||
* @link https://onthegosystems.myjetbrains.com/youtrack/issue/icldev-2285
|
||||
*/
|
||||
public function get_token( $ts_id, $ts_accesskey ) {
|
||||
$token = null;
|
||||
try {
|
||||
$token = $this->container->get_token()->get_token( $ts_id, $ts_accesskey );
|
||||
} catch ( WPML_TM_ICL20MigrationException $ex ) {
|
||||
$this->progress->log_failed_attempt( __METHOD__ . ' - ' . $ex->getCode() . ': ' . $ex->getMessage() );
|
||||
}
|
||||
|
||||
if ( null !== $token ) {
|
||||
$this->progress->set_completed_step( WPML_TM_ICL20_Migration_Progress::STEP_TOKEN, $token );
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
$this->progress->set_completed_step( 'token', false );
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $project_id
|
||||
* @param string $access_key
|
||||
* @param string $new_token
|
||||
*
|
||||
* @return bool|null
|
||||
* @link https://onthegosystems.myjetbrains.com/youtrack/issue/tsapi-887
|
||||
*
|
||||
*/
|
||||
public function migrate_project( $project_id, $access_key, $new_token ) {
|
||||
$migrate = null;
|
||||
try {
|
||||
$migrate = $this->container->get_project()->migrate( $project_id, $access_key, $new_token );
|
||||
} catch ( WPML_TM_ICL20MigrationException $ex ) {
|
||||
$this->progress->log_failed_attempt( __METHOD__ . ' - ' . $ex->getCode() . ': ' . $ex->getMessage() );
|
||||
}
|
||||
|
||||
if ( $migrate ) {
|
||||
$this->progress->set_completed_step( WPML_TM_ICL20_Migration_Progress::STEP_MIGRATE_REMOTE_PROJECT, true );
|
||||
|
||||
return $migrate;
|
||||
}
|
||||
|
||||
$this->progress->set_completed_step( WPML_TM_ICL20_Migration_Progress::STEP_MIGRATE_REMOTE_PROJECT, false );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $project_id
|
||||
* @param string $access_key
|
||||
*
|
||||
* @return bool
|
||||
* @link https://onthegosystems.myjetbrains.com/youtrack/issue/tsapi-887
|
||||
*
|
||||
*/
|
||||
public function migrate_project_rollback( $project_id, $access_key ) {
|
||||
$result = false;
|
||||
try {
|
||||
$result = $this->container->get_project()->rollback_migration( $project_id, $access_key );
|
||||
} catch ( WPML_TM_ICL20MigrationException $ex ) {
|
||||
$this->progress->log_failed_attempt( __METHOD__ . ' - ' . $ex->getCode() . ': ' . $ex->getMessage() );
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_TM_ICL20_Migrate {
|
||||
private $local_migration;
|
||||
private $progress;
|
||||
private $remote_migration;
|
||||
private $status;
|
||||
|
||||
/** @var WPML_TP_Services */
|
||||
private $tp_services;
|
||||
|
||||
public function __construct(
|
||||
WPML_TM_ICL20_Migration_Progress $progress,
|
||||
WPML_TM_ICL20_Migration_Status $status,
|
||||
WPML_TM_ICL20_Migrate_Remote $remote_migration,
|
||||
WPML_TM_ICL20_Migrate_Local $local_migration,
|
||||
WPML_TP_Services $tp_services
|
||||
) {
|
||||
$this->progress = $progress;
|
||||
$this->status = $status;
|
||||
$this->remote_migration = $remote_migration;
|
||||
$this->local_migration = $local_migration;
|
||||
$this->tp_services = $tp_services;
|
||||
}
|
||||
|
||||
public function migrate_project_rollback() {
|
||||
if ( ! $this->status->has_active_legacy_icl() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$project = $this->tp_services->get_current_project();
|
||||
$token = $this->get_token( $project );
|
||||
if ( $token ) {
|
||||
return $this->remote_migration->migrate_project_rollback( $project->id, $project->access_key );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function run() {
|
||||
$this->progress->set_migration_started();
|
||||
|
||||
$project = $this->tp_services->get_current_project();
|
||||
$token = $project ? $this->get_token( $project ) : null;
|
||||
|
||||
if ( (bool) $token
|
||||
&& $this->migrate_project( $project, $token )
|
||||
&& $this->acknowledge_icl( $project )
|
||||
&& $this->migrate_local_service( $token )
|
||||
&& $this->migrate_local_project()
|
||||
&& $this->migrate_local_jobs(
|
||||
WPML_TM_ICL20_Migrate_Local::JOBS_TYPES_DOCUMENTS,
|
||||
WPML_TM_ICL20_Migration_Progress::STEP_MIGRATE_JOBS_DOCUMENTS
|
||||
)
|
||||
&& $this->migrate_local_jobs(
|
||||
WPML_TM_ICL20_Migrate_Local::JOBS_TYPES_STRINGS,
|
||||
WPML_TM_ICL20_Migration_Progress::STEP_MIGRATE_JOBS_STRINGS
|
||||
) ) {
|
||||
|
||||
$this->progress->set_migration_done();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $project
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_token( $project ) {
|
||||
$token = $this->progress->get_completed_step( WPML_TM_ICL20_Migration_Progress::STEP_TOKEN );
|
||||
if ( WPML_TM_ICL20_Migration_Progress::STEP_FAILED === $token ) {
|
||||
$token = $this->remote_migration->get_token( $project->ts_id, $project->ts_access_key );
|
||||
}
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $project
|
||||
* @param $token
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function migrate_project( $project, $token ) {
|
||||
$project_migrated = $this->progress->get_completed_step( WPML_TM_ICL20_Migration_Progress::STEP_MIGRATE_REMOTE_PROJECT );
|
||||
if ( WPML_TM_ICL20_Migration_Progress::STEP_FAILED === $project_migrated ) {
|
||||
$project_migrated = $this->remote_migration->migrate_project( $project->id, $project->access_key, $token );
|
||||
}
|
||||
|
||||
return (bool) $project_migrated;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $project
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function acknowledge_icl( $project ) {
|
||||
$icl_acknowledged = $this->progress->get_completed_step( WPML_TM_ICL20_Migration_Progress::STEP_ICL_ACK );
|
||||
if ( WPML_TM_ICL20_Migration_Progress::STEP_FAILED === $icl_acknowledged ) {
|
||||
$icl_acknowledged = $this->remote_migration->acknowledge_icl( $project->ts_id, $project->ts_access_key );
|
||||
}
|
||||
|
||||
return (bool) $icl_acknowledged;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $token
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function migrate_local_service( $token ) {
|
||||
$service_migrated = $this->progress->get_completed_step( WPML_TM_ICL20_Migration_Progress::STEP_MIGRATE_LOCAL_SERVICE );
|
||||
if ( WPML_TM_ICL20_Migration_Progress::STEP_DONE === $service_migrated ) {
|
||||
$current_service = $this->tp_services->get_current_service();
|
||||
$service_migrated = $current_service && $this->status->get_ICL_20_TS_ID() === $current_service->id;
|
||||
}
|
||||
if ( WPML_TM_ICL20_Migration_Progress::STEP_FAILED === $service_migrated ) {
|
||||
$service_migrated = $this->local_migration->migrate_service( $token );
|
||||
}
|
||||
|
||||
return (bool) $service_migrated;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function migrate_local_project() {
|
||||
$project_migrated = $this->progress->get_completed_step( WPML_TM_ICL20_Migration_Progress::STEP_MIGRATE_LOCAL_PROJECT );
|
||||
if ( WPML_TM_ICL20_Migration_Progress::STEP_FAILED === $project_migrated ) {
|
||||
$project_migrated = $this->local_migration->migrate_project();
|
||||
}
|
||||
|
||||
return (bool) $project_migrated;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $table
|
||||
* @param string $step
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function migrate_local_jobs( $table, $step ) {
|
||||
$job_migrated = $this->progress->get_completed_step( $step );
|
||||
|
||||
if ( WPML_TM_ICL20_Migration_Progress::STEP_FAILED === $job_migrated ) {
|
||||
$job_migrated = $this->local_migration->migrate_jobs( $table );
|
||||
}
|
||||
|
||||
return (bool) $job_migrated;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_TM_ICL20_Migration_AJAX extends WPML_TM_AJAX {
|
||||
/** @var WPML_TM_ICL20_Migration_Progress */
|
||||
private $progress;
|
||||
|
||||
/**
|
||||
* WPML_TM_ICL20_Migration_AJAX constructor.
|
||||
*
|
||||
* @param WPML_TM_ICL20_Migration_Progress $progress
|
||||
*/
|
||||
public function __construct( WPML_TM_ICL20_Migration_Progress $progress ) {
|
||||
$this->progress = $progress;
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX callback used to set the user confirmation for starting the migration
|
||||
*/
|
||||
public function user_confirmation() {
|
||||
if ( $this->is_valid_request() ) {
|
||||
$this->progress->set_user_confirmed();
|
||||
wp_send_json_success();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
|
||||
class WPML_TM_ICL20MigrationException extends WPMLTranslationProxyApiException {
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_TM_ICL20_Migration_Factory {
|
||||
/**
|
||||
* @var WPML_TM_ICL20_Migration_Notices
|
||||
*/
|
||||
private $notices;
|
||||
/**
|
||||
* @var WPML_TM_ICL20_Migration_Progress
|
||||
*/
|
||||
private $progress;
|
||||
/**
|
||||
* @var WPML_TM_ICL20_Migration_Status
|
||||
*/
|
||||
private $status;
|
||||
/**
|
||||
* @var WPML_TP_Services
|
||||
*/
|
||||
private $tp_services;
|
||||
/**
|
||||
* @var WP_Http
|
||||
*/
|
||||
private $wp_http;
|
||||
|
||||
/**
|
||||
* @return WPML_TM_ICL20_Migration_AJAX
|
||||
*/
|
||||
public function create_ajax() {
|
||||
return new WPML_TM_ICL20_Migration_AJAX( $this->create_progress() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_TM_ICL20_Migration_Locks
|
||||
*/
|
||||
public function create_locks() {
|
||||
return new WPML_TM_ICL20_Migration_Locks( $this->create_progress() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_TM_ICL20_Migration_Progress
|
||||
*/
|
||||
public function create_progress() {
|
||||
if ( null === $this->progress ) {
|
||||
$this->progress = new WPML_TM_ICL20_Migration_Progress();
|
||||
}
|
||||
|
||||
return $this->progress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_TM_ICL20_Migrate
|
||||
*/
|
||||
public function create_migration() {
|
||||
return new WPML_TM_ICL20_Migrate(
|
||||
$this->create_progress(),
|
||||
$this->create_status(),
|
||||
$this->get_remote_migration(),
|
||||
$this->get_local_migration(),
|
||||
$this->get_tp_services()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_TM_ICL20_Migration_Status
|
||||
*/
|
||||
public function create_status() {
|
||||
if ( null === $this->status ) {
|
||||
$current_service = $this->get_tp_services()->get_current_service();
|
||||
$this->status = new WPML_TM_ICL20_Migration_Status( $current_service );
|
||||
}
|
||||
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_TM_ICL20_Migrate_Remote
|
||||
*/
|
||||
private function get_remote_migration() {
|
||||
$http = $this->get_wp_http();
|
||||
$token = new WPML_TM_ICL20_Token( $http, ICL_API_ENDPOINT );
|
||||
$project = new WPML_TM_ICL20_Project( $http, OTG_TRANSLATION_PROXY_URL );
|
||||
$ack = new WPML_TM_ICL20_Acknowledge( $http, ICL_API_ENDPOINT );
|
||||
|
||||
$container = new WPML_TM_ICL20_Migration_Container( $token, $project, $ack );
|
||||
|
||||
return new WPML_TM_ICL20_Migrate_Remote( $this->create_progress(), $container );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_TM_ICL20_Migrate_Local
|
||||
*/
|
||||
private function get_local_migration() {
|
||||
return new WPML_TM_ICL20_Migrate_Local(
|
||||
$this->get_tp_services(),
|
||||
$this->create_status(),
|
||||
$this->create_progress(),
|
||||
$this->get_sitepress()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_TP_Services
|
||||
*/
|
||||
private function get_tp_services() {
|
||||
if ( null === $this->tp_services ) {
|
||||
$this->tp_services = new WPML_TP_Services();
|
||||
}
|
||||
|
||||
return $this->tp_services;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WP_Http
|
||||
*/
|
||||
private function get_wp_http() {
|
||||
if ( null === $this->wp_http ) {
|
||||
$this->wp_http = new WP_Http();
|
||||
}
|
||||
|
||||
return $this->wp_http;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SitePress
|
||||
*/
|
||||
private function get_sitepress() {
|
||||
global $sitepress;
|
||||
|
||||
return $sitepress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_TM_ICL20_Migration_Notices
|
||||
*/
|
||||
public function create_notices() {
|
||||
if ( null === $this->notices ) {
|
||||
$this->notices = new WPML_TM_ICL20_Migration_Notices( $this->create_progress(), wpml_get_admin_notices() );
|
||||
}
|
||||
|
||||
return $this->notices;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_TM_ICL20_Migration_Support
|
||||
*/
|
||||
public function create_ui_support() {
|
||||
$template_paths = array(
|
||||
WPML_TM_PATH . '/templates/support/icl20/migration/',
|
||||
);
|
||||
|
||||
$template_loader = new WPML_Twig_Template_Loader( $template_paths );
|
||||
$template_service = $template_loader->get_template();
|
||||
|
||||
return new WPML_TM_ICL20_Migration_Support( $template_service, $this->create_progress(), $this->can_rollback() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function can_rollback() {
|
||||
return defined( 'WP_DEBUG' )
|
||||
&& defined( 'WPML_TP_ICL_20_ENABLE_ROLLBACK' )
|
||||
&& WP_DEBUG
|
||||
&& WPML_TP_ICL_20_ENABLE_ROLLBACK;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_TM_ICL20_Migration_Loader {
|
||||
/** @var WPML_TM_ICL20_Migration_Factory */
|
||||
private $factory;
|
||||
/** @var WPML_TM_ICL20_Migration_Progress */
|
||||
private $progress;
|
||||
/** @var WPML_TM_ICL20_Migration_Status */
|
||||
private $status;
|
||||
/** @var WPML_WP_API */
|
||||
private $wp_api;
|
||||
|
||||
/**
|
||||
* WPML_TM_ICL20_Migration_Loader constructor.
|
||||
*
|
||||
* @param WPML_WP_API $wp_api
|
||||
* @param WPML_TM_ICL20_Migration_Factory $factory
|
||||
*/
|
||||
public function __construct( WPML_WP_API $wp_api, WPML_TM_ICL20_Migration_Factory $factory ) {
|
||||
$this->wp_api = $wp_api;
|
||||
$this->factory = $factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the main method which deals with the whole logic for handling the migration
|
||||
*/
|
||||
public function run() {
|
||||
$this->status = $this->factory->create_status();
|
||||
$this->progress = $this->factory->create_progress();
|
||||
|
||||
$requires_migration = $this->requires_migration();
|
||||
|
||||
$notices = $this->factory->create_notices();
|
||||
$notices->clear_migration_required();
|
||||
|
||||
if ( $this->status->has_active_service() ) {
|
||||
$notices->run( $requires_migration );
|
||||
}
|
||||
|
||||
if ( $requires_migration ) {
|
||||
if ( ! $this->progress->get_user_confirmed() ) {
|
||||
add_action(
|
||||
'wp_ajax_' . WPML_TM_ICL20_Migration_Support::PREFIX . 'user_confirm',
|
||||
array( $this->factory->create_ajax(), 'user_confirmation' )
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $this->is_back_end() ) {
|
||||
$this->maybe_fix_preferred_service();
|
||||
$migration = $this->factory->create_migration();
|
||||
|
||||
if ( $this->factory->can_rollback() ) {
|
||||
add_action(
|
||||
'wpml_tm_icl20_migration_rollback',
|
||||
array( $migration, 'migrate_project_rollback' )
|
||||
);
|
||||
}
|
||||
|
||||
$support = $this->factory->create_ui_support();
|
||||
$support->add_hooks();
|
||||
$support->parse_request();
|
||||
|
||||
if ( ! $this->progress->are_next_automatic_attempts_locked() ) {
|
||||
$notices->run( ! $migration->run() );
|
||||
}
|
||||
|
||||
if ( ! $this->progress->is_migration_done() ) {
|
||||
$locks = $this->factory->create_locks();
|
||||
$locks->add_hooks();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @return bool */
|
||||
private function is_back_end() {
|
||||
return $this->wp_api->is_admin()
|
||||
&& ! $this->wp_api->is_ajax()
|
||||
&& ! $this->wp_api->is_cron_job()
|
||||
&& ! $this->wp_api->is_heartbeat();
|
||||
}
|
||||
|
||||
/** @return bool */
|
||||
private function requires_migration() {
|
||||
if ( $this->status->has_active_legacy_icl() ) {
|
||||
return true;
|
||||
}
|
||||
if ( $this->status->has_active_icl_20() ) {
|
||||
if ( $this->progress->is_migration_incomplete() ) {
|
||||
return true;
|
||||
}
|
||||
$this->progress->set_migration_done();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the website is set to use a preferred translation service which is the legacy ICL, it will replace it with
|
||||
* ICL2.0
|
||||
*/
|
||||
private function maybe_fix_preferred_service() {
|
||||
if ( $this->status->is_preferred_service_legacy_ICL() ) {
|
||||
$this->status->set_preferred_service_to_ICL20();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_TM_ICL20_Migration_Progress {
|
||||
const MAX_AUTOMATIC_ATTEMPTS = 5;
|
||||
const OPTION_KEY_USER_CONFIRMED = '_wpml_icl20_migration_user_confirmed';
|
||||
const OPTION_KEY_MIGRATION_ATTEMPTS = '_wpml_icl20_migration_attempts';
|
||||
const OPTION_KEY_MIGRATION_LAST_ATTEMPT = '_wpml_icl20_migration_last_attempt';
|
||||
const OPTION_KEY_MIGRATION_LAST_ERROR = '_wpml_icl20_migration_last_error';
|
||||
const OPTION_KEY_MIGRATION_LOCAL_PROJECT_INDEX = '_wpml_icl20_migration_local_project_index';
|
||||
const OPTION_KEY_MIGRATION_LOCKED = '_wpml_icl20_migration_locked';
|
||||
const OPTION_KEY_MIGRATION_REQUIRED = '_wpml_icl20_migration_required';
|
||||
const OPTION_KEY_MIGRATION_STEPS = '_wpml_icl20_migration_step_%s';
|
||||
const STEP_ICL_ACK = 'icl_ack';
|
||||
const STEP_MIGRATE_JOBS_DOCUMENTS = 'migrate_jobs_doc';
|
||||
const STEP_MIGRATE_JOBS_STRINGS = 'migrate_jobs_strings';
|
||||
const STEP_MIGRATE_LOCAL_PROJECT = 'migrate_local_project';
|
||||
const STEP_MIGRATE_LOCAL_SERVICE = 'migrate_local_service';
|
||||
const STEP_MIGRATE_REMOTE_PROJECT = 'migrate_remote_project';
|
||||
const STEP_TOKEN = 'token';
|
||||
const STEP_FAILED = 'failed';
|
||||
const STEP_DONE = 'done';
|
||||
const VALUE_YES = 'yes';
|
||||
const VALUE_NO = 'no';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $steps;
|
||||
|
||||
/**
|
||||
* WPML_TM_ICL20_Migration_Progress constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->steps = array(
|
||||
self::STEP_TOKEN,
|
||||
self::STEP_MIGRATE_REMOTE_PROJECT,
|
||||
self::STEP_ICL_ACK,
|
||||
self::STEP_MIGRATE_LOCAL_SERVICE,
|
||||
self::STEP_MIGRATE_LOCAL_PROJECT,
|
||||
self::STEP_MIGRATE_JOBS_DOCUMENTS,
|
||||
self::STEP_MIGRATE_JOBS_STRINGS,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $step
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_completed_step( $step ) {
|
||||
return get_option( sprintf( self::OPTION_KEY_MIGRATION_STEPS, $step ), self::STEP_FAILED );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|null
|
||||
*/
|
||||
public function get_last_attempt_timestamp() {
|
||||
return get_option( self::OPTION_KEY_MIGRATION_LAST_ATTEMPT, null );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_last_migration_error() {
|
||||
return get_option( self::OPTION_KEY_MIGRATION_LAST_ERROR, null );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_project_to_migrate() {
|
||||
return get_option( self::OPTION_KEY_MIGRATION_LOCAL_PROJECT_INDEX, null );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function get_steps() {
|
||||
return $this->steps;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
*/
|
||||
public function log_failed_attempt( $message ) {
|
||||
$this->update_last_error( $message );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
*/
|
||||
private function update_last_error( $message ) {
|
||||
update_option( self::OPTION_KEY_MIGRATION_LAST_ERROR, $message, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function is_migration_incomplete() {
|
||||
return $this->get_current_attempts_count() > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $step
|
||||
* @param string|bool $value
|
||||
*/
|
||||
public function set_completed_step( $step, $value ) {
|
||||
$step_value = $value;
|
||||
if ( is_bool( $value ) ) {
|
||||
$step_value = $value ? self::STEP_DONE : self::STEP_FAILED;
|
||||
}
|
||||
update_option( sprintf( self::OPTION_KEY_MIGRATION_STEPS, $step ), $step_value, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function has_migration_ever_started() {
|
||||
$this->requires_migration();
|
||||
$notoptions = wp_cache_get( 'notoptions', 'options' );
|
||||
if ( isset( $notoptions[ self::OPTION_KEY_MIGRATION_REQUIRED ] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* It will mark the migration as done
|
||||
*/
|
||||
public function set_migration_done() {
|
||||
update_option( self::OPTION_KEY_MIGRATION_REQUIRED, self::VALUE_NO, false );
|
||||
$this->clear_temporary_options();
|
||||
}
|
||||
|
||||
/**
|
||||
* It will remove all the temporary options used to store the status of the migration
|
||||
*/
|
||||
public function clear_temporary_options() {
|
||||
$options = array(
|
||||
self::OPTION_KEY_MIGRATION_LOCKED,
|
||||
self::OPTION_KEY_MIGRATION_LAST_ERROR,
|
||||
self::OPTION_KEY_MIGRATION_ATTEMPTS,
|
||||
self::OPTION_KEY_MIGRATION_LAST_ATTEMPT,
|
||||
self::OPTION_KEY_MIGRATION_LOCAL_PROJECT_INDEX,
|
||||
);
|
||||
|
||||
foreach ( $options as $option ) {
|
||||
delete_option( $option );
|
||||
}
|
||||
|
||||
foreach ( $this->steps as $step ) {
|
||||
delete_option( sprintf( self::OPTION_KEY_MIGRATION_STEPS, $step ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function is_migration_done() {
|
||||
$result = true;
|
||||
if ( $this->requires_migration() ) {
|
||||
foreach ( $this->steps as $step ) {
|
||||
if ( self::STEP_DONE !== get_option(
|
||||
sprintf( self::OPTION_KEY_MIGRATION_STEPS, $step ),
|
||||
self::STEP_FAILED
|
||||
) ) {
|
||||
$result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function requires_migration() {
|
||||
return self::VALUE_YES === get_option( self::OPTION_KEY_MIGRATION_REQUIRED, self::VALUE_NO );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the migration as started so to know, in the next attempts, if the migration was partial or never started.
|
||||
*/
|
||||
public function set_migration_started() {
|
||||
update_option( self::OPTION_KEY_MIGRATION_REQUIRED, self::VALUE_YES, false );
|
||||
$this->increase_attempts_count();
|
||||
}
|
||||
|
||||
/**
|
||||
* It will increases on every migration attempt
|
||||
*/
|
||||
private function increase_attempts_count() {
|
||||
update_option(
|
||||
self::OPTION_KEY_MIGRATION_ATTEMPTS,
|
||||
$this->get_current_attempts_count() + 1,
|
||||
false
|
||||
);
|
||||
update_option(
|
||||
self::OPTION_KEY_MIGRATION_LAST_ATTEMPT,
|
||||
time(),
|
||||
false
|
||||
);
|
||||
if ( $this->has_too_many_automatic_attempts() ) {
|
||||
$this->block_next_automatic_attempts();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function get_current_attempts_count() {
|
||||
return (int) get_option( self::OPTION_KEY_MIGRATION_ATTEMPTS, 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function has_too_many_automatic_attempts() {
|
||||
return $this->get_current_attempts_count() >= self::MAX_AUTOMATIC_ATTEMPTS
|
||||
|| $this->are_next_automatic_attempts_locked();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used when too many attempts are made
|
||||
*/
|
||||
private function block_next_automatic_attempts() {
|
||||
update_option( self::OPTION_KEY_MIGRATION_LOCKED, self::VALUE_YES, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function are_next_automatic_attempts_locked() {
|
||||
return self::VALUE_YES === get_option( self::OPTION_KEY_MIGRATION_LOCKED, self::VALUE_NO );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $old_index
|
||||
*/
|
||||
public function set_project_to_migrate( $old_index ) {
|
||||
update_option( self::OPTION_KEY_MIGRATION_LOCAL_PROJECT_INDEX, $old_index, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function get_user_confirmed() {
|
||||
return self::VALUE_YES === get_option( self::OPTION_KEY_USER_CONFIRMED, self::VALUE_NO );
|
||||
}
|
||||
|
||||
/**
|
||||
* User as an opt-in action from the user before starting the migration
|
||||
*/
|
||||
public function set_user_confirmed() {
|
||||
update_option( self::OPTION_KEY_USER_CONFIRMED, self::VALUE_YES, false );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_TM_ICL20_Migration_Status {
|
||||
const ICL_20_TS_ID = 67;
|
||||
const ICL_LEGACY_TS_ID = 4;
|
||||
const ICL_LEGACY_TS_SUID = '6ab1000a33e2cc9ecbcf6abc57254be8';
|
||||
const ICL_20_TS_SUID = 'dd17d48516ca4bce0b83043583fabd2e';
|
||||
|
||||
private $installer_settings = array();
|
||||
private $service;
|
||||
|
||||
public function __construct( $service ) {
|
||||
$this->service = $service;
|
||||
}
|
||||
|
||||
public function has_active_legacy_icl() {
|
||||
return $this->has_active_service() && $this->get_ICL_LEGACY_TS_ID() === $this->service->id;
|
||||
}
|
||||
|
||||
public function has_active_icl_20() {
|
||||
return $this->has_active_service() && $this->get_ICL_20_TS_ID() === $this->service->id;
|
||||
}
|
||||
|
||||
public function has_active_service() {
|
||||
return (bool) $this->service;
|
||||
}
|
||||
|
||||
public function get_ICL_LEGACY_TS_ID() {
|
||||
if ( defined( 'WPML_TP_ICL_LEGACY_TS_ID' ) ) {
|
||||
return WPML_TP_ICL_LEGACY_TS_ID;
|
||||
}
|
||||
|
||||
return self::ICL_LEGACY_TS_ID;
|
||||
}
|
||||
|
||||
public function get_ICL_20_TS_ID() {
|
||||
if ( defined( 'WPML_TP_ICL_20_TS_ID' ) ) {
|
||||
return WPML_TP_ICL_20_TS_ID;
|
||||
}
|
||||
|
||||
return self::ICL_20_TS_ID;
|
||||
}
|
||||
|
||||
public function get_ICL_LEGACY_TS_SUID() {
|
||||
if ( defined( 'WPML_TP_ICL_LEGACY_TS_SUID' ) ) {
|
||||
return WPML_TP_ICL_LEGACY_TS_SUID;
|
||||
}
|
||||
|
||||
return self::ICL_LEGACY_TS_SUID;
|
||||
}
|
||||
|
||||
public function get_ICL_20_TS_SUID() {
|
||||
if ( defined( 'WPML_TP_ICL_20_TS_SUID' ) ) {
|
||||
return WPML_TP_ICL_20_TS_SUID;
|
||||
}
|
||||
|
||||
return self::ICL_20_TS_SUID;
|
||||
}
|
||||
|
||||
public function is_preferred_service_legacy_ICL() {
|
||||
return $this->has_preferred_service() && self::ICL_LEGACY_TS_SUID === $this->get_preferred_service();
|
||||
}
|
||||
|
||||
public function set_preferred_service_to_ICL20() {
|
||||
if ( $this->get_preferred_service() ) {
|
||||
$this->installer_settings['repositories']['wpml']['ts_info']['preferred'] = $this->get_ICL_20_TS_SUID();
|
||||
$this->update_installer_settings();
|
||||
}
|
||||
}
|
||||
|
||||
private function has_preferred_service() {
|
||||
return ! in_array( $this->get_preferred_service(), array( 'clear', false ), true );
|
||||
}
|
||||
|
||||
private function get_preferred_service() {
|
||||
$installer_settings = $this->get_installer_settings();
|
||||
if ( isset( $installer_settings['repositories']['wpml']['ts_info']['preferred'] )
|
||||
&& 'clear' !== $installer_settings['repositories']['wpml']['ts_info']['preferred'] ) {
|
||||
return $installer_settings['repositories']['wpml']['ts_info']['preferred'];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function get_installer_settings() {
|
||||
if ( ! $this->installer_settings ) {
|
||||
$raw_settings = get_option( 'wp_installer_settings', null );
|
||||
|
||||
if ( $raw_settings ) {
|
||||
if ( is_array( $raw_settings ) || empty( $raw_settings ) ) { // backward compatibility 1.1
|
||||
$this->installer_settings = $raw_settings;
|
||||
} else {
|
||||
$has_gz_support = function_exists( 'gzuncompress' ) && function_exists( 'gzcompress' );
|
||||
$raw_settings = base64_decode( $raw_settings );
|
||||
if ( $has_gz_support ) {
|
||||
$raw_settings = gzuncompress( $raw_settings );
|
||||
}
|
||||
/** @noinspection UnserializeExploitsInspection */
|
||||
$this->installer_settings = unserialize( $raw_settings );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->installer_settings;
|
||||
}
|
||||
|
||||
private function update_installer_settings() {
|
||||
$has_gz_support = function_exists( 'gzuncompress' ) && function_exists( 'gzcompress' );
|
||||
$raw_settings = serialize( $this->installer_settings );
|
||||
if ( $has_gz_support ) {
|
||||
$raw_settings = gzcompress( $raw_settings );
|
||||
}
|
||||
$raw_settings = base64_encode( $raw_settings );
|
||||
update_option( 'wp_installer_settings', $raw_settings );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_TM_ICL20_Acknowledge {
|
||||
private $end_point;
|
||||
private $http;
|
||||
|
||||
/**
|
||||
* WPML_TM_ICL20 constructor.
|
||||
*
|
||||
* @param WP_Http $http
|
||||
* @param string $end_point
|
||||
*/
|
||||
public function __construct( WP_Http $http, $end_point ) {
|
||||
$this->http = $http;
|
||||
$this->end_point = $end_point;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $ts_accesskey
|
||||
* @param int $ts_id
|
||||
*
|
||||
* @return bool
|
||||
* @throws \WPML_TM_ICL20MigrationException
|
||||
*
|
||||
* Note: `ts_id` (aka `website_id`) = `website_id`
|
||||
*
|
||||
* @link https://onthegosystems.myjetbrains.com/youtrack/issue/icldev-2322
|
||||
*/
|
||||
public function acknowledge_icl( $ts_id, $ts_accesskey ) {
|
||||
$url = $this->end_point . '/wpml/websites/' . $ts_id . '/migrated';
|
||||
$url = add_query_arg( array(
|
||||
'accesskey' => $ts_accesskey,
|
||||
),
|
||||
$url );
|
||||
|
||||
$response = $this->http->post( $url,
|
||||
array(
|
||||
'method' => 'POST',
|
||||
'headers' => array(
|
||||
'Accept' => 'application/json',
|
||||
'Content-Type' => 'application/json',
|
||||
),
|
||||
) );
|
||||
|
||||
$code = (int) $response['response']['code'];
|
||||
if ( $code !== 200 ) {
|
||||
throw new WPML_TM_ICL20MigrationException( $response['response']['message'], $code );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_TM_ICL20_Migration_Container {
|
||||
private $acknowledge;
|
||||
private $project;
|
||||
private $token;
|
||||
|
||||
public function __construct(
|
||||
WPML_TM_ICL20_Token $token,
|
||||
WPML_TM_ICL20_Project $project,
|
||||
WPML_TM_ICL20_Acknowledge $ack
|
||||
) {
|
||||
$this->token = $token;
|
||||
$this->project = $project;
|
||||
$this->acknowledge = $ack;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_TM_ICL20_Acknowledge
|
||||
*/
|
||||
public function get_acknowledge() {
|
||||
return $this->acknowledge;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_TM_ICL20_Project
|
||||
*/
|
||||
public function get_project() {
|
||||
return $this->project;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_TM_ICL20_Token
|
||||
*/
|
||||
public function get_token() {
|
||||
return $this->token;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_TM_ICL20_Project {
|
||||
private $end_point;
|
||||
private $http;
|
||||
|
||||
/**
|
||||
* WPML_TM_ICL20 constructor.
|
||||
*
|
||||
* @param WP_Http $http
|
||||
* @param string $end_point
|
||||
*/
|
||||
public function __construct( WP_Http $http, $end_point ) {
|
||||
$this->http = $http;
|
||||
$this->end_point = $end_point;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $project_id
|
||||
* @param string $access_key
|
||||
* @param string $new_token
|
||||
*
|
||||
* @return bool|null
|
||||
* @throws \WPML_TM_ICL20MigrationException
|
||||
* @link https://onthegosystems.myjetbrains.com/youtrack/issue/tsapi-887
|
||||
*
|
||||
*/
|
||||
public function migrate( $project_id, $access_key, $new_token ) {
|
||||
$url = $this->end_point . '/projects/' . $project_id . '/migrate_service.json';
|
||||
|
||||
$args = array(
|
||||
'method' => 'POST',
|
||||
'headers' => array(
|
||||
'Accept' => 'application/json',
|
||||
'Content-Type' => 'application/json',
|
||||
),
|
||||
'body' => wp_json_encode( array(
|
||||
'accesskey' => $access_key,
|
||||
'custom_fields' => array(
|
||||
'api_token' => $new_token,
|
||||
)
|
||||
) )
|
||||
);
|
||||
|
||||
$response = $this->http->post( $url, $args );
|
||||
|
||||
$code = (int) $response['response']['code'];
|
||||
if ( $code !== 200 ) {
|
||||
$message = $response['response']['message'];
|
||||
if ( array_key_exists( 'body', $response ) ) {
|
||||
$body = json_decode( $response['body'], JSON_OBJECT_AS_ARRAY );
|
||||
if ( isset( $body['status']['message'] ) ) {
|
||||
$message .= PHP_EOL . $body['status']['message'];
|
||||
}
|
||||
}
|
||||
|
||||
throw new WPML_TM_ICL20MigrationException( $message, $code );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $project_id
|
||||
* @param string $access_key
|
||||
*
|
||||
* @return bool
|
||||
* @throws WPML_TM_ICL20MigrationException
|
||||
*/
|
||||
public function rollback_migration( $project_id, $access_key ) {
|
||||
$url = $this->end_point . '/projects/' . $project_id . '/rollback_migration.json';
|
||||
|
||||
$args = array(
|
||||
'method' => 'POST',
|
||||
'headers' => array(
|
||||
'Accept' => 'application/json',
|
||||
'Content-Type' => 'application/json',
|
||||
),
|
||||
'body' => wp_json_encode( array( 'accesskey' => $access_key ) )
|
||||
);
|
||||
|
||||
$response = $this->http->post( $url, $args );
|
||||
|
||||
$code = (int) $response['response']['code'];
|
||||
if ( $code !== 200 ) {
|
||||
$message = $response['response']['message'];
|
||||
if ( array_key_exists( 'body', $response ) ) {
|
||||
$body = json_decode( $response['body'], JSON_OBJECT_AS_ARRAY );
|
||||
if ( isset( $body['status']['message'] ) ) {
|
||||
$message .= PHP_EOL . $body['status']['message'];
|
||||
}
|
||||
}
|
||||
|
||||
throw new WPML_TM_ICL20MigrationException( $message, $code );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_TM_ICL20_Token {
|
||||
private $end_point;
|
||||
private $http;
|
||||
|
||||
/**
|
||||
* WPML_TM_ICL20 constructor.
|
||||
*
|
||||
* @param WP_Http $http
|
||||
* @param string $end_point
|
||||
*/
|
||||
public function __construct( WP_Http $http, $end_point ) {
|
||||
$this->http = $http;
|
||||
$this->end_point = $end_point;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $ts_accesskey
|
||||
* @param int $ts_id
|
||||
*
|
||||
* @return string|null
|
||||
* @throws \WPML_TM_ICL20MigrationException
|
||||
*
|
||||
* Note: `ts_id` (aka `website_id`) = `website_id`
|
||||
*
|
||||
* @link https://onthegosystems.myjetbrains.com/youtrack/issue/icldev-2285
|
||||
*/
|
||||
public function get_token( $ts_id, $ts_accesskey ) {
|
||||
if ( ! $ts_id ) {
|
||||
throw new WPML_TM_ICL20MigrationException( 'Missing ICL Website ID ($ts_id)' );
|
||||
}
|
||||
if ( ! $ts_accesskey ) {
|
||||
throw new WPML_TM_ICL20MigrationException( 'Missing ICL Access KEY ($ts_accesskey)' );
|
||||
}
|
||||
|
||||
$url = $this->end_point . '/wpml/websites/' . $ts_id . '/token';
|
||||
$url = add_query_arg( array(
|
||||
'accesskey' => $ts_accesskey,
|
||||
),
|
||||
$url );
|
||||
|
||||
$response = $this->http->get( $url,
|
||||
array(
|
||||
'method' => 'GET',
|
||||
'headers' => array(
|
||||
'Accept: application/json'
|
||||
),
|
||||
) );
|
||||
|
||||
$code = (int) $response['response']['code'];
|
||||
if ( 200 !== $code ) {
|
||||
throw new WPML_TM_ICL20MigrationException( $response['response']['message'], $code );
|
||||
}
|
||||
|
||||
if ( array_key_exists( 'body', $response ) ) {
|
||||
$response_data = json_decode( $response['body'], JSON_OBJECT_AS_ARRAY );
|
||||
|
||||
if ( array_key_exists( 'api_token', $response_data )
|
||||
&& '' !== trim( $response_data['api_token'] ) ) {
|
||||
return $response_data['api_token'];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*globals jQuery, ajaxurl */
|
||||
jQuery(function () {
|
||||
'use strict';
|
||||
|
||||
var notice = jQuery('[data-id="icl-20-migration"][data-group="icl-20-migration"]');
|
||||
var confirm;
|
||||
var startButton;
|
||||
|
||||
var updateButton = function () {
|
||||
if (confirm.prop('checked')) {
|
||||
startButton.removeClass('disabled');
|
||||
startButton.on('click', userConfirms);
|
||||
} else {
|
||||
startButton.addClass('disabled');
|
||||
startButton.off('click');
|
||||
}
|
||||
};
|
||||
|
||||
var userConfirms = function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
if (confirm.prop('checked')) {
|
||||
jQuery.ajax(ajaxurl, {
|
||||
method: 'POST',
|
||||
data: {
|
||||
action: confirm.data('action'),
|
||||
nonce: confirm.data('nonce')
|
||||
},
|
||||
complete: function () {
|
||||
location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (notice.length) {
|
||||
confirm = notice.find('#wpml-icl20-migrate-confirm');
|
||||
startButton = notice.find('.notice-action.button-secondary.notice-action-button-secondary');
|
||||
|
||||
if (confirm.length && startButton.length) {
|
||||
updateButton();
|
||||
confirm.on('click', updateButton);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_TM_ICL20_Migration_Locks {
|
||||
private $progress;
|
||||
|
||||
public function __construct( WPML_TM_ICL20_Migration_Progress $progress ) {
|
||||
$this->progress = $progress;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
if ( ! $this->progress->is_migration_done() ) {
|
||||
add_filter( 'wpml_tm_lock_ui', '__return_true' );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,285 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_TM_ICL20_Migration_Notices {
|
||||
const NOTICE_GROUP = 'icl-20-migration';
|
||||
const NOTICE_MIGRATION_REQUIRED_ID = 'icl-20-migration';
|
||||
const NOTICE_MIGRATION_COMPLETED_ID = 'icl-20-migration-completed';
|
||||
/**
|
||||
* @var WPML_Notices
|
||||
*/
|
||||
private $notices;
|
||||
/**
|
||||
* @var WPML_TM_ICL20_Migration_Progress
|
||||
*/
|
||||
private $progress;
|
||||
|
||||
/**
|
||||
* WPML_TM_ICL20_Migration_Notices constructor.
|
||||
*
|
||||
* @param WPML_TM_ICL20_Migration_Progress $progress
|
||||
* @param WPML_Notices $notices
|
||||
*/
|
||||
public function __construct( WPML_TM_ICL20_Migration_Progress $progress, WPML_Notices $notices ) {
|
||||
$this->progress = $progress;
|
||||
$this->notices = $notices;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $requires_migration
|
||||
*/
|
||||
public function run( $requires_migration = false ) {
|
||||
$this->clear_migration_required();
|
||||
|
||||
$ever_started = $this->progress->has_migration_ever_started();
|
||||
|
||||
if ( $ever_started && ! $this->progress->requires_migration() ) {
|
||||
$this->build_migration_completed();
|
||||
} else {
|
||||
if ( ! $ever_started
|
||||
&& $requires_migration
|
||||
&& ! $this->progress->is_migration_incomplete() ) {
|
||||
$this->build_migration_required();
|
||||
add_action( 'wpml-notices-scripts-enqueued', array( $this, 'admin_enqueue_scripts' ) );
|
||||
|
||||
return;
|
||||
}
|
||||
if ( $ever_started && ! $this->progress->is_migration_done() ) {
|
||||
$this->build_migration_failed();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all notices created before and during the migration
|
||||
*/
|
||||
public function clear_migration_required() {
|
||||
$this->notices->remove_notice( self::NOTICE_GROUP, self::NOTICE_MIGRATION_REQUIRED_ID );
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the notice shown if the migration fails
|
||||
*/
|
||||
private function build_migration_failed() {
|
||||
$message = array();
|
||||
$actions = array();
|
||||
|
||||
$title = '<h3>' . esc_html__(
|
||||
'ICanLocalize migration could not complete',
|
||||
'wpml-translation-management'
|
||||
) . '</h3>';
|
||||
$message[] = esc_html__(
|
||||
'WPML needs to update your connection to ICanLocalize, but could not complete the change.',
|
||||
'wpml-translation-management'
|
||||
);
|
||||
|
||||
$locked = $this->progress->are_next_automatic_attempts_locked();
|
||||
if ( $locked ) {
|
||||
$message[] = esc_html__(
|
||||
'Please contact WPML support and give them the following debug information:',
|
||||
'wpml-translation-management'
|
||||
);
|
||||
|
||||
$error = '<pre>';
|
||||
foreach ( $this->progress->get_steps() as $step ) {
|
||||
$completed_step = $this->progress->get_completed_step( $step );
|
||||
if ( ! $completed_step || WPML_TM_ICL20_Migration_Progress::STEP_FAILED === $completed_step ) {
|
||||
$error .= esc_html(
|
||||
sprintf(
|
||||
__(
|
||||
'Failed step: %s',
|
||||
'wpml-translation-management'
|
||||
),
|
||||
$step
|
||||
)
|
||||
) . PHP_EOL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$error .= esc_html( $this->progress->get_last_migration_error() );
|
||||
$error .= '</pre>';
|
||||
$message[] = $error;
|
||||
} else {
|
||||
$message[] = esc_html__(
|
||||
'Please wait a few minutes and try again to see if there’s a temporary problem.',
|
||||
'wpml-translation-management'
|
||||
);
|
||||
}
|
||||
|
||||
$text = $title . '<p>' . implode( '</p><p>', $message ) . '</p>';
|
||||
|
||||
$button_label = __( 'Try again', 'wpml-translation-management' );
|
||||
$button_url = add_query_arg(
|
||||
array(
|
||||
WPML_TM_ICL20_Migration_Support::PREFIX
|
||||
. 'nonce' => wp_create_nonce(
|
||||
WPML_TM_ICL20_Migration_Support::PREFIX
|
||||
. 'reset'
|
||||
),
|
||||
WPML_TM_ICL20_Migration_Support::PREFIX
|
||||
. 'action' => WPML_TM_ICL20_Migration_Support::PREFIX
|
||||
. 'reset',
|
||||
)
|
||||
) . '#icl20-migration';
|
||||
|
||||
$retry_action = $this->notices->get_new_notice_action( $button_label, $button_url, false, false, true );
|
||||
|
||||
$actions[] = $retry_action;
|
||||
|
||||
if ( $locked ) {
|
||||
$wpml_support_action = $this->notices->get_new_notice_action(
|
||||
__(
|
||||
'WPML Support',
|
||||
'wpml-translation-management'
|
||||
),
|
||||
'https://wpml.org/forums/'
|
||||
);
|
||||
$wpml_support_action->set_link_target( '_blank' );
|
||||
|
||||
$actions[] = $wpml_support_action;
|
||||
} else {
|
||||
$support_url = add_query_arg(
|
||||
array(
|
||||
'page' => WPML_PLUGIN_FOLDER . '/menu/support.php',
|
||||
),
|
||||
admin_url( 'admin.php' )
|
||||
) . '#icl20-migration';
|
||||
|
||||
$action = $this->notices->get_new_notice_action(
|
||||
__(
|
||||
'Error details',
|
||||
'wpml-translation-management'
|
||||
),
|
||||
$support_url
|
||||
);
|
||||
$actions[] = $action;
|
||||
}
|
||||
|
||||
$this->create_notice( $text, $actions );
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the notice shown when the migration is required
|
||||
*/
|
||||
private function build_migration_required() {
|
||||
$message = array();
|
||||
$actions = array();
|
||||
|
||||
$link_pattern = '<a href="%1$s" target="_blank">%2$s</a>';
|
||||
$ask_us_link = sprintf(
|
||||
$link_pattern,
|
||||
'https://wpml.org/forums/topic/im-not-sure-if-i-need-to-run-icanlocalize-migration/?utm_source=plugin&utm_medium=gui&utm_campaign=wpmltm',
|
||||
esc_html__( 'Ask us', 'wpml-translation-management' )
|
||||
);
|
||||
|
||||
$button_label = esc_html__( 'Start the update', 'wpml-translation-management' );
|
||||
|
||||
$title = '<h3>WPML needs to update your ICanLocalize account settings</h3>';
|
||||
|
||||
$message[] = esc_html__(
|
||||
'WPML 3.9 changes the way it works with ICanLocalize. This requires WPML to move to a new interface with ICanLocalize.',
|
||||
'wpml-translation-management'
|
||||
);
|
||||
$message[] = esc_html__(
|
||||
'If you are in a production site, you have to run this update before you can send more content for translation and receive completed translations.',
|
||||
'wpml-translation-management'
|
||||
);
|
||||
$message[] = esc_html__(
|
||||
"If this is not your production site (it's a staging or testing site), please do not run the update.",
|
||||
'wpml-translation-management'
|
||||
);
|
||||
$message[] = esc_html__(
|
||||
'Running this update on a non-production site will make it impossible to correctly run it on the production site.',
|
||||
'wpml-translation-management'
|
||||
);
|
||||
$message[] = '';
|
||||
$message[] = sprintf( esc_html__( 'Not sure? %s.', 'wpml-translation-management' ), $ask_us_link );
|
||||
$message[] = '';
|
||||
|
||||
$message[] = $this->get_user_confirmation_input();
|
||||
|
||||
$text = $title . '<p>' . implode( '</p><p>', $message ) . '</p>';
|
||||
|
||||
$actions[] = $this->notices->get_new_notice_action( $button_label, '#', false, false, true );
|
||||
|
||||
$this->create_notice( $text, $actions );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $text
|
||||
* @param array $actions
|
||||
*/
|
||||
private function create_notice( $text, array $actions = array() ) {
|
||||
$notice = $this->notices->create_notice( self::NOTICE_MIGRATION_REQUIRED_ID, $text, self::NOTICE_GROUP );
|
||||
|
||||
$notice->set_css_class_types( array( 'error' ) );
|
||||
|
||||
$notice->set_exclude_from_pages(
|
||||
array(
|
||||
'sitepress-multilingual-cms/menu/support.php',
|
||||
)
|
||||
);
|
||||
|
||||
foreach ( $actions as $action ) {
|
||||
$notice->add_action( $action );
|
||||
}
|
||||
|
||||
$this->notices->add_notice( $notice );
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the notice shown when the migration completes
|
||||
*/
|
||||
private function build_migration_completed() {
|
||||
$message = array();
|
||||
|
||||
$message[] = esc_html__(
|
||||
'WPML updated your connection to ICanLocalize. You can continue sending content to translation.',
|
||||
'wpml-translation-management'
|
||||
);
|
||||
|
||||
$text = '<p>' . implode( '</p><p>', $message ) . '</p>';
|
||||
|
||||
$notice = $this->notices->create_notice( self::NOTICE_MIGRATION_COMPLETED_ID, $text, self::NOTICE_GROUP );
|
||||
$notice->set_css_class_types( array( 'warning' ) );
|
||||
$notice->set_exclude_from_pages(
|
||||
array(
|
||||
'sitepress-multilingual-cms/menu/support.php',
|
||||
)
|
||||
);
|
||||
$notice->set_dismissible( true );
|
||||
|
||||
$this->notices->add_notice( $notice );
|
||||
}
|
||||
|
||||
/**
|
||||
* Required by `\WPML_TM_ICL20_Migration_Notices::build_migration_required`
|
||||
*/
|
||||
public function admin_enqueue_scripts() {
|
||||
wp_enqueue_script(
|
||||
'wpml-icl20-migrate-confirm',
|
||||
WPML_TM_URL . '/classes/ICL-20-migration/res/migration-required.js'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private function get_user_confirmation_input() {
|
||||
$id = 'wpml-icl20-migrate-confirm';
|
||||
|
||||
$label = esc_html__( 'This is indeed my production site', 'wpml-translation-management' );
|
||||
|
||||
$data_action = esc_attr( WPML_TM_ICL20_Migration_Support::PREFIX . 'user_confirm' );
|
||||
$data_nonce = esc_attr( wp_create_nonce( WPML_TM_ICL20_Migration_Support::PREFIX . 'user_confirm' ) );
|
||||
|
||||
$html_pattern = '<input type="checkbox" value="1" id="%1$s" data-action="%2$s" data-nonce="%3$s"><label for="%1$s">%4$s</label>';
|
||||
|
||||
return sprintf( $html_pattern, $id, $data_action, $data_nonce, $label );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_TM_ICL20_Migration_Support {
|
||||
const PREFIX = 'icl20-migration-reset-';
|
||||
const TIMESTAMP_FORMAT = 'Y-m-d H:i:s';
|
||||
|
||||
private $can_rollback;
|
||||
private $progress;
|
||||
private $template_service;
|
||||
|
||||
function __construct(
|
||||
IWPML_Template_Service $template_service,
|
||||
WPML_TM_ICL20_Migration_Progress $progress,
|
||||
$can_rollback = false
|
||||
) {
|
||||
$this->template_service = $template_service;
|
||||
$this->progress = $progress;
|
||||
$this->can_rollback = $can_rollback;
|
||||
}
|
||||
|
||||
function add_hooks() {
|
||||
add_action( 'wpml_support_page_after', array( $this, 'show' ) );
|
||||
}
|
||||
|
||||
public function parse_request() {
|
||||
$nonce_arg = self::PREFIX . 'nonce';
|
||||
$action_arg = self::PREFIX . 'action';
|
||||
|
||||
if ( array_key_exists( $nonce_arg, $_GET ) && array_key_exists( $action_arg, $_GET ) ) {
|
||||
$nonce = filter_var( $_GET[ $nonce_arg ] );
|
||||
$action = filter_var( $_GET[ $action_arg ] );
|
||||
|
||||
if ( wp_verify_nonce( $nonce, $action ) ) {
|
||||
if ( self::PREFIX . 'reset' === $action ) {
|
||||
update_option( WPML_TM_ICL20_Migration_Progress::OPTION_KEY_MIGRATION_LOCKED, false, false );
|
||||
}
|
||||
if ( self::PREFIX . 'rollback' === $action && $this->can_rollback ) {
|
||||
do_action( 'wpml_tm_icl20_migration_rollback' );
|
||||
}
|
||||
}
|
||||
|
||||
$redirect_to = remove_query_arg( array( $nonce_arg, $action_arg ) );
|
||||
wp_safe_redirect( $redirect_to, 302, 'WPML' );
|
||||
}
|
||||
}
|
||||
|
||||
public function show() {
|
||||
$model = $this->get_model();
|
||||
|
||||
echo $this->template_service->show( $model, 'main.twig' );
|
||||
}
|
||||
|
||||
private function get_model() {
|
||||
|
||||
$reset_target_url = add_query_arg( array(
|
||||
self::PREFIX . 'nonce' => wp_create_nonce( self::PREFIX . 'reset' ),
|
||||
self::PREFIX . 'action' => self::PREFIX . 'reset',
|
||||
) );
|
||||
$reset_target_url .= '#icl20-migration';
|
||||
|
||||
$model = array(
|
||||
'title' => __( 'Migration to ICL 2.0', 'wpml-translation-management' ),
|
||||
'data' => array(
|
||||
__( 'Number of attempts made',
|
||||
'wpml-translation-management' ) => $this->progress->get_current_attempts_count(),
|
||||
__( 'Last attempt was on',
|
||||
'wpml-translation-management' ) => date( self::TIMESTAMP_FORMAT,
|
||||
$this->progress->get_last_attempt_timestamp() ),
|
||||
__( 'Last error', 'wpml-translation-management' ) => $this->progress->get_last_migration_error(),
|
||||
),
|
||||
'buttons' => array(
|
||||
'reset' => array(
|
||||
'type' => 'primary',
|
||||
'label' => __( 'Try again', 'wpml-translation-management' ),
|
||||
'url' => $reset_target_url,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
if ( $this->can_rollback ) {
|
||||
$rollback_target_url = add_query_arg( array(
|
||||
self::PREFIX . 'nonce' => wp_create_nonce( self::PREFIX
|
||||
. 'rollback' ),
|
||||
self::PREFIX . 'action' => self::PREFIX . 'rollback',
|
||||
) );
|
||||
$model['buttons']['rollback'] = array(
|
||||
'type' => 'secondary',
|
||||
'label' => __( 'Rollback migration (use at your own risk!)',
|
||||
'wpml-translation-management' ),
|
||||
'url' => $rollback_target_url,
|
||||
);
|
||||
}
|
||||
|
||||
return $model;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user