balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

OneClickDemoImport.php (18725B)


      1 <?php
      2 
      3 /**
      4  * Main One Click Demo Import plugin class/file.
      5  *
      6  * @package ocdi
      7  */
      8 
      9 namespace OCDI;
     10 
     11 /**
     12  * One Click Demo Import class, so we don't have to worry about namespaces.
     13  */
     14 class OneClickDemoImport {
     15 
     16 	/**
     17 	 * The instance *Singleton* of this class
     18 	 *
     19 	 * @var object
     20 	 */
     21 	private static $instance;
     22 
     23 	/**
     24 	 * The instance of the OCDI\Importer class.
     25 	 *
     26 	 * @var object
     27 	 */
     28 	public $importer;
     29 
     30 	/**
     31 	 * The resulting page's hook_suffix, or false if the user does not have the capability required.
     32 	 *
     33 	 * @var boolean or string
     34 	 */
     35 	private $plugin_page;
     36 
     37 	/**
     38 	 * Holds the verified import files.
     39 	 *
     40 	 * @var array
     41 	 */
     42 	public $import_files;
     43 
     44 	/**
     45 	 * The path of the log file.
     46 	 *
     47 	 * @var string
     48 	 */
     49 	public $log_file_path;
     50 
     51 	/**
     52 	 * The index of the `import_files` array (which import files was selected).
     53 	 *
     54 	 * @var int
     55 	 */
     56 	private $selected_index;
     57 
     58 	/**
     59 	 * The paths of the actual import files to be used in the import.
     60 	 *
     61 	 * @var array
     62 	 */
     63 	private $selected_import_files;
     64 
     65 	/**
     66 	 * Holds any error messages, that should be printed out at the end of the import.
     67 	 *
     68 	 * @var string
     69 	 */
     70 	public $frontend_error_messages = array();
     71 
     72 	/**
     73 	 * Was the before content import already triggered?
     74 	 *
     75 	 * @var boolean
     76 	 */
     77 	private $before_import_executed = false;
     78 
     79 	/**
     80 	 * Make plugin page options available to other methods.
     81 	 *
     82 	 * @var array
     83 	 */
     84 	private $plugin_page_setup = array();
     85 
     86 	/**
     87 	 * Returns the *Singleton* instance of this class.
     88 	 *
     89 	 * @return OneClickDemoImport the *Singleton* instance.
     90 	 */
     91 	public static function get_instance() {
     92 		if ( null === static::$instance ) {
     93 			static::$instance = new static();
     94 		}
     95 
     96 		return static::$instance;
     97 	}
     98 
     99 
    100 	/**
    101 	 * Class construct function, to initiate the plugin.
    102 	 * Protected constructor to prevent creating a new instance of the
    103 	 * *Singleton* via the `new` operator from outside of this class.
    104 	 */
    105 	protected function __construct() {
    106 		// Actions.
    107 		add_action( 'admin_menu', array( $this, 'create_plugin_page' ) );
    108 		add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
    109 		add_action( 'wp_ajax_ocdi_import_demo_data', array( $this, 'import_demo_data_ajax_callback' ) );
    110 		add_action( 'wp_ajax_ocdi_import_customizer_data', array( $this, 'import_customizer_data_ajax_callback' ) );
    111 		add_action( 'wp_ajax_ocdi_after_import_data', array( $this, 'after_all_import_data_ajax_callback' ) );
    112 		add_action( 'after_setup_theme', array( $this, 'setup_plugin_with_filter_data' ) );
    113 		add_action( 'plugins_loaded', array( $this, 'load_textdomain' ) );
    114 	}
    115 
    116 
    117 	/**
    118 	 * Private clone method to prevent cloning of the instance of the *Singleton* instance.
    119 	 *
    120 	 * @return void
    121 	 */
    122 	private function __clone() {    }
    123 
    124 
    125 	/**
    126 	 * Private unserialize method to prevent unserializing of the *Singleton* instance.
    127 	 *
    128 	 * @return void
    129 	 */
    130 	public function __wakeup() {    }
    131 
    132 
    133 	/**
    134 	 * Creates the plugin page and a submenu item in WP Appearance menu.
    135 	 */
    136 	public function create_plugin_page() {
    137 		$this->plugin_page_setup = apply_filters(
    138 			'pt-ocdi/plugin_page_setup',
    139 			array(
    140 				'parent_slug' => 'themes.php',
    141 				'page_title'  => esc_html__( 'One Click Demo Import', 'pt-ocdi' ),
    142 				'menu_title'  => esc_html__( 'Import Demo Data', 'pt-ocdi' ),
    143 				'capability'  => 'import',
    144 				'menu_slug'   => 'pt-one-click-demo-import',
    145 			)
    146 		);
    147 
    148 		$this->plugin_page = add_submenu_page(
    149 			$this->plugin_page_setup['parent_slug'],
    150 			$this->plugin_page_setup['page_title'],
    151 			$this->plugin_page_setup['menu_title'],
    152 			$this->plugin_page_setup['capability'],
    153 			$this->plugin_page_setup['menu_slug'],
    154 			apply_filters( 'pt-ocdi/plugin_page_display_callback_function', array( $this, 'display_plugin_page' ) )
    155 		);
    156 
    157 		register_importer( $this->plugin_page_setup['menu_slug'], $this->plugin_page_setup['page_title'], $this->plugin_page_setup['menu_title'], apply_filters( 'pt-ocdi/plugin_page_display_callback_function', array( $this, 'display_plugin_page' ) ) );
    158 	}
    159 
    160 
    161 	/**
    162 	 * Plugin page display.
    163 	 * Output (HTML) is in another file.
    164 	 */
    165 	public function display_plugin_page() {
    166 		 require_once PT_OCDI_PATH . 'views/plugin-page.php';
    167 	}
    168 
    169 
    170 	/**
    171 	 * Enqueue admin scripts (JS and CSS)
    172 	 *
    173 	 * @param string $hook holds info on which admin page you are currently loading.
    174 	 */
    175 	public function admin_enqueue_scripts( $hook ) {
    176 		// Enqueue the scripts only on the plugin page.
    177 		if ( $this->plugin_page === $hook || ( 'admin.php' === $hook && $this->plugin_page_setup['menu_slug'] === esc_attr( $_GET['import'] ) ) ) {
    178 			wp_enqueue_script( 'jquery-ui-dialog' );
    179 			wp_enqueue_style( 'wp-jquery-ui-dialog' );
    180 
    181 			wp_enqueue_script( 'ocdi-main-js', PT_OCDI_URL . 'assets/js/main.js', array( 'jquery', 'jquery-ui-dialog' ), PT_OCDI_VERSION );
    182 
    183 			// Get theme data.
    184 			$theme = wp_get_theme();
    185 
    186 			wp_localize_script(
    187 				'ocdi-main-js',
    188 				'ocdi',
    189 				array(
    190 					'ajax_url'         => admin_url( 'admin-ajax.php' ),
    191 					'ajax_nonce'       => wp_create_nonce( 'ocdi-ajax-verification' ),
    192 					'import_files'     => $this->import_files,
    193 					'wp_customize_on'  => apply_filters( 'pt-ocdi/enable_wp_customize_save_hooks', false ),
    194 					'import_popup'     => apply_filters( 'pt-ocdi/enable_grid_layout_import_popup_confirmation', true ),
    195 					'theme_screenshot' => $theme->get_screenshot(),
    196 					'texts'            => array(
    197 						'missing_preview_image' => esc_html__( 'No preview image defined for this import.', 'pt-ocdi' ),
    198 						'dialog_title'          => esc_html__( 'Are you sure?', 'pt-ocdi' ),
    199 						'dialog_no'             => esc_html__( 'Cancel', 'pt-ocdi' ),
    200 						'dialog_yes'            => esc_html__( 'Yes, import!', 'pt-ocdi' ),
    201 						'selected_import_title' => esc_html__( 'Selected demo import:', 'pt-ocdi' ),
    202 					),
    203 					'dialog_options'   => apply_filters( 'pt-ocdi/confirmation_dialog_options', array() ),
    204 				)
    205 			);
    206 
    207 			wp_enqueue_style( 'ocdi-main-css', PT_OCDI_URL . 'assets/css/main.css', array(), PT_OCDI_VERSION );
    208 		}
    209 	}
    210 
    211 
    212 	/**
    213 	 * Main AJAX callback function for:
    214 	 * 1). prepare import files (uploaded or predefined via filters)
    215 	 * 2). execute 'before content import' actions (before import WP action)
    216 	 * 3). import content
    217 	 * 4). execute 'after content import' actions (before widget import WP action, widget import, customizer import, after import WP action)
    218 	 */
    219 	public function import_demo_data_ajax_callback() {
    220 		// Try to update PHP memory limit (so that it does not run out of it).
    221 		ini_set( 'memory_limit', apply_filters( 'pt-ocdi/import_memory_limit', '350M' ) );
    222 
    223 		// Verify if the AJAX call is valid (checks nonce and current_user_can).
    224 		Helpers::verify_ajax_call();
    225 
    226 		// Is this a new AJAX call to continue the previous import?
    227 		$use_existing_importer_data = $this->use_existing_importer_data();
    228 
    229 		if ( ! $use_existing_importer_data ) {
    230 			// Create a date and time string to use for demo and log file names.
    231 			Helpers::set_demo_import_start_time();
    232 
    233 			// Define log file path.
    234 			$this->log_file_path = Helpers::get_log_path();
    235 
    236 			// Get selected file index or set it to 0.
    237 			$this->selected_index = empty( $_POST['selected'] ) ? 0 : absint( $_POST['selected'] );
    238 			/**
    239 			 * 1). Prepare import files.
    240 			 * Manually uploaded import files or predefined import files via filter: pt-ocdi/import_files
    241 			 */
    242 			if ( ! empty( $_FILES ) ) { // Using manual file uploads?
    243 				// Get paths for the uploaded files.
    244 				$this->selected_import_files = Helpers::process_uploaded_files( $_FILES, $this->log_file_path );
    245 
    246 				// Set the name of the import files, because we used the uploaded files.
    247 				$this->import_files[ $this->selected_index ]['import_file_name'] = esc_html__( 'Manually uploaded files', 'pt-ocdi' );
    248 			} elseif ( ! empty( $this->import_files[ $this->selected_index ] ) ) { // Use predefined import files from wp filter: pt-ocdi/import_files.
    249 
    250 				// Download the import files (content, widgets and customizer files).
    251 				$this->selected_import_files = Helpers::download_import_files( $this->import_files[ $this->selected_index ] );
    252 
    253 				// Check Errors.
    254 				if ( is_wp_error( $this->selected_import_files ) ) {
    255 					// Write error to log file and send an AJAX response with the error.
    256 					Helpers::log_error_and_send_ajax_response(
    257 						$this->selected_import_files->get_error_message(),
    258 						$this->log_file_path,
    259 						esc_html__( 'Downloaded files', 'pt-ocdi' )
    260 					);
    261 				}
    262 
    263 				// Add this message to log file.
    264 				$log_added = Helpers::append_to_file(
    265 					sprintf(
    266 						__( 'The import files for: %s were successfully downloaded!', 'pt-ocdi' ),
    267 						$this->import_files[ $this->selected_index ]['import_file_name']
    268 					) . Helpers::import_file_info( $this->selected_import_files ),
    269 					$this->log_file_path,
    270 					esc_html__( 'Downloaded files', 'pt-ocdi' )
    271 				);
    272 			} else {
    273 				// Send JSON Error response to the AJAX call.
    274 				wp_send_json( esc_html__( 'No import files specified!', 'pt-ocdi' ) );
    275 			}
    276 		}
    277 
    278 		// Save the initial import data as a transient, so other import parts (in new AJAX calls) can use that data.
    279 		Helpers::set_ocdi_import_data_transient( $this->get_current_importer_data() );
    280 
    281 		if ( ! $this->before_import_executed ) {
    282 			$this->before_import_executed = true;
    283 
    284 			/**
    285 			 * 2). Execute the actions hooked to the 'pt-ocdi/before_content_import_execution' action:
    286 			 *
    287 			 * Default actions:
    288 			 * 1 - Before content import WP action (with priority 10).
    289 			 */
    290 			do_action( 'pt-ocdi/before_content_import_execution', $this->selected_import_files, $this->import_files, $this->selected_index );
    291 		}
    292 
    293 		/**
    294 		 * 3). Import content (if the content XML file is set for this import).
    295 		 * Returns any errors greater then the "warning" logger level, that will be displayed on front page.
    296 		 */
    297 		if ( ! empty( $this->selected_import_files['content'] ) ) {
    298 			$this->append_to_frontend_error_messages( $this->importer->import_content( $this->selected_import_files['content'] ) );
    299 		}
    300 
    301 		/**
    302 		 * 4). Execute the actions hooked to the 'pt-ocdi/after_content_import_execution' action:
    303 		 *
    304 		 * Default actions:
    305 		 * 1 - Before widgets import setup (with priority 10).
    306 		 * 2 - Import widgets (with priority 20).
    307 		 * 3 - Import Redux data (with priority 30).
    308 		 */
    309 		do_action( 'pt-ocdi/after_content_import_execution', $this->selected_import_files, $this->import_files, $this->selected_index );
    310 
    311 		// Save the import data as a transient, so other import parts (in new AJAX calls) can use that data.
    312 		Helpers::set_ocdi_import_data_transient( $this->get_current_importer_data() );
    313 
    314 		// Request the customizer import AJAX call.
    315 		if ( ! empty( $this->selected_import_files['customizer'] ) ) {
    316 			wp_send_json( array( 'status' => 'customizerAJAX' ) );
    317 		}
    318 
    319 		// Request the after all import AJAX call.
    320 		if ( false !== has_action( 'pt-ocdi/after_all_import_execution' ) ) {
    321 			wp_send_json( array( 'status' => 'afterAllImportAJAX' ) );
    322 		}
    323 
    324 		// Send a JSON response with final report.
    325 		$this->final_response();
    326 	}
    327 
    328 
    329 	/**
    330 	 * AJAX callback for importing the customizer data.
    331 	 * This request has the wp_customize set to 'on', so that the customizer hooks can be called
    332 	 * (they can only be called with the $wp_customize instance). But if the $wp_customize is defined,
    333 	 * then the widgets do not import correctly, that's why the customizer import has its own AJAX call.
    334 	 */
    335 	public function import_customizer_data_ajax_callback() {
    336 		// Verify if the AJAX call is valid (checks nonce and current_user_can).
    337 		Helpers::verify_ajax_call();
    338 
    339 		// Get existing import data.
    340 		if ( $this->use_existing_importer_data() ) {
    341 			/**
    342 			 * Execute the customizer import actions.
    343 			 *
    344 			 * Default actions:
    345 			 * 1 - Customizer import (with priority 10).
    346 			 */
    347 			do_action( 'pt-ocdi/customizer_import_execution', $this->selected_import_files );
    348 		}
    349 
    350 		// Request the after all import AJAX call.
    351 		if ( false !== has_action( 'pt-ocdi/after_all_import_execution' ) ) {
    352 			wp_send_json( array( 'status' => 'afterAllImportAJAX' ) );
    353 		}
    354 
    355 		// Send a JSON response with final report.
    356 		$this->final_response();
    357 	}
    358 
    359 
    360 	/**
    361 	 * AJAX callback for the after all import action.
    362 	 */
    363 	public function after_all_import_data_ajax_callback() {
    364 		 // Verify if the AJAX call is valid (checks nonce and current_user_can).
    365 		Helpers::verify_ajax_call();
    366 
    367 		// Get existing import data.
    368 		if ( $this->use_existing_importer_data() ) {
    369 			/**
    370 			 * Execute the after all import actions.
    371 			 *
    372 			 * Default actions:
    373 			 * 1 - after_import action (with priority 10).
    374 			 */
    375 			do_action( 'pt-ocdi/after_all_import_execution', $this->selected_import_files, $this->import_files, $this->selected_index );
    376 		}
    377 
    378 		// Send a JSON response with final report.
    379 		$this->final_response();
    380 	}
    381 
    382 
    383 	/**
    384 	 * Send a JSON response with final report.
    385 	 */
    386 	private function final_response() {
    387 		 // Delete importer data transient for current import.
    388 		delete_transient( 'ocdi_importer_data' );
    389 
    390 		// Display final messages (success or error messages).
    391 		if ( empty( $this->frontend_error_messages ) ) {
    392 			$response['message'] = '';
    393 
    394 			if ( ! apply_filters( 'pt-ocdi/disable_pt_branding', false ) ) {
    395 				$twitter_status = esc_html__( 'Just used One Click Demo Import plugin and it was awesome! Thanks @ProteusThemes! #OCDI https://www.proteusthemes.com/', 'pt-ocdi' );
    396 
    397 				$response['message'] .= sprintf(
    398 					__( '%1$s%6$sWasn\'t this a great One Click Demo Import experience?%7$s Created and maintained by %3$sProteusThemes%4$s. %2$s%5$sClick to Tweet!%4$s%8$s', 'pt-ocdi' ),
    399 					'<div class="notice  notice-info"><p>',
    400 					'<br>',
    401 					'<strong><a href="https://www.proteusthemes.com/" target="_blank">',
    402 					'</a></strong>',
    403 					'<strong><a href="' . add_query_arg( 'status', urlencode( $twitter_status ), 'http://twitter.com/home' ) . '" target="_blank">',
    404 					'<strong>',
    405 					'</strong>',
    406 					'</p></div>'
    407 				);
    408 			}
    409 
    410 			$response['message'] .= sprintf(
    411 				__( '%1$s%3$sThat\'s it, all done!%4$s%2$sThe demo import has finished. Please check your page and make sure that everything has imported correctly. If it did, you can deactivate the %3$sDemo Installer%4$s plugin, because it has done its job.%5$s', 'pt-ocdi' ),
    412 				'<div class="notice  notice-success"><p>',
    413 				'<br>',
    414 				'<strong>',
    415 				'</strong>',
    416 				'</p></div>'
    417 			);
    418 		} else {
    419 			$response['message']  = $this->frontend_error_messages_display() . '<br>';
    420 			$response['message'] .= sprintf(
    421 				__( '%1$sThe demo import has finished, but there were some import errors.%2$sMore details about the errors can be found in this %3$s%5$slog file%6$s%4$s%7$s', 'pt-ocdi' ),
    422 				'<div class="notice  notice-warning"><p>',
    423 				'<br>',
    424 				'<strong>',
    425 				'</strong>',
    426 				'<a href="' . Helpers::get_log_url( $this->log_file_path ) . '" target="_blank">',
    427 				'</a>',
    428 				'</p></div>'
    429 			);
    430 		}
    431 
    432 		wp_send_json( $response );
    433 	}
    434 
    435 
    436 	/**
    437 	 * Get content importer data, so we can continue the import with this new AJAX request.
    438 	 *
    439 	 * @return boolean
    440 	 */
    441 	private function use_existing_importer_data() {
    442 		if ( $data = get_transient( 'ocdi_importer_data' ) ) {
    443 			$this->frontend_error_messages = empty( $data['frontend_error_messages'] ) ? array() : $data['frontend_error_messages'];
    444 			$this->log_file_path           = empty( $data['log_file_path'] ) ? '' : $data['log_file_path'];
    445 			$this->selected_index          = empty( $data['selected_index'] ) ? 0 : $data['selected_index'];
    446 			$this->selected_import_files   = empty( $data['selected_import_files'] ) ? array() : $data['selected_import_files'];
    447 			$this->before_import_executed  = empty( $data['before_import_executed'] ) ? false : $data['before_import_executed'];
    448 			$this->importer->set_importer_data( $data );
    449 
    450 			return true;
    451 		}
    452 		return false;
    453 	}
    454 
    455 
    456 	/**
    457 	 * Get the current state of selected data.
    458 	 *
    459 	 * @return array
    460 	 */
    461 	public function get_current_importer_data() {
    462 		return array(
    463 			'frontend_error_messages' => $this->frontend_error_messages,
    464 			'log_file_path'           => $this->log_file_path,
    465 			'selected_index'          => $this->selected_index,
    466 			'selected_import_files'   => $this->selected_import_files,
    467 			'before_import_executed'  => $this->before_import_executed,
    468 		);
    469 	}
    470 
    471 
    472 	/**
    473 	 * Getter function to retrieve the private log_file_path value.
    474 	 *
    475 	 * @return string The log_file_path value.
    476 	 */
    477 	public function get_log_file_path() {
    478 		return $this->log_file_path;
    479 	}
    480 
    481 
    482 	/**
    483 	 * Setter function to append additional value to the private frontend_error_messages value.
    484 	 *
    485 	 * @param string $additional_value The additional value that will be appended to the existing frontend_error_messages.
    486 	 */
    487 	public function append_to_frontend_error_messages( $text ) {
    488 		$lines = array();
    489 
    490 		if ( ! empty( $text ) ) {
    491 			$text  = str_replace( '<br>', PHP_EOL, $text );
    492 			$lines = explode( PHP_EOL, $text );
    493 		}
    494 
    495 		foreach ( $lines as $line ) {
    496 			if ( ! empty( $line ) && ! in_array( $line, $this->frontend_error_messages ) ) {
    497 				$this->frontend_error_messages[] = $line;
    498 			}
    499 		}
    500 	}
    501 
    502 
    503 	/**
    504 	 * Display the frontend error messages.
    505 	 *
    506 	 * @return string Text with HTML markup.
    507 	 */
    508 	public function frontend_error_messages_display() {
    509 		 $output = '';
    510 
    511 		if ( ! empty( $this->frontend_error_messages ) ) {
    512 			foreach ( $this->frontend_error_messages as $line ) {
    513 				$output .= esc_html( $line );
    514 				$output .= '<br>';
    515 			}
    516 		}
    517 
    518 		return $output;
    519 	}
    520 
    521 
    522 	/**
    523 	 * Load the plugin textdomain, so that translations can be made.
    524 	 */
    525 	public function load_textdomain() {
    526 		 load_plugin_textdomain( 'pt-ocdi', false, plugin_basename( dirname( dirname( __FILE__ ) ) ) . '/languages' );
    527 	}
    528 
    529 
    530 	/**
    531 	 * Get data from filters, after the theme has loaded and instantiate the importer.
    532 	 */
    533 	public function setup_plugin_with_filter_data() {
    534 		// Get info of import data files and filter it.
    535 		$this->import_files = Helpers::validate_import_file_info( apply_filters( 'pt-ocdi/import_files', array() ) );
    536 
    537 		/**
    538 		 * Register all default actions (before content import, widget, customizer import and other actions)
    539 		 * to the 'before_content_import_execution' and the 'pt-ocdi/after_content_import_execution' action hook.
    540 		 */
    541 		$import_actions = new ImportActions();
    542 		$import_actions->register_hooks();
    543 
    544 		// Importer options array.
    545 		$importer_options = apply_filters(
    546 			'pt-ocdi/importer_options',
    547 			array(
    548 				'fetch_attachments' => true,
    549 			)
    550 		);
    551 
    552 		// Logger options for the logger used in the importer.
    553 		$logger_options = apply_filters(
    554 			'pt-ocdi/logger_options',
    555 			array(
    556 				'logger_min_level' => 'warning',
    557 			)
    558 		);
    559 
    560 		// Configure logger instance and set it to the importer.
    561 		$logger            = new Logger();
    562 		$logger->min_level = $logger_options['logger_min_level'];
    563 
    564 		// Create importer instance with proper parameters.
    565 		$this->importer = new Importer( $importer_options, $logger );
    566 	}
    567 }