do_something()
*
* @return US_Migration
*/
public static function instance() {
if ( ! isset( self::$instance ) ) {
self::$instance = new US_Migration;
}
return self::$instance;
}
/**
* @var array List of migration classes instances $version => $instance
*/
public $translators = array();
public $current_translator;
protected function __construct() {
global $us_template_directory;
// Get the current DB version
$db_version = $this->get_db_version();
// Get available migrations (should be set by the theme's us_config_migrations filter) and keep only the needed ones
$migrations = array();
foreach ( us_config( 'migrations', array() ) as $migration_version => $migration_file ) {
if ( version_compare( $db_version, $migration_version, '<' ) ) {
$class = basename( $migration_file, '.php' );
if ( file_exists( trailingslashit( $us_template_directory ) . $migration_file ) ) {
include trailingslashit( $us_template_directory ) . $migration_file;
} elseif ( WP_DEBUG ) {
wp_die( 'Defined migration file not found: ' . trailingslashit( $us_template_directory ) . $migration_file );
}
if ( class_exists( $class ) ) {
$this->translators[ $migration_version ] = new $class;
}
}
}
if ( empty( $this->translators ) ) {
// Regenerate theme CSS file on update
if ( $db_version != US_THEMEVERSION ) {
us_generate_asset_files();
}
// Set DB version if the theme was just installed
$this->set_db_version();
return;
}
if ( defined( 'DOING_AJAX' ) AND DOING_AJAX ) {
// Providing fall-back compatibility for the previous website db versions
$this->provide_fallback( $migrations );
} else {
if ( $this->should_be_manual() ) {
if ( ! is_admin() ) {
// Providing fall-back compatibility for the previous website db versions
$this->provide_fallback( $migrations );
} else {
if ( isset( $_GET['us-migration'] ) AND wp_verify_nonce( $_GET['us-migration'], 'us-migration' ) ) {
// Performing the migration
add_action( 'admin_init', array( $this, 'perform_migration' ), 1 );
add_action( 'admin_notices', array( $this, 'display_migration_completed' ), 1 );
} else {
// Notifying about the needed migrations
add_action( 'admin_notices', array( $this, 'display_migration_needed' ), 1 );
add_action( 'admin_footer', array( $this, 'output_migration_needed_js' ), 1 );
}
}
} else {
if ( ! is_admin() ) {
// Performing the migration silently
add_action( 'init', array( $this, 'perform_migration' ), 11 );
} else {
// Performing the migration silently
add_action( 'admin_init', array( $this, 'perform_migration' ), 1 );
}
}
}
}
/**
* Check if the current set of migrations should be manual
*/
protected function should_be_manual() {
$should_be_manual = FALSE;
$migration_needed_message = '';
$migration_completed_message = '';
foreach ( $this->translators as $version => $translator ) {
if ( method_exists( $translator, 'migration_needed_message' ) ) {
$migration_needed_message .= $translator->migration_needed_message();
}
if ( method_exists( $translator, 'migration_completed_message' ) ) {
$migration_completed_message .= $translator->migration_completed_message();
}
$should_be_manual = ( $should_be_manual OR $translator->should_be_manual );
}
$this->migration_needed_message = $migration_needed_message;
$this->migration_completed_message = $migration_completed_message;
return $should_be_manual;
}
/**
* Get the theme's current database version
*
* @return string
*/
public function get_db_version() {
// Getting from global options, not from the theme mods, as it affects content and general options (not theme mods)
$result = get_option( 'us_db_version' ) ? get_option( 'us_db_version' ) : US_THEMEVERSION;
// removing 'betaX' suffix from version
$result = preg_replace( '~beta\d~', '', $result );
return $result;
}
/**
* Set the current database version
*
* @param string $version If not set will be updated to the current theme's version
*/
public function set_db_version( $version = NULL ) {
if ( $version === NULL ) {
$version = US_THEMEVERSION;
}
// removing 'betaX' suffix from version
$version = preg_replace( '~beta\d~', '', $version );
$current_version = get_option( 'us_db_version' );
if ( $current_version != $version ) {
update_option( 'us_db_version', $version, TRUE );
}
}
public function provide_fallback( $migrations ) {
global $us_migration_doing_fallback;
$us_migration_doing_fallback = TRUE;
// For both frontend and ajax requests
add_action( 'init', array( $this, 'fallback_theme_options' ), 12 );
add_filter( 'get_post_metadata', array( $this, 'fallback_meta' ), 10, 4 );
if ( ! is_admin() ) {
// For frontend requests only
add_filter( 'theme_mod_nav_menu_locations', array( $this, 'fallback_menus' ), 5 );
add_filter( 'the_content', array( $this, 'fallback_content' ), 5 );
}
if ( $this->has_widgets_translators() ) {
add_action( 'init', array( $this, 'fallback_widgets' ), 12 );
}
}
/**
* Method that is bound to 'theme_mod_nav_menu_locations' filter to provide live fallback compatibility for menus migrations
*
* @param string $locations
*
* @return mixed
*/
public function fallback_menus( $locations ) {
foreach ( $this->translators as $version => $translator ) {
if ( method_exists( $translator, 'translate_menus' ) ) {
$translator->translate_menus( $locations );
}
}
return $locations;
}
/**
* Method for providing live fallback compatibility for options migrations
*/
public function fallback_theme_options() {
global $usof_options;
usof_load_options_once();
foreach ( $this->translators as $version => $translator ) {
if ( method_exists( $translator, 'translate_theme_options' ) ) {
$translator->translate_theme_options( $usof_options );
}
}
$usof_options = array_merge( usof_defaults(), $usof_options );
}
/**
* Method for providing live fallback compatibility for metas migrations
*
* @param mixed $meta_val
* @param string $key
* @param array $args
* @param int $post_id
*
* @return mixed
*/
public function fallback_meta( $meta_val, $post_id, $key, $single ) {
if ( ! get_the_ID() OR $post_id != get_the_ID() OR empty( $key ) ) {
return $meta_val;
}
$meta = get_post_meta( $post_id );
$post_type = get_post_type( $post_id );
foreach ( $this->translators as $version => $translator ) {
if ( method_exists( $translator, 'translate_meta' ) ) {
$translator->translate_meta( $meta, $post_type );
}
}
if ( isset( $meta[ $key ] ) ) {
if ( $single ) {
return $meta[ $key ][0];
} else {
return $meta[ $key ];
}
} else {
return $meta_val;
}
}
/**
* Method that is bound to 'the_content' filter to provide live fallback compatibility for content migrations
*
* @param $content
*
* @return mixed
*/
public function fallback_content( $content ) {
global $post;
$postID = ( isset( $post->ID ) ) ? $post->ID : NULL; // TODO check if we really use passed post ID
foreach ( $this->translators as $version => $translator ) {
if ( method_exists( $translator, 'translate_content' ) ) {
$translator->translate_content( $content, $postID );
}
}
return $content;
}
public function has_widgets_translators() {
foreach ( $this->translators as $version => $translator ) {
if ( method_exists( $translator, 'translate_widgets' ) ) {
return TRUE;
}
}
return FALSE;
}
public $sidebars_widgets = array();
public $widgets_instances = array();
public function fallback_widgets() {
$this->sidebars_widgets = array();
$this->widgets_instances = array();
$filters_added = array();
foreach ( get_option( 'sidebars_widgets', array() ) as $sidebar => $widgets ) {
if ( ! is_array( $widgets ) ) {
// For non-widgets additional option data
$this->sidebars_widgets[ $sidebar ] = $widgets;
continue;
}
foreach ( $widgets as $index => $widget_binding ) {
if ( ! preg_match( '@^(.+)\-(\d+)$@', $widget_binding, $matches ) ) {
continue;
}
$widget_name = $original_widget_name = $matches[1];
$instance_id = $matches[2];
$this->widgets_instances[ $widget_name ] = get_option( 'widget_' . $widget_name, array() );
if ( ! isset( $this->widgets_instances[ $widget_name ][ $instance_id ] ) ) {
continue;
}
foreach ( $this->translators as $version => $translator ) {
if ( ! method_exists( $translator, 'translate_widgets' ) ) {
continue;
}
if ( $translator->translate_widgets( $widget_name, $this->widgets_instances[ $widget_name ][ $instance_id ] ) ) {
if ( $widget_name != $original_widget_name ) {
if ( ! isset( $this->widgets_instances[ $widget_name ] ) ) {
// Widget name has changed
$this->widgets_instances[ $widget_name ] = isset( $this->widgets_instances[ $original_widget_name ] ) ? $this->widgets_instances[ $original_widget_name ] : array();
} else {
$this->widgets_instances[ $widget_name ][ $instance_id ] = $this->widgets_instances[ $original_widget_name ][ $instance_id ];
}
}
if ( ! in_array( $widget_name, $filters_added ) ) {
// Binding each widget once
add_filter(
'pre_option_widget_' . $widget_name, array(
$this,
'fallback_widgets_instance',
)
);
$filters_added[] = $widget_name;
}
}
}
$widgets[ $index ] = $widget_name . '-' . $instance_id;
}
$this->sidebars_widgets[ $sidebar ] = $widgets;
}
if ( count( $filters_added ) > 0 ) {
add_filter( 'option_sidebars_widgets', array( $this, 'fallback_sidebars_widgets' ) );
}
}
public function fallback_sidebars_widgets() {
return $this->sidebars_widgets;
}
public function fallback_widgets_instance() {
if ( ! preg_match( '@^pre_option_widget_(.+)$@', current_filter(), $matches ) OR ! isset( $this->widgets_instances[ $matches[1] ] ) ) {
return FALSE;
}
return $this->widgets_instances[ $matches[1] ];
}
public function display_migration_needed() {
if ( $this->migration_needed_message != '' ) {
$output = $this->migration_needed_message;
} else {
$output = '
';
$output .= '
Your website content needs to be changed to be compatible with ' . US_THEMENAME . ' ' . US_THEMEVERSION . '
';
// Prevent migration access when "Wordfence" or "iThemes Security" plugins are active
if ( class_exists( 'wordfence' ) OR class_exists( 'ITSEC_Core' ) ) {
$output .= '