403Webshell
Server IP : 172.67.214.6  /  Your IP : 216.73.216.73
Web Server : LiteSpeed
System : Linux premium900.web-hosting.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64
User : redwjova ( 1790)
PHP Version : 8.1.32
Disable Function : NONE
MySQL : OFF |  cURL : ON |  WGET : ON |  Perl : ON |  Python : ON |  Sudo : OFF |  Pkexec : OFF
Directory :  /home/redwjova/fyntric.com/wp-content/themes/smart-mag/lib/vendor/plugins/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/redwjova/fyntric.com/wp-content/themes/smart-mag/lib/vendor/plugins/bunyad-demo-import.zip
PK/3Y�6#�)bunyad-demo-import/bunyad-demo-import.php<?php
/*
Plugin Name: Bunyad Demo Import
Plugin URI: https://theme-sphere.com
Description: Modified (fork) version of "One Click Demo Import"
Version: 2.6.4
Author: ThemeSphere & ProteusThemes
Author URI: https://theme-sphere.com
License: GPL3
License URI: http://www.gnu.org/licenses/gpl.html
Text Domain: pt-ocdi
*/

/**
 * This fork was created due to underlying difference between our idea of
 * how the UI should function vs the one in the original plugin.
 * 
 * Main Changes:
 *  - Different UI in class-ocdi-main
 *  - A different AJAX implementation to handle failures better
 *  - Improvements to new_ajax_request_maybe()
 *  - WXRImporter::process_attachment() improvement for skipping redownloads
 *  - Importer.php improvements to add missing xml import logs.
 */

// Exit if accessed directly
if (!defined('ABSPATH')) exit;

/**
 * Main plugin class with initialization tasks.
 */
class Bunyad_Demo_Import_Plugin {
	/**
	 * Constructor for this class.
	 */
	public function __construct() {
		/**
		 * Display admin error message if PHP version is older than 5.3.2.
		 * Otherwise execute the main plugin class.
		 */
		if ( version_compare( phpversion(), '5.3.2', '<' ) ) {
			add_action( 'admin_notices', array( $this, 'old_php_admin_error_notice' ) );
		}
		else {
			// Set plugin constants.
			$this->set_plugin_constants();

			// Composer autoloader.
			require_once PT_OCDI_PATH . 'vendor/autoload.php';

			// Instantiate the main plugin class *Singleton*.
			$pt_one_click_demo_import = OCDI\OneClickDemoImport::get_instance();


			// +EDIT: Menu importer.
			require PT_OCDI_PATH . 'inc/menus.php';
			// Backward compatibility.
			class_alias('OCDI\OneClickDemoImport', 'Bunyad_Demo_Import');

			// Register WP CLI commands
			// +EDIT: Disabled for PHP8.0 issues.
			// if ( defined( 'WP_CLI' ) && WP_CLI ) {
				// WP_CLI::add_command( 'ocdi list', array( 'OCDI\WPCLICommands', 'list_predefined' ) );
				// WP_CLI::add_command( 'ocdi import', array( 'OCDI\WPCLICommands', 'import' ) );
			// }
		}
	}

	/**
	 * Display an admin error notice when PHP is older the version 5.3.2.
	 * Hook it to the 'admin_notices' action.
	 */
	public function old_php_admin_error_notice() {
		$message = sprintf( esc_html__( 'The %2$sOne Click Demo Import%3$s plugin requires %2$sPHP 5.3.2+%3$s to run properly. Please contact your hosting company and ask them to update the PHP version of your site to at least PHP 5.3.2.%4$s Your current version of PHP: %2$s%1$s%3$s', 'pt-ocdi' ), phpversion(), '<strong>', '</strong>', '<br>' );

		printf( '<div class="notice notice-error"><p>%1$s</p></div>', wp_kses_post( $message ) );
	}


	/**
	 * Set plugin constants.
	 *
	 * Path/URL to root of this plugin, with trailing slash and plugin version.
	 */
	private function set_plugin_constants() {
		// Path/URL to root of this plugin, with trailing slash.
		if ( ! defined( 'PT_OCDI_PATH' ) ) {
			define( 'PT_OCDI_PATH', plugin_dir_path( __FILE__ ) );
		}
		if ( ! defined( 'PT_OCDI_URL' ) ) {
			define( 'PT_OCDI_URL', plugin_dir_url( __FILE__ ) );
		}

		// Action hook to set the plugin version constant.
		add_action( 'admin_init', array( $this, 'set_plugin_version_constant' ) );
	}


	/**
	 * Set plugin version constant -> PT_OCDI_VERSION.
	 */
	public function set_plugin_version_constant() {
		if ( ! defined( 'PT_OCDI_VERSION' ) ) {
			$plugin_data = get_plugin_data( __FILE__ );
			define( 'PT_OCDI_VERSION', $plugin_data['Version'] );
		}
	}
}

if (!function_exists('bunyad_demo_import_init')) {

	/**
	 * Detect plugin clash or initialize.
	 */
	function bunyad_demo_import_init() {
		if (
			class_exists('PT_One_Click_Demo_Import') 
			|| class_exists('OCDI_Plugin', false) 
			|| defined('PT_OCDI_PATH')
		) {			
			add_action('admin_notices', function() {
				echo '<div class="notice notice-error"><h2>Plugin Conflict</h2><p>Please de-activate the plugin "One Click Demo Import" as it conflicts with Bunyad Demo Import.</p></div>';
			});
			return;
		}

		// Instantiate the plugin class.
		new Bunyad_Demo_Import_Plugin;
	}
}

add_action('plugins_loaded', 'bunyad_demo_import_init');
PK/3Y��eebunyad-demo-import/readme.txt=== One Click Demo Import ===
Contributors: smub, proteusthemes
Tags: import, content, demo, data, widgets, settings, redux, theme options
Requires at least: 4.0
Tested up to: 5.4
Requires PHP: 5.3.2
Stable tag: 2.6.1
License: GPLv3 or later

Import your demo content, widgets and theme settings with one click. Theme authors! Enable simple demo import for your theme demo data.

== Description ==

The best feature of this plugin is, that theme authors can define import files in their themes and so all you (the user of the theme) have to do is click on the "Import Demo Data" button.

> **Are you a theme author?**
>
> Setup One Click Demo Imports for your theme and your users will thank you for it!
>
> [Follow this easy guide on how to setup this plugin for your themes!](http://awesomemotive.github.io/one-click-demo-import/)

> **Are you a theme user?**
>
> Contact the author of your theme and [let them know about this plugin](http://awesomemotive.github.io/one-click-demo-import/theme-users.html). Theme authors can make any theme compatible with this plugin in 15 minutes and make it much more user-friendly.
>
> "[Where can I find the contact of the theme author?](http://awesomemotive.github.io/one-click-demo-import/theme-users.html)"

This plugin will create a submenu page under Appearance with the title **Import demo data**.

If the theme you are using does not have any predefined import files, then you will be presented with three file upload inputs. First one is required and you will have to upload a demo content XML file, for the actual demo import. The second one is optional and will ask you for a WIE or JSON file for widgets import. You create that file using the [Widget Importer & Exporter](https://wordpress.org/plugins/widget-importer-exporter/) plugin. The third one is also optional and will import the customizer settings, select the DAT file which you can generate from [Customizer Export/Import](https://wordpress.org/plugins/customizer-export-import/) plugin (the customizer settings will be imported only if the export file was created from the same theme). The final one is optional as well and will import your Redux framework settings. You can generate the export json file with the [Redux framework](https://wordpress.org/plugins/redux-framework/) plugin.

This plugin is using the improved WP import 2.0 that is still in development and can be found here: https://github.com/humanmade/WordPress-Importer.

All progress of this plugin's work is logged in a log file in the default WP upload directory, together with the demo import files used in the importing process.

NOTE: There is no setting to "connect" authors from the demo import file to the existing users in your WP site (like there is in the original WP Importer plugin). All demo content will be imported under the current user.

**Do you want to contribute?**

Please refer to the official [GitHub repository](https://github.com/awesomemotive/one-click-demo-import) of this plugin.

== Installation ==

**From your WordPress dashboard**

1. Visit 'Plugins > Add New',
2. Search for 'One Click Demo Import' and install the plugin,
3. Activate 'One Click Demo Import' from your Plugins page.

**From WordPress.org**

1. Download 'One Click Demo Import'.
2. Upload the 'one-click-demo-import' directory to your '/wp-content/plugins/' directory, using your favorite method (ftp, sftp, scp, etc...)
3. Activate 'One Click Demo Import' from your Plugins page.

**Once the plugin is activated you will find the actual import page in: Appearance -> Import Demo Data.**

== Frequently Asked Questions ==

= I have activated the plugin. Where is the "Import Demo Data" page? =

You will find the import page in *wp-admin -> Appearance -> Import Demo Data*.

= Where are the demo import files and the log files saved? =

The files used in the demo import will be saved to the default WordPress uploads directory. An example of that directory would be: `../wp-content/uploads/2016/03/`.

The log file will also be registered in the *wp-admin -> Media* section, so you can access it easily.

= How to predefine demo imports? =

This question is for theme authors. To predefine demo imports, you just have to add the following code structure, with your own values to your theme (using the `pt-ocdi/import_files` filter):

`
function ocdi_import_files() {
	return array(
		array(
			'import_file_name'           => 'Demo Import 1',
			'categories'                 => array( 'Category 1', 'Category 2' ),
			'import_file_url'            => 'http://www.your_domain.com/ocdi/demo-content.xml',
			'import_widget_file_url'     => 'http://www.your_domain.com/ocdi/widgets.json',
			'import_customizer_file_url' => 'http://www.your_domain.com/ocdi/customizer.dat',
			'import_redux'               => array(
				array(
					'file_url'    => 'http://www.your_domain.com/ocdi/redux.json',
					'option_name' => 'redux_option_name',
				),
			),
			'import_preview_image_url'   => 'http://www.your_domain.com/ocdi/preview_import_image1.jpg',
			'import_notice'              => __( 'After you import this demo, you will have to setup the slider separately.', 'your-textdomain' ),
			'preview_url'                => 'http://www.your_domain.com/my-demo-1',
		),
		array(
			'import_file_name'           => 'Demo Import 2',
			'categories'                 => array( 'New category', 'Old category' ),
			'import_file_url'            => 'http://www.your_domain.com/ocdi/demo-content2.xml',
			'import_widget_file_url'     => 'http://www.your_domain.com/ocdi/widgets2.json',
			'import_customizer_file_url' => 'http://www.your_domain.com/ocdi/customizer2.dat',
			'import_redux'               => array(
				array(
					'file_url'    => 'http://www.your_domain.com/ocdi/redux.json',
					'option_name' => 'redux_option_name',
				),
				array(
					'file_url'    => 'http://www.your_domain.com/ocdi/redux2.json',
					'option_name' => 'redux_option_name_2',
				),
			),
			'import_preview_image_url'   => 'http://www.your_domain.com/ocdi/preview_import_image2.jpg',
			'import_notice'              => __( 'A special note for this import.', 'your-textdomain' ),
			'preview_url'                => 'http://www.your_domain.com/my-demo-2',
		),
	);
}
add_filter( 'pt-ocdi/import_files', 'ocdi_import_files' );
`

You can set content import, widgets, customizer and Redux framework import files. You can also define a preview image, which will be used only when multiple demo imports are defined, so that the user will see the difference between imports. Categories can be assigned to each demo import, so that they can be filtered easily. The preview URL will display the "Preview" button in the predefined demo item, which will open this URL in a new tab and user can view how the demo site looks like.

= How to automatically assign "Front page", "Posts page" and menu locations after the importer is done? =

You can do that, with the `pt-ocdi/after_import` action hook. The code would look something like this:

`
function ocdi_after_import_setup() {
	// Assign menus to their locations.
	$main_menu = get_term_by( 'name', 'Main Menu', 'nav_menu' );

	set_theme_mod( 'nav_menu_locations', array(
			'main-menu' => $main_menu->term_id, // replace 'main-menu' here with the menu location identifier from register_nav_menu() function
		)
	);

	// Assign front page and posts page (blog page).
	$front_page_id = get_page_by_title( 'Home' );
	$blog_page_id  = get_page_by_title( 'Blog' );

	update_option( 'show_on_front', 'page' );
	update_option( 'page_on_front', $front_page_id->ID );
	update_option( 'page_for_posts', $blog_page_id->ID );

}
add_action( 'pt-ocdi/after_import', 'ocdi_after_import_setup' );
`

= What about using local import files (from theme folder)? =

You have to use the same filter as in above example, but with a slightly different array keys: `local_*`. The values have to be absolute paths (not URLs) to your import files. To use local import files, that reside in your theme folder, please use the below code. Note: make sure your import files are readable!

`
function ocdi_import_files() {
	return array(
		array(
			'import_file_name'             => 'Demo Import 1',
			'categories'                   => array( 'Category 1', 'Category 2' ),
			'local_import_file'            => trailingslashit( get_template_directory() ) . 'ocdi/demo-content.xml',
			'local_import_widget_file'     => trailingslashit( get_template_directory() ) . 'ocdi/widgets.json',
			'local_import_customizer_file' => trailingslashit( get_template_directory() ) . 'ocdi/customizer.dat',
			'local_import_redux'           => array(
				array(
					'file_path'   => trailingslashit( get_template_directory() ) . 'ocdi/redux.json',
					'option_name' => 'redux_option_name',
				),
			),
			'import_preview_image_url'     => 'http://www.your_domain.com/ocdi/preview_import_image1.jpg',
			'import_notice'                => __( 'After you import this demo, you will have to setup the slider separately.', 'your-textdomain' ),
			'preview_url'                  => 'http://www.your_domain.com/my-demo-1',
		),
		array(
			'import_file_name'             => 'Demo Import 2',
			'categories'                   => array( 'New category', 'Old category' ),
			'local_import_file'            => trailingslashit( get_template_directory() ) . 'ocdi/demo-content2.xml',
			'local_import_widget_file'     => trailingslashit( get_template_directory() ) . 'ocdi/widgets2.json',
			'local_import_customizer_file' => trailingslashit( get_template_directory() ) . 'ocdi/customizer2.dat',
			'local_import_redux'           => array(
				array(
					'file_path'   => trailingslashit( get_template_directory() ) . 'ocdi/redux.json',
					'option_name' => 'redux_option_name',
				),
				array(
					'file_path'   => trailingslashit( get_template_directory() ) . 'ocdi/redux2.json',
					'option_name' => 'redux_option_name_2',
				),
			),
			'import_preview_image_url'     => 'http://www.your_domain.com/ocdi/preview_import_image2.jpg',
			'import_notice'                => __( 'A special note for this import.', 'your-textdomain' ),
			'preview_url'                  => 'http://www.your_domain.com/my-demo-2',
		),
	);
}
add_filter( 'pt-ocdi/import_files', 'ocdi_import_files' );
`

= How to handle different "after import setups" depending on which predefined import was selected? =

This question might be asked by a theme author wanting to implement different after import setups for multiple predefined demo imports. Lets say we have predefined two demo imports with the following names: 'Demo Import 1' and 'Demo Import 2', the code for after import setup would be (using the `pt-ocdi/after_import` filter):

`
function ocdi_after_import( $selected_import ) {
	echo "This will be displayed on all after imports!";

	if ( 'Demo Import 1' === $selected_import['import_file_name'] ) {
		echo "This will be displayed only on after import if user selects Demo Import 1";

		// Set logo in customizer
		set_theme_mod( 'logo_img', get_template_directory_uri() . '/assets/images/logo1.png' );
	}
	elseif ( 'Demo Import 2' === $selected_import['import_file_name'] ) {
		echo "This will be displayed only on after import if user selects Demo Import 2";

		// Set logo in customizer
		set_theme_mod( 'logo_img', get_template_directory_uri() . '/assets/images/logo2.png' );
	}
}
add_action( 'pt-ocdi/after_import', 'ocdi_after_import' );
`

= Can I add some code before the widgets get imported? =

Of course you can, use the `pt-ocdi/before_widgets_import` action. You can also target different predefined demo imports like in the example above. Here is a simple example code of the `pt-ocdi/before_widgets_import` action:

`
function ocdi_before_widgets_import( $selected_import ) {
	echo "Add your code here that will be executed before the widgets get imported!";
}
add_action( 'pt-ocdi/before_widgets_import', 'ocdi_before_widgets_import' );
`

= How can I import via the WP-CLI? =

In the 2.4.0 version of this pugin we added two WP-CLI commands:

* `wp ocdi list` - Which will list any predefined demo imports currently active theme might have,
* `wp ocdi import` - which has a few options that you can use to import the things you want (content/widgets/customizer/predefined demos). Let's look at these options below.

`wp ocdi import` options:

`wp ocdi import [--content=<file>] [--widgets=<file>] [--customizer=<file>] [--predefined=<index>]`

* `--content=<file>` - will run the content import with the WP import file specified in the `<file>` parameter,
* `--widgets=<file>` - will run the widgets import with the widgets import file specified in the `<file>` parameter,
* `--customizer=<file>` - will run the customizer settings import with the customizer import file specified in the `<file>` parameter,
* `--predefined=<index>` - will run the theme predefined import with the index of the predefined import in the `<index>` parameter (you can use the `wp ocdi list` command to check which index is used for each predefined demo import)

The content, widgets and customizer options can be mixed and used at the same time. If the `predefined` option is set, then it will ignore all other options and import the predefined demo data.

= I'm a theme author and I want to change the plugin intro text, how can I do that? =

You can change the plugin intro text by using the `pt-ocdi/plugin_intro_text` filter:

`
function ocdi_plugin_intro_text( $default_text ) {
	$default_text .= '<div class="ocdi__intro-text">This is a custom text added to this plugin intro text.</div>';

	return $default_text;
}
add_filter( 'pt-ocdi/plugin_intro_text', 'ocdi_plugin_intro_text' );
`

To add some text in a separate "box", you should wrap your text in a div with a class of 'ocdi__intro-text', like in the code example above.

= How to disable generation of smaller images (thumbnails) during the content import =

This will greatly improve the time needed to import the content (images), but only the original sized images will be imported. You can disable it with a filter, so just add this code to your theme function.php file:

`add_filter( 'pt-ocdi/regenerate_thumbnails_in_content_import', '__return_false' );`

= How to change the location, title and other parameters of the plugin page? =

As a theme author you do not like the location of the "Import Demo Data" plugin page in *Appearance -> Import Demo Data*? You can change that with the filter below. Apart from the location, you can also change the title or the page/menu and some other parameters as well.

`
function ocdi_plugin_page_setup( $default_settings ) {
	$default_settings['parent_slug'] = 'themes.php';
	$default_settings['page_title']  = esc_html__( 'One Click Demo Import' , 'pt-ocdi' );
	$default_settings['menu_title']  = esc_html__( 'Import Demo Data' , 'pt-ocdi' );
	$default_settings['capability']  = 'import';
	$default_settings['menu_slug']   = 'pt-one-click-demo-import';

	return $default_settings;
}
add_filter( 'pt-ocdi/plugin_page_setup', 'ocdi_plugin_page_setup' );
`

= How to do something before the content import executes? =

In version 2.0.0 there is a new action hook: `pt-ocdi/before_content_import`, which will let you hook before the content import starts. An example of the code would look like this:

`
function ocdi_before_content_import( $selected_import ) {
	if ( 'Demo Import 1' === $selected_import['import_file_name'] ) {
		// Here you can do stuff for the "Demo Import 1" before the content import starts.
		echo "before import 1";
	}
	else {
		// Here you can do stuff for all other imports before the content import starts.
		echo "before import 2";
	}
}
add_action( 'pt-ocdi/before_content_import', 'ocdi_before_content_import' );
`

= How can I enable the `customize_save*` wp action hooks in the customizer import? =

It's easy, just add this to your theme:

`add_action( 'pt-ocdi/enable_wp_customize_save_hooks', '__return_true' );`

This will enable the following WP hooks when importing the customizer data: `customize_save`, `customize_save_*`, `customize_save_after`.


= How to configure the multi grid layout import popup confirmation? =

If you want to disable the popup confirmation modal window, use this filter:

`add_filter( 'pt-ocdi/enable_grid_layout_import_popup_confirmation', '__return_false' );`

If you want to just change some options for the jQuery modal window we use for the popup confirmation, then use this filter:

`
function my_theme_ocdi_confirmation_dialog_options ( $options ) {
	return array_merge( $options, array(
		'width'       => 300,
		'dialogClass' => 'wp-dialog',
		'resizable'   => false,
		'height'      => 'auto',
		'modal'       => true,
	) );
}
add_filter( 'pt-ocdi/confirmation_dialog_options', 'my_theme_ocdi_confirmation_dialog_options', 10, 1 );
`

= How can I disable the ProteusThemes branding notice after successful demo import? =

You can disable the branding notice with a WP filter. All you need to do is add this bit of code to your theme:

`add_filter( 'pt-ocdi/disable_pt_branding', '__return_true' );`

and the notice will not be displayed.

= How can I pass Amazon S3 presigned URL's (temporary links) as external files ? =

If you want to host your import content files on Amazon S3, but you want them to be publicly available, rather through an own API as presigned URL's (which expires) you can use the filter `pt-ocdi/pre_download_import_files` in which you can pass your own URL's, for example:

```
add_filter( 'pt-ocdi/pre_download_import_files', function( $import_file_info ){

	// In this example `get_my_custom_urls` is supposedly making a `wp_remote_get` request, getting the urls from an API server where you're creating the presigned urls, [example here](https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/s3-presigned-url.html).
	// This request should return an array containing all the 3 links - `import_file_url`, `import_widget_file_url`, `import_customizer_file_url`
	$request = get_my_custom_urls( $import_file_info );

	if ( !is_wp_error( $request ) )
	{
		if ( isset($request['data']) && is_array($request['data']) )
		{
			if( isset($request['data']['import_file_url']) && $import_file_url = $request['data']['import_file_url'] ){
				$import_file_info['import_file_url'] = $import_file_url;
			}
			if( isset($request['data']['import_widget_file_url']) && $import_widget_file_url = $request['data']['import_widget_file_url'] ){
				$import_file_info['import_widget_file_url'] = $import_widget_file_url;
			}
			if( isset($request['data']['import_customizer_file_url']) && $import_customizer_file_url = $request['data']['import_customizer_file_url'] ){
				$import_file_info['import_customizer_file_url'] = $import_customizer_file_url;
			}
		}
	}

	return $import_file_info;

} );
```

= I can't activate the plugin, because of a fatal error, what can I do? =

*Update: since version 1.2.0, there is now a admin error notice, stating that the minimal PHP version required for this plugin is 5.3.2.*

You want to activate the plugin, but this error shows up:

*Plugin could not be activated because it triggered a fatal error*

This happens, because your hosting server is using a very old version of PHP. This plugin requires PHP version of at least **5.3.x**, but we recommend version *5.6.x* or better yet *7.x*. Please contact your hosting company and ask them to update the PHP version for your site.

= Issues with the import, that we can't fix in the plugin =

Please visit this [docs page](https://github.com/awesomemotive/one-click-demo-import/blob/master/docs/import-problems.md), for more answers to issues with importing data.

== Screenshots ==

1. Example of multiple predefined demo imports, that a user can choose from.
2. How the import page looks like, when only one demo import is predefined.
3. Example of how the import page looks like, when no demo imports are predefined a.k.a manual import.

== Changelog ==

= 2.6.1 =

*Release Date - 21 July 2020*

* Fixed Elementor import issues.

= 2.6.0 =

*Release Date - 21 July 2020*

* Improved code execution: not loading plugin code on frontend.
* Fixed incorrect post and post meta import (unicode and other special characters were not escaped properly).
* Fixed error (500 - internal error) for Widgets import on PHP 7.x.
* Fixed PHP notices for manual demo import.
* Fixed PHP warning if `set_time_limit` function is disabled.
* Fixed links for switching manual and predefined import modes.

= 2.5.2 =

*Release Date - 29 July 2019*

* Improved documentation and code sample
* Added `pt-ocdi/pre_download_import_files` filter
* Added two action hooks to plugin-page.php
* Bumped `Tested up to` tag

= 2.5.1 =

*Release Date - 25 October 2018*

* Fix missing translation strings

= 2.5.0 =

*Release Date - 8 January 2018*

* Add OCDI as a WordPress import tool in Tools -> Import,
* Add switching to the manual import, if the theme has predefined demo imports,
* Fix text domain loading

= 2.4.0 =

*Release Date - 23 August 2017*

* Add WP-CLI commands for importing with this plugin,
* Fix conflict with WooCommerce importer

= 2.3.0 =

*Release Date - 28 May 2017*

* Add preview button option to the predefined demo import items,
* Add custom JS event trigger when the import process is completed,
* Add custom filter for plugin page title,
* Remove content import as a required import. Now you can make separate imports for customizer, widgets or redux options.
* Fix custom menu widgets imports, the menus will now be set correctly.

= 2.2.1 =

*Release Date - 3 April 2017*

* Fix image importing error for server compressed files,
* Fix remapping of featured images,
* Fix custom post type existing posts check (no more multiple imports for custom post types).

= 2.2.0 =

*Release Date - 5 February 2017*

* Add ProteusThemes branding notice after successful import,
* Fix after import error reporting (duplicate errors were shown),
* Fix some undefined variables in the plugin, causing PHP notices.

= 2.1.0 =

*Release Date - 8 January 2017*

* Add grid layout import confirmation popup options filter,
* Fix term meta data double import,
* Fix WooCommerce product attributes import.

= 2.0.2 =

*Release Date - 13 December 2016*

* Fix issue with customizer options import

= 2.0.1 =

*Release Date - 12 December 2016*

* Fix issue with some browsers (Safari and IE) not supporting some FormData methods.

= 2.0.0 =

*Release Date - 10 December 2016*

* Add new layout for multiple predefined demo imports (a grid layout instead of the dropdown selector),
* Add support for Redux framework import,
* Change the code structure of the plugin (plugin rewrite, namespaces, autoloading),
* Now the whole import (content, widgets, customizer, redux) goes through even if something goes wrong in the content import (before content import errors blocked further import),
* Add `pt-ocdi/before_content_import` action hook, that theme authors can use to hook into before the content import starts,
* Fix frontend error reporting through multiple AJAX calls,
* Fix post formats (video/quote/gallery,...) not importing,
* Fix customizer import does not save some options (because of the missing WP actions - these can be enabled via a filter, more in the FAQ section).

= 1.4.0 =

*Release Date - 29 October 2016*

* Add support for WP term meta data in content importer,
* Fix the issue of having both plugins (OCDI and the new WP importer v2) activated at the same time.

= 1.3.0 =

*Release Date - 1 October 2016*

* Import/plugin page re-design. Updated the plugin page styles to match WordPress (thanks to Oliver Juhas).


= 1.2.0 =

*Release Date - 9 July 2016*

* Now also accepts predefined local import files (from theme folder),
* Fixes PHP fatal error on plugin activation, for sites using PHP versions older then 5.3.2 (added admin error notice),
* Register log file in *wp-admin -> Media*, so that it's easier to access,
* No more "[WARNING] Could not find the author for ..." messages in the log file.

= 1.1.3 =

*Release Date - 17 June 2016*

* Updated plugin design,
* Changed the plugin page setup filter name from `pt-ocdi/plugin-page-setup` to `pt-ocdi/plugin_page_setup` (mind the underscore characters instead of dashes).

= 1.1.2 =

*Release Date - 12 June 2016*

* An 'import notice' field has been added to the predefined demo import settings. This notice is displayed above the import button (it also accepts HTML),
* Now displays proper error message, if the file-system method is not set to "direct",
* This plugin is now compatible with the new [Humanmade content importer plugin](https://github.com/humanmade/WordPress-Importer),
* Added a filter to the plugin page creation, so that theme authors can now change the location of the plugin page (Demo data import) and some other parameters as well.


= 1.1.1 =

*Release Date - 22 May 2016*

* Preview import images can now be defined for multiple predefined import files (check FAQ "How to predefine demo imports?" for more info),
* You can now also import customizer settings.

= 1.1.0 =

*Release Date - 14 May 2016*

* Content import now imports in multiple AJAX calls, so there should be no more server timeout errors,
* The setting for generation of multiple image sizes in the content import is again enabled by default,
* Plugin textdomain was loaded, so that translations can be made.

= 1.0.3 =

*Release Date - 27 April 2016*

* Added filter to enable image regeneration,
* Added filter to change the plugin intro text,
* Added action to execute custom code before widget import,
* Disabled author imports.

= 1.0.2 =

*Release Date - 15 April 2016*

* Monkey fix for WP version 4.5. - disabled generation of multiple image sizes in the content import.

= 1.0.1 =

*Release Date - 2 April 2016*

Small code fixes:

* Fixed undefined variable bug,
* Fixed naming of downloaded files and their filters.

= 1.0.0 =

*Release Date - 25 March 2016*

* Initial release!
PK/3Y/�<��&bunyad-demo-import/assets/css/main.css.bunyad-import .intro-text {
	padding: 10px 15px;
	margin-top: 25px;
	margin-bottom: 32px;
    border-left: 4px solid #0073aa;
}

.bunyad-import .intro-text p {
	max-width: 1200px;
}

.bunyad-import .intro-text hr {
	margin: 14px 0;
}

.bunyad-import [name=import_type] {
	width: 90px;
}

.bunyad-import .spinner {
	display: inline-block;
	float: none;
	visibility: visible;
	margin: 0;
	margin-right: 3px;
    margin-bottom: 1px;	
}

.bunyad-import .theme-browser {
	margin-top: 25px;
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(330px, 1fr));
	grid-gap: 38px;
}

.bunyad-import .theme {
	width: auto !important;
	margin: 0 !important;
}

.bunyad-import .theme-browser .theme-name {
	font-size: 14px;
}

.bunyad-import .theme-actions {
	opacity: 1 !important;
}

.bunyad-depends-modal .plugin-names {
	list-style: decimal inside;
	margin-left: 10px;
}

.bunyad-depends-modal .form-buttons {
	margin: -15px;
	margin-top: 20px;
}PK/3YEN�PP$bunyad-demo-import/assets/js/main.js"use strict";

jQuery(function($) {
	var ajaxRun = 0;

	function ajaxCall(data) {
		
		ajaxRun++;
		
		// Been almost 15 minutes, that's enough
		if (ajaxRun > 30) {
			$('.bunyad-import .ajax-response').append('<div class="error  below-h2"><p>Could not complete the import. Please contact support.</p></div>');
			$('.bunyad-import .ajax-loader').remove();
			
			return;
		}
		
		$.ajax({
			method:     'POST',
			url:        Bunyad_Import.ajax_url,
			data:       data,
			beforeSend: function() {
				$('.bunyad-import .ajax-response').append(
					'<div class="notice ajax-loader"><p><span class="spinner"></span> Importing...</p></div>'
				);
			}
		})
		.done(function(response) {
			if ( 'undefined' !== typeof response.status && 'newAJAX' === response.status ) {
				ajaxCall(data);
			}
			else if ( 'undefined' !== typeof response.message ) {
				$('.bunyad-import .ajax-response').append( '<p>' + response.message + '</p>' );
				$('.bunyad-import .ajax-loader').remove();
			}
			else {
				$('.bunyad-import .ajax-response').append('<div class="error  below-h2"><p>' + response + '</p></div>');
				$('.bunyad-import .ajax-loader').remove();
			}

		})
		.fail(function(error) {
			$('.bunyad-import .ajax-response').append('<div class="error  below-h2"><p>Error: ' + error.statusText + ' (' + error.status + ')' + '. You may try the process again a few times. Refresh the page, select your demo and click Import.</p></div>');
			$('.bunyad-import .ajax-loader').remove();

			// Server has possibly hit the execution time, restart
			// ajaxCall(data);
		});
	}

	function handleDependencies(depends, srcBtn) {
		if (!depends || !Object.keys(depends).length) {
			return true;
		}

		const modal = $('#bunyad-missing-plugins');
		const form  = modal.find('form');
		const required = [];
		Object.keys(depends).forEach(key => {
			const plugin = depends[key];
			required.push(`<li>${plugin}</li>`);
			form.append(`<input type="hidden" name="plugin[]" value="${key}" />`);
		});

		modal.find('.plugin-names').html(required.join(''));

		// Handle plugin activation.
		form.find('input[type=submit]').on('click', function(e) {
			$(this).attr('disabled', true);
			$(this).val('Installing...');

			e.preventDefault();
			form.submit();
		});

		// Show modal.
		modal.dialog({
			title: 'Required Plugins',
			dialogClass: 'wp-dialog',
			autoOpen: false,
			draggable: false,
			width: 'auto',
			modal: true,
			resizable: false,
			closeOnEscape: true,
			position: {
				my: "center",
				at: "center",
				of: window
			},
			open: function () {
				// Close dialog by clicking the overlay behind it
				$('.ui-widget-overlay').bind('click', function() {
					modal.dialog('close');
				})
			},
			create: function () {
				$('.ui-dialog-titlebar-close').addClass('ui-button');
			},
		});

		modal.dialog('open');

		// Close the dialog, and restart import once plugins installed.
		setTimeout(() => {
			const iframe = modal.find('iframe');
			iframe.on('load', function() {
				modal.dialog('close');
				srcBtn.data('depends', []);
				srcBtn.click();
			});
		}, 50);

		return false;
	}

	
	// Run the importer
	$('.button.import').click(function() {

		// Ensure dependencies are met.
		// .data() will parse it.
		var data = $(this).data('depends');
		if (!handleDependencies(data, $(this))) {
			return;
		}
		
		ajaxCall({
			action: 'bunyad_import_demo',
			demo_id: $(this).data('id'),
			import_type: $(this).parent().find('[name=import_type]').val(),
			security: Bunyad_Import.ajax_nonce
		});
		
		// Scroll to response area if needed
		var scrollTo = $(".bunyad-import .ajax-response").offset().top - 75
		if ($(window).scrollTop() > scrollTo) {
			$('html, body').animate({
				scrollTop: scrollTo
			}, 100);
		}
		
		// disable all
		$('.button.import').attr('disabled', true).unbind('click');
	});
	
	// Remove
	$('.bunyad-import').on('click', 'a.cleanup', function() {
		var links = ($(this).data('remove')).split(','),
			current;
		
		var recursive = function() {
			current = links.shift();
			
			if (!current) {
				return;
			}
			
			$.get(current, function() {
				recursive();
			});
		};
		
		recursive();
		
	});
	
});
PK/3Y�Rww-bunyad-demo-import/inc/CustomizerImporter.php<?php
/**
 * Class for the customizer importer used in the One Click Demo Import plugin.
 *
 * Code is mostly from the Customizer Export/Import plugin.
 *
 * @see https://wordpress.org/plugins/customizer-export-import/
 * @package ocdi
 */

namespace OCDI;

class CustomizerImporter {
	/**
	 * Import customizer from a DAT file, generated by the Customizer Export/Import plugin.
	 *
	 * @param string $customizer_import_file_path path to the customizer import file.
	 */
	public static function import( $customizer_import_file_path ) {
		$ocdi          = OneClickDemoImport::get_instance();
		$log_file_path = $ocdi->get_log_file_path();

		// Try to import the customizer settings.
		$results = self::import_customizer_options( $customizer_import_file_path );

		// Check for errors, else write the results to the log file.
		if ( is_wp_error( $results ) ) {
			$error_message = $results->get_error_message();

			// Add any error messages to the frontend_error_messages variable in OCDI main class.
			$ocdi->append_to_frontend_error_messages( $error_message );

			// Write error to log file.
			Helpers::append_to_file(
				$error_message,
				$log_file_path,
				esc_html__( 'Importing customizer settings', 'pt-ocdi' )
			);
		}
		else {
			// Add this message to log file.
			$log_added = Helpers::append_to_file(
				esc_html__( 'Customizer settings import finished!', 'pt-ocdi' ),
				$log_file_path,
				esc_html__( 'Importing customizer settings' , 'pt-ocdi' )
			);
		}
	}


	/**
	 * Imports uploaded mods and calls WordPress core customize_save actions so
	 * themes that hook into them can act before mods are saved to the database.
	 *
	 * Update: WP core customize_save actions were removed, because of some errors.
	 *
	 * @since 1.1.1
	 * @param string $import_file_path Path to the import file.
	 * @return void|WP_Error
	 */
	public static function import_customizer_options( $import_file_path ) {
		// Setup global vars.
		global $wp_customize;

		// Setup internal vars.
		$template = get_template();

		// Make sure we have an import file.
		if ( ! file_exists( $import_file_path ) ) {
			return new \WP_Error(
				'missing_cutomizer_import_file',
				sprintf(
					esc_html__( 'Error: The customizer import file is missing! File path: %s', 'pt-ocdi' ),
					$import_file_path
				)
			);
		}

		// Get the upload data.
		$raw = Helpers::data_from_file( $import_file_path );

		// Make sure we got the data.
		if ( is_wp_error( $raw ) ) {
			return $raw;
		}

		$data = unserialize( $raw );

		// Data checks.
		if ( ! is_array( $data ) && ( ! isset( $data['template'] ) || ! isset( $data['mods'] ) ) ) {
			return new \WP_Error(
				'customizer_import_data_error',
				esc_html__( 'Error: The customizer import file is not in a correct format. Please make sure to use the correct customizer import file.', 'pt-ocdi' )
			);
		}
		if ( $data['template'] !== $template ) {
			return new \WP_Error(
				'customizer_import_wrong_theme',
				esc_html__( 'Error: The customizer import file is not suitable for current theme. You can only import customizer settings for the same theme or a child theme.', 'pt-ocdi' )
			);
		}

		// Import images.
		if ( apply_filters( 'pt-ocdi/customizer_import_images', true ) ) {
			$data['mods'] = self::import_customizer_images( $data['mods'] );
		}

		// Import custom options.
		if ( isset( $data['options'] ) ) {
			// Require modified customizer options class.
			if ( ! class_exists( '\WP_Customize_Setting' ) ) {
				require_once ABSPATH . 'wp-includes/class-wp-customize-setting.php';
			}

			foreach ( $data['options'] as $option_key => $option_value ) {
				$option = new CustomizerOption( $wp_customize, $option_key, array(
					'default'    => '',
					'type'       => 'option',
					'capability' => 'edit_theme_options',
				) );

				$option->import( $option_value );
			}
		}

		// Should the customizer import use the WP customize_save* hooks?
		$use_wp_customize_save_hooks = apply_filters( 'pt-ocdi/enable_wp_customize_save_hooks', false );

		if ( $use_wp_customize_save_hooks ) {
			do_action( 'customize_save', $wp_customize );
		}

		// Loop through the mods and save the mods.
		foreach ( $data['mods'] as $key => $val ) {
			if ( $use_wp_customize_save_hooks ) {
				do_action( 'customize_save_' . $key, $wp_customize );
			}

			set_theme_mod( $key, $val );
		}

		if ( $use_wp_customize_save_hooks ) {
			do_action( 'customize_save_after', $wp_customize );
		}
	}

	/**
	 * Helper function: Customizer import - imports images for settings saved as mods.
	 *
	 * @since 1.1.1
	 * @param array $mods An array of customizer mods.
	 * @return array The mods array with any new import data.
	 */
	private static function import_customizer_images( $mods ) {
		foreach ( $mods as $key => $val ) {
			if ( self::customizer_is_image_url( $val ) ) {
				$data = self::customizer_sideload_image( $val );
				if ( ! is_wp_error( $data ) ) {
					$mods[ $key ] = $data->url;

					// Handle header image controls.
					if ( isset( $mods[ $key . '_data' ] ) ) {
						$mods[ $key . '_data' ] = $data;
						update_post_meta( $data->attachment_id, '_wp_attachment_is_custom_header', get_stylesheet() );
					}
				}
			}
		}

		return $mods;
	}

	/**
	 * Helper function: Customizer import
	 * Taken from the core media_sideload_image function and
	 * modified to return an array of data instead of html.
	 *
	 * @since 1.1.1.
	 * @param string $file The image file path.
	 * @return array An array of image data.
	 */
	private static function customizer_sideload_image( $file ) {
		$data = new \stdClass();

		if ( ! function_exists( 'media_handle_sideload' ) ) {
			require_once( ABSPATH . 'wp-admin/includes/media.php' );
			require_once( ABSPATH . 'wp-admin/includes/file.php' );
			require_once( ABSPATH . 'wp-admin/includes/image.php' );
		}
		if ( ! empty( $file ) ) {
			// Set variables for storage, fix file filename for query strings.
			preg_match( '/[^\?]+\.(jpe?g|jpe|gif|png)\b/i', $file, $matches );
			$file_array = array();
			$file_array['name'] = basename( $matches[0] );

			// Download file to temp location.
			$file_array['tmp_name'] = download_url( $file );

			// If error storing temporarily, return the error.
			if ( is_wp_error( $file_array['tmp_name'] ) ) {
				return $file_array['tmp_name'];
			}

			// Do the validation and storage stuff.
			$id = media_handle_sideload( $file_array, 0 );

			// If error storing permanently, unlink.
			if ( is_wp_error( $id ) ) {
				unlink( $file_array['tmp_name'] );
				return $id;
			}

			// Build the object to return.
			$meta                = wp_get_attachment_metadata( $id );
			$data->attachment_id = $id;
			$data->url           = wp_get_attachment_url( $id );
			$data->thumbnail_url = wp_get_attachment_thumb_url( $id );
			$data->height        = $meta['height'];
			$data->width         = $meta['width'];
		}

		return $data;
	}

	/**
	 * Checks to see whether a string is an image url or not.
	 *
	 * @since 1.1.1
	 * @param string $string The string to check.
	 * @return bool Whether the string is an image url or not.
	 */
	private static function customizer_is_image_url( $string = '' ) {
		if ( is_string( $string ) ) {
			if ( preg_match( '/\.(jpg|jpeg|png|gif)/i', $string ) ) {
				return true;
			}
		}

		return false;
	}
}
PK/3Y4C���+bunyad-demo-import/inc/CustomizerOption.php<?php
/**
 * A class that extends WP_Customize_Setting so we can access
 * the protected updated method when importing options.
 *
 * Used in the Customizer importer.
 *
 * @since 1.1.1
 * @package ocdi
 */

namespace OCDI;

final class CustomizerOption extends \WP_Customize_Setting {
	/**
	 * Import an option value for this setting.
	 *
	 * @since 1.1.1
	 * @param mixed $value The option value.
	 * @return void
	 */
	public function import( $value ) {
		$this->update( $value );
	}
}
PK/3YB�hG��%bunyad-demo-import/inc/Downloader.php<?php
/**
 * Class for downloading a file from a given URL.
 *
 * @package ocdi
 */

namespace OCDI;

class Downloader {
	/**
	 * Holds full path to where the files will be saved.
	 *
	 * @var string
	 */
	private $download_directory_path = '';

	/**
	 * Constructor method.
	 *
	 * @param string $download_directory_path Full path to where the files will be saved.
	 */
	public function __construct( $download_directory_path = '' ) {
		$this->set_download_directory_path( $download_directory_path );
	}


	/**
	 * Download file from a given URL.
	 *
	 * @param string $url URL of file to download.
	 * @param string $filename Filename of the file to save.
	 * @return string|WP_Error Full path to the downloaded file or WP_Error object with error message.
	 */
	public function download_file( $url, $filename ) {
		$content = $this->get_content_from_url( $url );

		// Check if there was an error and break out.
		if ( is_wp_error( $content ) ) {
			return $content;
		}

		return Helpers::write_to_file( $content, $this->download_directory_path . $filename );
	}


	/**
	 * Helper function: get content from an URL.
	 *
	 * @param string $url URL to the content file.
	 * @return string|WP_Error, content from the URL or WP_Error object with error message.
	 */
	private function get_content_from_url( $url ) {
		// Test if the URL to the file is defined.
		if ( empty( $url ) ) {
			return new \WP_Error(
				'missing_url',
				__( 'Missing URL for downloading a file!', 'pt-ocdi' )
			);
		}

		// Get file content from the server.
		$response = wp_remote_get(
			$url,
			array( 'timeout' => apply_filters( 'pt-ocdi/timeout_for_downloading_import_file', 20 ) )
		);

		// Test if the get request was not successful.
		if ( is_wp_error( $response ) || 200 !== $response['response']['code'] ) {
			// Collect the right format of error data (array or WP_Error).
			$response_error = $this->get_error_from_response( $response );

			return new \WP_Error(
				'download_error',
				sprintf(
					__( 'An error occurred while fetching file from: %1$s%2$s%3$s!%4$sReason: %5$s - %6$s.', 'pt-ocdi' ),
					'<strong>',
					$url,
					'</strong>',
					'<br>',
					$response_error['error_code'],
					$response_error['error_message']
				) . '<br>' .
				apply_filters( 'pt-ocdi/message_after_file_fetching_error', '' )
			);
		}

		// Return content retrieved from the URL.
		return wp_remote_retrieve_body( $response );
	}


	/**
	 * Helper function: get the right format of response errors.
	 *
	 * @param array|WP_Error $response Array or WP_Error or the response.
	 * @return array Error code and error message.
	 */
	private function get_error_from_response( $response ) {
		$response_error = array();

		if ( is_array( $response ) ) {
			$response_error['error_code']    = $response['response']['code'];
			$response_error['error_message'] = $response['response']['message'];
		}
		else {
			$response_error['error_code']    = $response->get_error_code();
			$response_error['error_message'] = $response->get_error_message();
		}

		return $response_error;
	}


	/**
	 * Get download_directory_path attribute.
	 */
	public function get_download_directory_path() {
		return $this->download_directory_path;
	}


	/**
	 * Set download_directory_path attribute.
	 * If no valid path is specified, the default WP upload directory will be used.
	 *
	 * @param string $download_directory_path Path, where the files will be saved.
	 */
	public function set_download_directory_path( $download_directory_path ) {
		if ( file_exists( $download_directory_path ) ) {
			$this->download_directory_path = $download_directory_path;
		}
		else {
			$upload_dir = wp_upload_dir();
			$this->download_directory_path = apply_filters( 'pt-ocdi/upload_file_path', trailingslashit( $upload_dir['path'] ) );
		}
	}
}
PK/3YԠH:�V�V"bunyad-demo-import/inc/Helpers.php<?php
/**
 * Static functions used in the OCDI plugin.
 *
 * @package ocdi
 */

namespace OCDI;

/**
 * Class with static helper functions.
 */
class Helpers {
	/**
	 * Holds the date and time string for demo import and log file.
	 *
	 * @var string
	 */
	public static $demo_import_start_time = '';

	/**
	 * Filter through the array of import files and get rid of those who do not comply.
	 *
	 * @param  array $import_files list of arrays with import file details.
	 * @return array list of filtered arrays.
	 */
	public static function validate_import_file_info( $import_files ) {
		$filtered_import_file_info = array();

		foreach ( $import_files as $import_file ) {
			if ( self::is_import_file_info_format_correct( $import_file ) ) {
				$filtered_import_file_info[] = $import_file;
			}
		}

		return $filtered_import_file_info;
	}


	/**
	 * Helper function: a simple check for valid import file format.
	 *
	 * @param  array $import_file_info array with import file details.
	 * @return boolean
	 */
	private static function is_import_file_info_format_correct( $import_file_info ) {
		if ( empty( $import_file_info['import_file_name'] ) ) {
			return false;
		}

		return true;
	}


	/**
	 * Download import files. Content .xml and widgets .wie|.json files.
	 *
	 * @param  array  $import_file_info array with import file details.
	 * @return array|WP_Error array of paths to the downloaded files or WP_Error object with error message.
	 */
	public static function download_import_files( $import_file_info ) {
		$downloaded_files = array(
			'content'    => '',
			'widgets'    => '',
			'customizer' => '',
			'redux'      => '',
		);
		$downloader = new Downloader();

		$import_file_info = apply_filters('pt-ocdi/pre_download_import_files', $import_file_info);

		// ----- Set content file path -----
		// Check if 'import_file_url' is not defined. That would mean a local file.
		if ( empty( $import_file_info['import_file_url'] ) ) {
			if ( file_exists( $import_file_info['local_import_file'] ) ) {
				$downloaded_files['content'] = $import_file_info['local_import_file'];
			}
		}
		else {
			// Set the filename string for content import file.
			$content_filename = apply_filters( 'pt-ocdi/downloaded_content_file_prefix', 'demo-content-import-file_' ) . self::$demo_import_start_time . apply_filters( 'pt-ocdi/downloaded_content_file_suffix_and_file_extension', '.xml' );

			// Download the content import file.
			$downloaded_files['content'] = $downloader->download_file( $import_file_info['import_file_url'], $content_filename );

			// Return from this function if there was an error.
			if ( is_wp_error( $downloaded_files['content'] ) ) {
				return $downloaded_files['content'];
			}
		}

		// ----- Set widget file path -----
		// Get widgets file as well. If defined!
		if ( ! empty( $import_file_info['import_widget_file_url'] ) ) {
			// Set the filename string for widgets import file.
			$widget_filename = apply_filters( 'pt-ocdi/downloaded_widgets_file_prefix', 'demo-widgets-import-file_' ) . self::$demo_import_start_time . apply_filters( 'pt-ocdi/downloaded_widgets_file_suffix_and_file_extension', '.json' );

			// Download the widgets import file.
			$downloaded_files['widgets'] = $downloader->download_file( $import_file_info['import_widget_file_url'], $widget_filename );

			// Return from this function if there was an error.
			if ( is_wp_error( $downloaded_files['widgets'] ) ) {
				return $downloaded_files['widgets'];
			}
		}
		else if ( ! empty( $import_file_info['local_import_widget_file'] ) ) {
			if ( file_exists( $import_file_info['local_import_widget_file'] ) ) {
				$downloaded_files['widgets'] = $import_file_info['local_import_widget_file'];
			}
		}

		// ----- Set customizer file path -----
		// Get customizer import file as well. If defined!
		if ( ! empty( $import_file_info['import_customizer_file_url'] ) ) {
			// Setup filename path to save the customizer content.
			$customizer_filename = apply_filters( 'pt-ocdi/downloaded_customizer_file_prefix', 'demo-customizer-import-file_' ) . self::$demo_import_start_time . apply_filters( 'pt-ocdi/downloaded_customizer_file_suffix_and_file_extension', '.dat' );

			// Download the customizer import file.
			$downloaded_files['customizer'] = $downloader->download_file( $import_file_info['import_customizer_file_url'], $customizer_filename );

			// Return from this function if there was an error.
			if ( is_wp_error( $downloaded_files['customizer'] ) ) {
				return $downloaded_files['customizer'];
			}
		}
		else if ( ! empty( $import_file_info['local_import_customizer_file'] ) ) {
			if ( file_exists( $import_file_info['local_import_customizer_file'] ) ) {
				$downloaded_files['customizer'] = $import_file_info['local_import_customizer_file'];
			}
		}

		// ----- Set Redux file paths -----
		// Get Redux import file as well. If defined!
		if ( ! empty( $import_file_info['import_redux'] ) && is_array( $import_file_info['import_redux'] ) ) {
			$redux_items = array();

			// Setup filename paths to save the Redux content.
			foreach ( $import_file_info['import_redux'] as $index => $redux_item ) {
				$redux_filename = apply_filters( 'pt-ocdi/downloaded_redux_file_prefix', 'demo-redux-import-file_' ) . $index . '-' . self::$demo_import_start_time . apply_filters( 'pt-ocdi/downloaded_redux_file_suffix_and_file_extension', '.json' );

				// Download the Redux import file.
				$file_path = $downloader->download_file( $redux_item['file_url'], $redux_filename );

				// Return from this function if there was an error.
				if ( is_wp_error( $file_path ) ) {
					return $file_path;
				}

				$redux_items[] = array(
					'option_name' => $redux_item['option_name'],
					'file_path'   => $file_path,
				);
			}

			// Download the Redux import file.
			$downloaded_files['redux'] = $redux_items;
		}
		else if ( ! empty( $import_file_info['local_import_redux'] ) ) {

			$redux_items = array();

			// Setup filename paths to save the Redux content.
			foreach ( $import_file_info['local_import_redux'] as $redux_item ) {
				if ( file_exists( $redux_item['file_path'] ) ) {
					$redux_items[] = $redux_item;
				}
			}

			// Download the Redux import file.
			$downloaded_files['redux'] = $redux_items;
		}

		return $downloaded_files;
	}


	/**
	 * Write content to a file.
	 *
	 * @param string $content content to be saved to the file.
	 * @param string $file_path file path where the content should be saved.
	 * @return string|WP_Error path to the saved file or WP_Error object with error message.
	 */
	public static function write_to_file( $content, $file_path ) {
		// Verify WP file-system credentials.
		$verified_credentials = self::check_wp_filesystem_credentials();

		if ( is_wp_error( $verified_credentials ) ) {
			return $verified_credentials;
		}

		// By this point, the $wp_filesystem global should be working, so let's use it to create a file.
		global $wp_filesystem;

		if ( ! $wp_filesystem->put_contents( $file_path, $content ) ) {
			return new \WP_Error(
				'failed_writing_file_to_server',
				sprintf(
					__( 'An error occurred while writing file to your server! Tried to write a file to: %s%s.', 'pt-ocdi' ),
					'<br>',
					$file_path
				)
			);
		}

		// Return the file path on successful file write.
		return $file_path;
	}


	/**
	 * Append content to the file.
	 *
	 * @param string $content content to be saved to the file.
	 * @param string $file_path file path where the content should be saved.
	 * @param string $separator_text separates the existing content of the file with the new content.
	 * @return boolean|WP_Error, path to the saved file or WP_Error object with error message.
	 */
	public static function append_to_file( $content, $file_path, $separator_text = '' ) {
		// Verify WP file-system credentials.
		$verified_credentials = self::check_wp_filesystem_credentials();

		if ( is_wp_error( $verified_credentials ) ) {
			return $verified_credentials;
		}

		// By this point, the $wp_filesystem global should be working, so let's use it to create a file.
		global $wp_filesystem;

		$existing_data = '';
		if ( file_exists( $file_path ) ) {
			$existing_data = $wp_filesystem->get_contents( $file_path );
		}

		// Style separator.
		$separator = PHP_EOL . '---' . $separator_text . '---' . PHP_EOL;

		if ( ! $wp_filesystem->put_contents( $file_path, $existing_data . $separator . $content . PHP_EOL ) ) {
			return new \WP_Error(
				'failed_writing_file_to_server',
				sprintf(
					__( 'An error occurred while writing file to your server! Tried to write a file to: %s%s.', 'pt-ocdi' ),
					'<br>',
					$file_path
				)
			);
		}

		return true;
	}


	/**
	 * Get data from a file
	 *
	 * @param string $file_path file path where the content should be saved.
	 * @return string $data, content of the file or WP_Error object with error message.
	 */
	public static function data_from_file( $file_path ) {
		// Verify WP file-system credentials.
		$verified_credentials = self::check_wp_filesystem_credentials();

		if ( is_wp_error( $verified_credentials ) ) {
			return $verified_credentials;
		}

		// By this point, the $wp_filesystem global should be working, so let's use it to read a file.
		global $wp_filesystem;

		$data = $wp_filesystem->get_contents( $file_path );

		if ( ! $data ) {
			return new \WP_Error(
				'failed_reading_file_from_server',
				sprintf(
					__( 'An error occurred while reading a file from your server! Tried reading file from path: %s%s.', 'pt-ocdi' ),
					'<br>',
					$file_path
				)
			);
		}

		// Return the file data.
		return $data;
	}


	/**
	 * Helper function: check for WP file-system credentials needed for reading and writing to a file.
	 *
	 * @return boolean|WP_Error
	 */
	private static function check_wp_filesystem_credentials() {
		// Check if the file-system method is 'direct', if not display an error.
		if ( ! ( 'direct' === get_filesystem_method() ) ) {
			return new \WP_Error(
				'no_direct_file_access',
				sprintf(
					__( 'This WordPress page does not have %sdirect%s write file access. This plugin needs it in order to save the demo import xml file to the upload directory of your site. You can change this setting with these instructions: %s.', 'pt-ocdi' ),
					'<strong>',
					'</strong>',
					'<a href="http://gregorcapuder.com/wordpress-how-to-set-direct-filesystem-method/" target="_blank">How to set <strong>direct</strong> filesystem method</a>'
				)
			);
		}

		// Get plugin page settings.
		$plugin_page_setup = apply_filters( 'pt-ocdi/plugin_page_setup', array(
				'parent_slug' => 'themes.php',
				'page_title'  => esc_html__( 'One Click Demo Import' , 'pt-ocdi' ),
				'menu_title'  => esc_html__( 'Import Demo Data' , 'pt-ocdi' ),
				'capability'  => 'import',
				'menu_slug'   => 'pt-one-click-demo-import',
			)
		);

		// Get user credentials for WP file-system API.
		$demo_import_page_url = wp_nonce_url( $plugin_page_setup['parent_slug'] . '?page=' . $plugin_page_setup['menu_slug'], $plugin_page_setup['menu_slug'] );

		if ( false === ( $creds = request_filesystem_credentials( $demo_import_page_url, '', false, false, null ) ) ) {
			return new \WP_error(
				'filesystem_credentials_could_not_be_retrieved',
				__( 'An error occurred while retrieving reading/writing permissions to your server (could not retrieve WP filesystem credentials)!', 'pt-ocdi' )
			);
		}

		// Now we have credentials, try to get the wp_filesystem running.
		if ( ! WP_Filesystem( $creds ) ) {
			return new \WP_Error(
				'wrong_login_credentials',
				__( 'Your WordPress login credentials don\'t allow to use WP_Filesystem!', 'pt-ocdi' )
			);
		}

		return true;
	}


	/**
	 * Get log file path
	 *
	 * @return string, path to the log file
	 */
	public static function get_log_path() {
		$upload_dir  = wp_upload_dir();
		$upload_path = apply_filters( 'pt-ocdi/upload_file_path', trailingslashit( $upload_dir['path'] ) );

		$log_path = $upload_path 
			. apply_filters( 'pt-ocdi/log_file_prefix', 'log_file_' ) 
			. self::$demo_import_start_time 
			// +EDIT: Random string
			. wp_rand(99999)
			. apply_filters( 'pt-ocdi/log_file_suffix_and_file_extension', '.txt' );

		self::register_file_as_media_attachment( $log_path );

		return $log_path;
	}


	/**
	 * Register file as attachment to the Media page.
	 *
	 * @param string $log_path log file path.
	 * @return void
	 */
	public static function register_file_as_media_attachment( $log_path ) {
		// Check the type of file.
		$log_mimes = array( 'txt' => 'text/plain' );
		$filetype  = wp_check_filetype( basename( $log_path ), apply_filters( 'pt-ocdi/file_mimes', $log_mimes ) );

		// Prepare an array of post data for the attachment.
		$attachment = array(
			'guid'           => self::get_log_url( $log_path ),
			'post_mime_type' => $filetype['type'],
			'post_title'     => apply_filters( 'pt-ocdi/attachment_prefix', esc_html__( 'One Click Demo Import - ', 'pt-ocdi' ) ) . preg_replace( '/\.[^.]+$/', '', basename( $log_path ) ),
			'post_content'   => '',
			'post_status'    => 'inherit',
		);

		// Insert the file as attachment in Media page.
		$attach_id = wp_insert_attachment( $attachment, $log_path );
	}


	/**
	 * Get log file url
	 *
	 * @param string $log_path log path to use for the log filename.
	 * @return string, url to the log file.
	 */
	public static function get_log_url( $log_path ) {
		$upload_dir = wp_upload_dir();
		$upload_url = apply_filters( 'pt-ocdi/upload_file_url', trailingslashit( $upload_dir['url'] ) );

		return $upload_url . basename( $log_path );
	}


	/**
	 * Check if the AJAX call is valid.
	 */
	public static function verify_ajax_call() {
		check_ajax_referer( 'ocdi-ajax-verification', 'security' );

		// Check if user has the WP capability to import data.
		if ( ! current_user_can( 'import' ) ) {
			wp_die(
				sprintf(
					__( '%sYour user role isn\'t high enough. You don\'t have permission to import demo data.%s', 'pt-ocdi' ),
					'<div class="notice  notice-error"><p>',
					'</p></div>'
				)
			);
		}
	}


	/**
	 * Process uploaded files and return the paths to these files.
	 *
	 * @param array  $uploaded_files $_FILES array form an AJAX request.
	 * @param string $log_file_path path to the log file.
	 * @return array of paths to the content import and widget import files.
	 */
	public static function process_uploaded_files( $uploaded_files, $log_file_path ) {
		// Variable holding the paths to the uploaded files.
		$selected_import_files = array(
			'content'    => '',
			'widgets'    => '',
			'customizer' => '',
			'redux'      => '',
		);

		// Upload settings to disable form and type testing for AJAX uploads.
		$upload_overrides = array(
			'test_form' => false,
			'test_type' => false,
		);

		// Error data if the demo file was not provided.
		$file_not_provided_error = array(
			'error' => esc_html__( 'No file provided.', 'pt-ocdi' )
		);

		// Handle demo file uploads.
		$content_file_info = isset( $_FILES['content_file'] ) ?
			wp_handle_upload( $_FILES['content_file'], $upload_overrides ) :
			$file_not_provided_error;

		$widget_file_info = isset( $_FILES['widget_file'] ) ?
			wp_handle_upload( $_FILES['widget_file'], $upload_overrides ) :
			$file_not_provided_error;

		$customizer_file_info = isset( $_FILES['customizer_file'] ) ?
			wp_handle_upload( $_FILES['customizer_file'], $upload_overrides ) :
			$file_not_provided_error;

		$redux_file_info = isset( $_FILES['customizer_file'] ) ?
			wp_handle_upload( $_FILES['redux_file'], $upload_overrides ) :
			$file_not_provided_error;

		// Process content import file.
		if ( $content_file_info && ! isset( $content_file_info['error'] ) ) {
			// Set uploaded content file.
			$selected_import_files['content'] = $content_file_info['file'];
		}
		else {
			// Add this error to log file.
			$log_added = self::append_to_file(
				sprintf(
					__( 'Content file was not uploaded. Error: %s', 'pt-ocdi' ),
					$content_file_info['error']
				),
				$log_file_path,
				esc_html__( 'Upload files' , 'pt-ocdi' )
			);
		}

		// Process widget import file.
		if ( $widget_file_info && ! isset( $widget_file_info['error'] ) ) {
			// Set uploaded widget file.
			$selected_import_files['widgets'] = $widget_file_info['file'];
		}
		else {
			// Add this error to log file.
			$log_added = self::append_to_file(
				sprintf(
					__( 'Widget file was not uploaded. Error: %s', 'pt-ocdi' ),
					$widget_file_info['error']
				),
				$log_file_path,
				esc_html__( 'Upload files' , 'pt-ocdi' )
			);
		}

		// Process Customizer import file.
		if ( $customizer_file_info && ! isset( $customizer_file_info['error'] ) ) {
			// Set uploaded customizer file.
			$selected_import_files['customizer'] = $customizer_file_info['file'];
		}
		else {
			// Add this error to log file.
			$log_added = self::append_to_file(
				sprintf(
					__( 'Customizer file was not uploaded. Error: %s', 'pt-ocdi' ),
					$customizer_file_info['error']
				),
				$log_file_path,
				esc_html__( 'Upload files' , 'pt-ocdi' )
			);
		}

		// Process Redux import file.
		if ( $redux_file_info && ! isset( $redux_file_info['error'] ) ) {
			if ( isset( $_POST['redux_option_name'] ) && empty( $_POST['redux_option_name'] ) ) {
				// Write error to log file and send an AJAX response with the error.
				self::log_error_and_send_ajax_response(
					esc_html__( 'Missing Redux option name! Please also enter the Redux option name!', 'pt-ocdi' ),
					$log_file_path,
					esc_html__( 'Upload files', 'pt-ocdi' )
				);
			}

			// Set uploaded Redux file.
			$selected_import_files['redux'] = array(
				array(
					'option_name' => $_POST['redux_option_name'],
					'file_path'   => $redux_file_info['file'],
				),
			);
		}
		else {
			// Add this error to log file.
			$log_added = self::append_to_file(
				sprintf(
					__( 'Redux file was not uploaded. Error: %s', 'pt-ocdi' ),
					$redux_file_info['error']
				),
				$log_file_path,
				esc_html__( 'Upload files' , 'pt-ocdi' )
			);
		}

		// Add this message to log file.
		$log_added = self::append_to_file(
			__( 'The import files were successfully uploaded!', 'pt-ocdi' ) . self::import_file_info( $selected_import_files ),
			$log_file_path,
			esc_html__( 'Upload files' , 'pt-ocdi' )
		);

		// Return array with paths of uploaded files.
		return $selected_import_files;
	}


	/**
	 * Get import file information and max execution time.
	 *
	 * @param array $selected_import_files array of selected import files.
	 */
	public static function import_file_info( $selected_import_files ) {
		$redux_file_string = '';

		if ( ! empty( $selected_import_files['redux'] ) ) {
			$redux_file_string = array_reduce( $selected_import_files['redux'], function( $string, $item ) {
				return sprintf( '%1$s%2$s -> %3$s %4$s', $string, $item['option_name'], $item['file_path'], PHP_EOL );
			}, '' );
		}

		return PHP_EOL .
		sprintf(
			__( 'Initial max execution time = %s', 'pt-ocdi' ),
			ini_get( 'max_execution_time' )
		) . PHP_EOL .
		sprintf(
			__( 'Files info:%1$sSite URL = %2$s%1$sData file = %3$s%1$sWidget file = %4$s%1$sCustomizer file = %5$s%1$sRedux files:%1$s%6$s', 'pt-ocdi' ),
			PHP_EOL,
			get_site_url(),
			empty( $selected_import_files['content'] ) ? esc_html__( 'not defined!', 'pt-ocdi' ) : basename($selected_import_files['content']),
			empty( $selected_import_files['widgets'] ) ? esc_html__( 'not defined!', 'pt-ocdi' ) : basename($selected_import_files['widgets']),
			empty( $selected_import_files['customizer'] ) ? esc_html__( 'not defined!', 'pt-ocdi' ) : basename($selected_import_files['customizer']),
			empty( $redux_file_string ) ? esc_html__( 'not defined!', 'pt-ocdi' ) : basename($redux_file_string)
		);
	}


	/**
	 * Write the error to the log file and send the AJAX response.
	 *
	 * @param string $error_text text to display in the log file and in the AJAX response.
	 * @param string $log_file_path path to the log file.
	 * @param string $separator title separating the old and new content.
	 */
	public static function log_error_and_send_ajax_response( $error_text, $log_file_path, $separator = '' ) {
		// Add this error to log file.
		$log_added = self::append_to_file(
			$error_text,
			$log_file_path,
			$separator
		);

		// Send JSON Error response to the AJAX call.
		wp_send_json( $error_text );
	}


	/**
	 * Set the $demo_import_start_time class variable with the current date and time string.
	 */
	public static function set_demo_import_start_time() {
		self::$demo_import_start_time = date( apply_filters( 'pt-ocdi/date_format_for_file_names', 'Y-m-d__H-i-s' ) );
	}


	/**
	 * Get the category list of all categories used in the predefined demo imports array.
	 *
	 * @param  array $demo_imports Array of demo import items (arrays).
	 * @return array|boolean       List of all the categories or false if there aren't any.
	 */
	public static function get_all_demo_import_categories( $demo_imports ) {
		$categories = array();

		foreach ( $demo_imports as $item ) {
			if ( ! empty( $item['categories'] ) && is_array( $item['categories'] ) ) {
				foreach ( $item['categories'] as $category ) {
					$categories[ sanitize_key( $category ) ] = $category;
				}
			}
		}

		if ( empty( $categories ) ) {
			return false;
		}

		return $categories;
	}


	/**
	 * Return the concatenated string of demo import item categories.
	 * These should be separated by comma and sanitized properly.
	 *
	 * @param  array  $item The predefined demo import item data.
	 * @return string       The concatenated string of categories.
	 */
	public static function get_demo_import_item_categories( $item ) {
		$sanitized_categories = array();

		if ( isset( $item['categories'] ) ) {
			foreach ( $item['categories'] as $category ) {
				$sanitized_categories[] = sanitize_key( $category );
			}
		}

		if ( ! empty( $sanitized_categories ) ) {
			return implode( ',', $sanitized_categories );
		}

		return false;
	}


	/**
	 * Set the OCDI transient with the current importer data.
	 *
	 * @param array $data Data to be saved to the transient.
	 */
	public static function set_ocdi_import_data_transient( $data ) {
		set_transient( 'ocdi_importer_data', $data, 0.1 * HOUR_IN_SECONDS );
	}
}
PK/3Y� ���(bunyad-demo-import/inc/ImportActions.php<?php
/**
 * Class for the import actions used in the One Click Demo Import plugin.
 * Register default WP actions for OCDI plugin.
 *
 * @package ocdi
 */

namespace OCDI;

class ImportActions {
	/**
	 * Register all action hooks for this class.
	 */
	public function register_hooks() {
		// Before content import.
		add_action( 'pt-ocdi/before_content_import_execution', array( $this, 'before_content_import_action' ), 10, 3 );

		// After content import.
		add_action( 'pt-ocdi/after_content_import_execution', array( $this, 'before_widget_import_action' ), 10, 3 );
		add_action( 'pt-ocdi/after_content_import_execution', array( $this, 'widgets_import' ), 20, 3 );
		add_action( 'pt-ocdi/after_content_import_execution', array( $this, 'redux_import' ), 30, 3 );

		// Customizer import.
		add_action( 'pt-ocdi/customizer_import_execution', array( $this, 'customizer_import' ), 10, 1 );

		// After full import action.
		add_action( 'pt-ocdi/after_all_import_execution', array( $this, 'after_import_action' ), 10, 3 );

		// Special widget import cases.
		if ( apply_filters( 'pt_ocdi/enable_custom_menu_widget_ids_fix', true ) ) {
			add_action( 'pt-ocdi/widget_settings_array', array( $this, 'fix_custom_menu_widget_ids' ) );
		}
	}


	/**
	 * Change the menu IDs in the custom menu widgets in the widget import data.
	 * This solves the issue with custom menu widgets not having the correct (new) menu ID, because they
	 * have the old menu ID from the export site.
	 *
	 * @param array $widget The widget settings array.
	 */
	public function fix_custom_menu_widget_ids( $widget ) {
		// Skip (no changes needed), if this is not a custom menu widget.
		if ( ! array_key_exists( 'nav_menu', $widget ) || empty( $widget['nav_menu'] ) || ! is_int( $widget['nav_menu'] ) ) {
			return $widget;
		}

		// Get import data, with new menu IDs.
		$ocdi                = OneClickDemoImport::get_instance();
		$content_import_data = $ocdi->importer->get_importer_data();
		$term_ids            = $content_import_data['mapping']['term_id'];

		// Set the new menu ID for the widget.
		$widget['nav_menu'] = $term_ids[ $widget['nav_menu'] ];

		return $widget;
	}


	/**
	 * Execute the widgets import.
	 *
	 * @param array $selected_import_files Actual selected import files (content, widgets, customizer, redux).
	 * @param array $import_files          The filtered import files defined in `pt-ocdi/import_files` filter.
	 * @param int   $selected_index        Selected index of import.
	 */
	public function widgets_import( $selected_import_files, $import_files, $selected_index ) {
		if ( ! empty( $selected_import_files['widgets'] ) ) {
			WidgetImporter::import( $selected_import_files['widgets'] );
		}
	}


	/**
	 * Execute the Redux import.
	 *
	 * @param array $selected_import_files Actual selected import files (content, widgets, customizer, redux).
	 * @param array $import_files          The filtered import files defined in `pt-ocdi/import_files` filter.
	 * @param int   $selected_index        Selected index of import.
	 */
	public function redux_import( $selected_import_files, $import_files, $selected_index ) {
		if ( ! empty( $selected_import_files['redux'] ) ) {
			ReduxImporter::import( $selected_import_files['redux'] );
		}
	}


	/**
	 * Execute the customizer import.
	 *
	 * @param array $selected_import_files Actual selected import files (content, widgets, customizer, redux).
	 * @param array $import_files          The filtered import files defined in `pt-ocdi/import_files` filter.
	 * @param int   $selected_index        Selected index of import.
	 */
	public function customizer_import( $selected_import_files ) {
		if ( ! empty( $selected_import_files['customizer'] ) ) {
			CustomizerImporter::import( $selected_import_files['customizer'] );
		}
	}


	/**
	 * Execute the action: 'pt-ocdi/before_content_import'.
	 *
	 * @param array $selected_import_files Actual selected import files (content, widgets, customizer, redux).
	 * @param array $import_files          The filtered import files defined in `pt-ocdi/import_files` filter.
	 * @param int   $selected_index        Selected index of import.
	 */
	public function before_content_import_action( $selected_import_files, $import_files, $selected_index ) {
		$this->do_import_action( 'pt-ocdi/before_content_import', $import_files[ $selected_index ] );
	}


	/**
	 * Execute the action: 'pt-ocdi/before_widgets_import'.
	 *
	 * @param array $selected_import_files Actual selected import files (content, widgets, customizer, redux).
	 * @param array $import_files          The filtered import files defined in `pt-ocdi/import_files` filter.
	 * @param int   $selected_index        Selected index of import.
	 */
	public function before_widget_import_action( $selected_import_files, $import_files, $selected_index ) {
		$this->do_import_action( 'pt-ocdi/before_widgets_import', $import_files[ $selected_index ] );
	}


	/**
	 * Execute the action: 'pt-ocdi/after_import'.
	 *
	 * @param array $selected_import_files Actual selected import files (content, widgets, customizer, redux).
	 * @param array $import_files          The filtered import files defined in `pt-ocdi/import_files` filter.
	 * @param int   $selected_index        Selected index of import.
	 */
	public function after_import_action( $selected_import_files, $import_files, $selected_index ) {
		$this->do_import_action( 'pt-ocdi/after_import', $import_files[ $selected_index ] );
	}


	/**
	 * Register the do_action hook, so users can hook to these during import.
	 *
	 * @param string $action          The action name to be executed.
	 * @param array  $selected_import The data of selected import from `pt-ocdi/import_files` filter.
	 */
	private function do_import_action( $action, $selected_import ) {
		if ( false !== has_action( $action ) ) {
			$ocdi          = OneClickDemoImport::get_instance();
			$log_file_path = $ocdi->get_log_file_path();

			ob_start();
				do_action( $action, $selected_import );
			$message = ob_get_clean();

			// Add this message to log file.
			$log_added = Helpers::append_to_file(
				$message,
				$log_file_path,
				$action
			);
		}
	}
}
PK/3Y[��C��#bunyad-demo-import/inc/Importer.php<?php
/**
 * Class for declaring the content importer used in the One Click Demo Import plugin
 *
 * @package ocdi
 */

namespace OCDI;

class Importer {
	/**
	 * The importer class object used for importing content.
	 *
	 * @var object
	 */
	private $importer;

	/**
	 * Time in milliseconds, marking the beginning of the import.
	 *
	 * @var float
	 */
	private $microtime;

	/**
	 * The instance of the OCDI\Logger class.
	 *
	 * @var object
	 */
	public $logger;

	/**
	 * The instance of the One Click Demo Import class.
	 *
	 * @var object
	 */
	private $ocdi;

	/**
	 * Constructor method.
	 *
	 * @param array  $importer_options Importer options.
	 * @param object $logger           Logger object used in the importer.
	 */
	public function __construct( $importer_options = array(), $logger = null ) {
		// Include files that are needed for WordPress Importer v2.
		$this->include_required_files();

		// Set the WordPress Importer v2 as the importer used in this plugin.
		// More: https://github.com/humanmade/WordPress-Importer.
		$this->importer = new WXRImporter( $importer_options );

		// Set logger to the importer.
		$this->logger = $logger;
		if ( ! empty( $this->logger ) ) {
			$this->set_logger( $this->logger );
		}

		// Get the OCDI (main plugin class) instance.
		$this->ocdi = OneClickDemoImport::get_instance();
	}


	/**
	 * Include required files.
	 */
	private function include_required_files() {
		if ( ! class_exists( '\WP_Importer' ) ) {
			require ABSPATH . '/wp-admin/includes/class-wp-importer.php';
		}
	}


	/**
	 * Imports content from a WordPress export file.
	 *
	 * @param string $data_file path to xml file, file with WordPress export data.
	 */
	public function import( $data_file ) {
		$this->importer->import( $data_file );
	}


	/**
	 * Set the logger used in the import
	 *
	 * @param object $logger logger instance.
	 */
	public function set_logger( $logger ) {
		$this->importer->set_logger( $logger );
	}


	/**
	 * Get all protected variables from the WXR_Importer needed for continuing the import.
	 */
	public function get_importer_data() {
		return $this->importer->get_importer_data();
	}


	/**
	 * Sets all protected variables from the WXR_Importer needed for continuing the import.
	 *
	 * @param array $data with set variables.
	 */
	public function set_importer_data( $data ) {
		$this->importer->set_importer_data( $data );
	}


	/**
	 * Import content from an WP XML file.
	 *
	 * @param string $import_file_path Path to the import file.
	 */
	public function import_content( $import_file_path ) {
		$this->microtime = microtime( true );

		// Increase PHP max execution time. Just in case, even though the AJAX calls are only 25 sec long.
		if ( strpos( ini_get( 'disable_functions' ), 'set_time_limit' ) === false ) {
			set_time_limit( apply_filters( 'pt-ocdi/set_time_limit_for_demo_data_import', 300 ) );
		}

		// Disable import of authors.
		add_filter( 'wxr_importer.pre_process.user', '__return_false' );

		// Check, if we need to send another AJAX request and set the importing author to the current user.
		add_filter( 'wxr_importer.pre_process.post', array( $this, 'new_ajax_request_maybe' ) );

		// Disables generation of multiple image sizes (thumbnails) in the content import step.
		if ( ! apply_filters( 'pt-ocdi/regenerate_thumbnails_in_content_import', true ) ) {
			add_filter( 'intermediate_image_sizes_advanced', '__return_null' );
		}

		// Import content.
		if ( ! empty( $import_file_path ) ) {
			ob_start();
				$this->import( $import_file_path );
			$message = ob_get_clean();

			// +EDIT: Add logging.

			// Use this for debugging. Also have to enable 'debug' in OneClickDemoImport.php file
			// like so: 'logger_min_level' => 'debug',

			// To only log if logger_min_level was set to lower than error:
			//    if ($this->logger->level_to_numeric($this->logger->min_level) < $this->logger->level_to_numeric('error')) {
			$log_added = Helpers::append_to_file(
				$message,
				$this->ocdi->get_log_file_path(),
				esc_html__( 'Importing content' , 'pt-ocdi' )
			);
		}

		// Return any error messages for the front page output (errors, critical, alert and emergency level messages only).
		return $this->logger->error_output;
	}

	/**
	 * Check if we need to create a new AJAX request, so that server does not timeout.
	 *
	 * @param array $data current post data.
	 * @return array
	 */
	public function new_ajax_request_maybe( $data ) {
		$time = microtime( true ) - $this->microtime;

		// + Bunyad
		// Check if ini_get is enabled, if not default to 25s
		$exec_time = 25;
		if (function_exists('ini_get') && ($max_time = ini_get('max_execution_time'))) {
			// Set it to 50 secs, or 75% of execution time. Whichever's lower. 
			// Gateway timeouts usually are at 60 seconds.
			$exec_time = min(50, intval($max_time) * 0.75);
		}
		// / Bunyad

		// We should make a new ajax call, if the time is right.
		if ( $time > apply_filters( 'pt-ocdi/time_for_one_ajax_call', $exec_time ) ) {
			$response = array(
				'status'  => 'newAJAX',
				'message' => 'Time for new AJAX request!: ' . $time,
			);

			// Add any output to the log file and clear the buffers.
			$message = ob_get_clean();

			// Add any error messages to the frontend_error_messages variable in OCDI main class.
			if ( ! empty( $message ) ) {
				$this->ocdi->append_to_frontend_error_messages( $message );
			}

			// Add message to log file.
			$log_added = Helpers::append_to_file(
				__( 'New AJAX call!' , 'pt-ocdi' ) . PHP_EOL . $message,
				$this->ocdi->get_log_file_path(),
				''
			);

			// Set the current importer stat, so it can be continued on the next AJAX call.
			$this->set_current_importer_data();

			// Send the request for a new AJAX call.
			wp_send_json( $response );
		}

		// Set importing author to the current user.
		// Fixes the [WARNING] Could not find the author for ... log warning messages.
		$current_user_obj    = wp_get_current_user();
		$data['post_author'] = $current_user_obj->user_login;

		return $data;
	}


	/**
	 * Set current state of the content importer, so we can continue the import with new AJAX request.
	 */
	private function set_current_importer_data() {
		$data = array_merge( $this->ocdi->get_current_importer_data(), $this->get_importer_data() );

		Helpers::set_ocdi_import_data_transient( $data );
	}
}
PK/3YC��r��!bunyad-demo-import/inc/Logger.php<?php
/**
 * Logger class used in the One Click Demo Import plugin
 *
 * @package ocdi
 */

namespace OCDI;

class Logger extends \AwesomeMotive\WPContentImporter2\WPImporterLoggerCLI {
	/**
	 * Variable for front-end error display.
	 *
	 * @var string
	 */
	public $error_output = '';

	/**
	 * Overwritten log function from WP_Importer_Logger_CLI.
	 *
	 * Logs with an arbitrary level.
	 *
	 * @param mixed  $level level of reporting.
	 * @param string $message log message.
	 * @param array  $context context to the log message.
	 */
	public function log( $level, $message, array $context = array() ) {
		// Save error messages for front-end display.
		$this->error_output( $level, $message, $context = array() );

		if ( $this->level_to_numeric( $level ) < $this->level_to_numeric( $this->min_level ) ) {
			return;
		}

		printf(
			'[%s] %s' . PHP_EOL,
			strtoupper( $level ),
			$message
		);
	}


	/**
	 * Save messages for error output.
	 * Only the messages greater then Error.
	 *
	 * @param mixed  $level level of reporting.
	 * @param string $message log message.
	 * @param array  $context context to the log message.
	 */
	public function error_output( $level, $message, array $context = array() ) {
		if ( $this->level_to_numeric( $level ) < $this->level_to_numeric( 'error' ) ) {
			return;
		}

		$this->error_output .= sprintf(
			'[%s] %s<br>',
			strtoupper( $level ),
			$message
		);
	}
}
PK/3YTLR�� bunyad-demo-import/inc/menus.php<?php
/**
 * Import specified menus and the items.
 * 
 * @copyright ThemeSphere
 */
class Bunyad_Demo_Import_Menus
{
	public $items;
	public $menu_data;
	public $base_url;

	protected $random_cat_ids = [];
	protected $random_post_ids = [];
	
	public function __construct($menu_data = [], $base_url = '')
	{
		$this->menu_data = $menu_data;
		$this->base_url  = $base_url;
		
		if (!$this->base_url) {
			$this->base_url = untrailingslashit(get_bloginfo('url'));
		}
	}

	// public function map_term_ids($map)
	// {
	// 	foreach ($this->menu_data as $key => $menu) {
	// 		$this->menu_data[$key] = $this->replace_term_ids($menu, $map);
	// 	}
	// }

	// public function replace_term_ids($menu, $map) {

	// 	$items = [];
	// 	foreach ($menu['items'] as $key => $item) {

	// 		$items[$key] = $item;

	// 		if ($item['items']) {
	// 			$items[$key]['items'] = $this->replace_term_ids($item, $map);
	// 		}
	// 	}

	// 	if (count($items)) {
	// 		$menu['items'] = $items;
	// 	}

	// 	return $items;
	// }

	/**
	 * Begin importing the menu.
	 *
	 * @return void
	 */
	public function import()
	{
		// Add all the menus and their respective items.
		foreach ($this->menu_data as $menu) {
			$menu_id = $this->create_menu($menu);

			if (false !== $menu_id) {
				$this->add_to_menu($menu['items'], $menu_id);
			}
		}
	}

	/**
	 * Create a menu and add its items.
	 *
	 * @param array $menu
	 * @return void
	 */
	public function create_menu($menu) 
	{
		if (!isset($menu['label'])) {
			return;
		}

		// Test for existing.
		$menu_exists = get_term_by('name', $menu['label'], 'nav_menu');
		if ($menu_exists && is_object($menu_exists)) {
			$menu_id = $menu_exists->term_id;

			// Do the remaps below, but return false as a new menu wasn't created.
			$return  = false;
		}
		else {
			// Create new menu.
			$menu_id = wp_create_nav_menu($menu['label']);
			
			// Nothing to import?
			if (is_wp_error($menu_id) || !isset($menu['items'])) {
				return false;
			}

			$return  = $menu_id;
		}

		// Add location to the menu if specified.
		if (!empty($menu['location'])) {
			$menu_locations = (array) get_theme_mod('nav_menu_locations');
			set_theme_mod('nav_menu_locations', array_replace(
				$menu_locations,
				[
					$menu['location'] => $menu_id
				]
			));
		}

		// Update a bunyad option.
		if (!empty($menu['bunyad_option'])) {
			Bunyad::options()->set(
					$menu['bunyad_option'],
					$menu_id
				)
				->update();
		}

		return $return;
	}

	/**
	 * Add all items to a menu.
	 * 
	 * @param array   $items   Array of items to array 
	 * @param integer $menu_id Menu ID
	 * @param integer $parent  Parent Item ID.
	 * @param integer $position Position starts at 0 but continues globally recursively.
	 */
	public function add_to_menu($items = [], $menu_id = 0, $parent = 0, &$position = 0)
	{
		if (!$items) {
			$items = $this->items;
		}

		foreach ($items as $key => $item) {
			
			// Reset parent for current loop.
			$item_id = 0;

			// If type is unknown, fallback to custom.
			$item['type'] = empty($item['type']) ? 'custom' : $item['type'];

			// Base shared args for the nav item.
			$args = [
				'menu-item-status'    => 'publish',
				'menu-item-parent-id' => $parent,
				'menu-item-position'  => isset($item['order']) ? $item['order'] : $position,
				'menu-item-title'     => isset($item['title']) ? $item['title'] : ''
			];

			// Check menu type. Currently supports category, custom and post.
			switch ($item['type']) {

				/**
				 * Category item by slug or a random category (sorted post count).
				 */
				case 'category':
					if (!isset($item['slug'])) {
						continue 2;
					}

					$term = $this->get_category($item['slug']);
					if (!$term) {
						continue 2;
					}

					$item = array_replace($item, [
						'object'    => 'category',
						'object_id' => $term->term_id,
						'type'      => 'taxonomy',
					]);

					break;

				/**
				 * Add a post item using slug or a random latest post.
				 */
				case 'post':
				case 'page':

					$post = $this->get_post(
						isset($item['slug']) ? $item['slug'] : '',
						$item['type']
					);

					if (!$post) {
						continue 2;
					}

					$item = array_replace($item, [
						'object'    => $item['type'],
						'object_id' => $post->ID,
						'type'      => 'post_type',
					]);

					break;

				/**
				 * Custom item with title and url with an optional open target.
				 */
				case 'custom':

					// Title is required.
					if (!isset($item['title'])) {
						continue 2;
					}

					// Set URL to # if container or empty.
					$item_url = isset($item['url']) ? $item['url'] : '#';
					$item_url = str_replace('{base_url}', $this->base_url, $item_url);

					$args += [
						'menu-item-url' => $item_url,
						'menu-item-target' => isset($item['target']) ? $item['target'] : ''
					];

					break;

				// Unsupport type
				default:
					continue 2;
			}

			if (isset($item['object'])) {
				$args['menu-item-object'] = $item['object'];
			}

			if (isset($item['object_id'])) {
				$args['menu-item-object-id'] = $item['object_id'];
			}

			// Set the type of menu: taxonomy, custom, post_type etc.
			$args['menu-item-type'] = $item['type'];
			
			// Finally, add the menu item.
			$item_id = wp_update_nav_menu_item($menu_id, 0, $args);

			// Add menu item meta fields, such as for mega menu.
			if (!empty($item['meta'])) {
				foreach ((array) $item['meta'] as $mkey => $value) {
					update_post_meta($item_id, '_menu_item_' . $mkey, $value);
				}
			}
			
			// Increment the auto-position.
			$position++;

			// Recursively add any child items.
			if (!empty($item['items'])) {
				$this->add_to_menu($item['items'], $menu_id, $item_id, $position);
			}
		}
	}

	/**
	 * Get the specified post by slug or a random post if not found.
	 * 
	 * @return bool|WP_Post
	 */
	public function get_post($slug = '', $type = 'post')
	{
		if ($slug) {
			$posts = get_posts([
				'name' => $slug,
				'posts_per_page' => 1,
				'post_type' => $type,
			]);

			if ($posts) {
				return current($posts);
			}
		}

		/**
		 * Get a random latest post, excluding already used ones.
		 */

		// Add hello world / first post to excluded posts.
		$exclude = array_merge([1], $this->random_post_ids);

		$posts = get_posts([
			'posts_per_page' => 1,
			'exclude'   => $exclude,
			'post_type' => $type,
		]);

		if (!$posts) {
			return false;
		}

		$post = current($posts);
		$this->random_post_ids[] = $post->ID;

		return $post;
	}

	/**
	 * Get the specified category by slug or a random category if not found.
	 * 
	 * @return bool|WP_Term
	 */
	public function get_category($slug)
	{
		$term = get_term_by('slug', $slug, 'category');
		if (!$term || empty($term->term_id)) {
			$categories = get_terms('category', [
				'orderby' => 'count',
				'order'   => 'desc',
				'exclude' => $this->random_cat_ids,
			]);

			if (!$categories) {
				return false;
			}

			// Return first category with highest posts and add to exclusion list.
			$category = current($categories);
			$this->random_cat_ids[] = $category->term_id;

			return $category;
		}

		return $term;
	}
}
PK/3Y�
r:r:-bunyad-demo-import/inc/OneClickDemoImport.php<?php
/**
 * Main One Click Demo Import plugin class/file.
 * 
 * Modified by ThemeSphere.
 *
 * @package ocdi
 */

namespace OCDI;

/**
 * One Click Demo Import class, so we don't have to worry about namespaces.
 */
class OneClickDemoImport {
	/**
	 * The instance *Singleton* of this class
	 *
	 * @var object
	 */
	private static $instance;

	/**
	 * The instance of the OCDI\Importer class.
	 *
	 * @var object
	 */
	public $importer;

	/**
	 * The resulting page's hook_suffix, or false if the user does not have the capability required.
	 *
	 * @var boolean or string
	 */
	private $plugin_page;

	/**
	 * Holds the verified import files.
	 *
	 * @var array
	 */
	public $import_files;

	/**
	 * The path of the log file.
	 *
	 * @var string
	 */
	public $log_file_path;

	/**
	 * The index of the `import_files` array (which import files was selected).
	 *
	 * @var int
	 */
	private $selected_index;

	/**
	 * The paths of the actual import files to be used in the import.
	 *
	 * @var array
	 */
	private $selected_import_files;

	/**
	 * Holds any error messages, that should be printed out at the end of the import.
	 *
	 * @var string
	 */
	public $frontend_error_messages = array();

	/**
	 * Was the before content import already triggered?
	 *
	 * @var boolean
	 */
	private $before_import_executed = false;

  /**
   * Make plugin page options available to other methods.
   *
   * @var array
   */
  private $plugin_page_setup = array();

  /**
   * Bunyad Import Type. Full or partial.
   *
   * @var string
   */
  public $import_type;
  protected $admin_page;

	/**
	 * Returns the *Singleton* instance of this class.
	 *
	 * @return OneClickDemoImport the *Singleton* instance.
	 */
	public static function get_instance() {
		if ( null === static::$instance ) {
			static::$instance = new static();
		}

		return static::$instance;
	}


	/**
	 * Class construct function, to initiate the plugin.
	 * Protected constructor to prevent creating a new instance of the
	 * *Singleton* via the `new` operator from outside of this class.
	 */
	protected function __construct() {
		// Actions
		add_action( 'after_setup_theme', array( $this, 'setup_plugin_with_filter_data' ) );
		add_action( 'plugins_loaded', array( $this, 'load_textdomain' ) );
		
		// +EDIT: Bunyad
		
		// Import AJAX handler
		add_action('wp_ajax_bunyad_import_demo', array($this, 'import'));
		
		// Register scripts
		add_action('admin_enqueue_scripts', array( $this, 'register_assets'));
		
		// Add Menu page
		add_action('admin_menu', array($this, 'menu_setup'));
	}


	/**
	 * Private clone method to prevent cloning of the instance of the *Singleton* instance.
	 *
	 * @return void
	 */
	private function __clone() {}


	/**
	 * Private unserialize method to prevent unserializing of the *Singleton* instance.
	 *
	 * @return void
	 */
	public function __wakeup() {}

	/**
	 * Enqueue admin scripts (JS and CSS)
	 *
	 * @param string $hook holds info on which admin page you are currently loading.
	 */
	public function register_assets($hook) {

		// Enqueue the scripts only on the plugin page.
		if ($this->admin_page === $hook) {
			wp_enqueue_script('bunyad-import', PT_OCDI_URL . 'assets/js/main.js', array('jquery'), PT_OCDI_VERSION);

			wp_localize_script('bunyad-import', 'Bunyad_Import',
				array(
					'ajax_url'     => admin_url('admin-ajax.php'),
					'ajax_nonce'   => wp_create_nonce('ocdi-ajax-verification'),
				)
			);
			
			wp_enqueue_style('bunyad-import-css', PT_OCDI_URL . 'assets/css/main.css', array(), PT_OCDI_VERSION);
		}
	}

	/**
	 * Add the menu option
	 */
	public function menu_setup()
	{
		$this->admin_page = add_submenu_page(
			'themes.php', esc_html__('Demo Import', 'pt-ocdi'), esc_html__('Import Demos', 'pt-ocdi'), 'import', 'bunyad-demo-import', array($this, 'admin_page')
		);
	}

	/**
	 * Admin page output - can be overridden by the theme using bunyad_import_admin_page hook
	 */
	public function admin_page()
	{
		ob_start();
		do_action('bunyad_import_admin_page');
		$content = ob_get_clean();
		
		if (!empty($content)) {
			echo $content;
			return;
		}

		// Should be in admin_head ideally.
		wp_enqueue_script('jquery-ui-dialog');
		wp_enqueue_style('wp-jquery-ui-dialog');

		require_once PT_OCDI_PATH . 'views/plugin-page.php';
	}

	/**
	 * Main AJAX callback function for:
	 * 1). prepare import files (uploaded or predefined via filters)
	 * 2). execute 'before content import' actions (before import WP action)
	 * 3). import content
	 * 4). execute 'after content import' actions (before widget import WP action, widget import, customizer import, after import WP action)
	 */
	public function import() 
	{
		// This may run multiple times due to AJAX. Use 'bunyad_import_begin' filter for single
		// run only at beginning.
		do_action('bunyad_import_pre_import');

		// Try to update PHP memory limit (so that it does not run out of it).
		@ini_set( 'memory_limit', apply_filters( 'pt-ocdi/import_memory_limit', '350M' ) );

		// DEBUG INFO: To debug and log proper messages in the log file, such as "DOM support is not enabled", make sure to enable showing errors:
		// ini_set('display_errors', 'on');

		// Check for XMLReader availability or a FATAL error maybe caused.
		if (!class_exists('XMLReader')) {
			ob_start();
			?>
			<div class="notice error">
				<p>  
				<?php 
					echo esc_html('Missing XMLReader. Installed PHP is missing an essential feature for any importer to work. Please contact your webhost to enable xmlreader in PHP.', 'pt-ocdi'); ?>
				</p>
			</div>
			<?php

			wp_send_json(array('message' => ob_get_clean()));
			return;
		}

		// Verify if the AJAX call is valid (checks nonce and current_user_can).
		Helpers::verify_ajax_call();

		// Is this a new AJAX call to continue the previous import?
		$use_existing_importer_data = $this->use_existing_importer_data();

		if (!$use_existing_importer_data) {

			// Will only fire on the first AJAX call.
			do_action('bunyad_import_begin', $this->selected_index, $this->importer, $this);

			// Create a date and time string to use for demo and log file names.
			Helpers::set_demo_import_start_time();

			// Define log file path.
			$this->log_file_path = Helpers::get_log_path();

			// Get selected file index or set it to 0.
			$this->selected_index = empty($_POST['demo_id']) ? 0 : $_POST['demo_id'];
			$this->import_type = $_POST['import_type'];

			// Download the import files (content, widgets and customizer files).
			$this->selected_import_files = Helpers::download_import_files( $this->import_files[ $this->selected_index ] );

			// Check Errors.
			if ( is_wp_error( $this->selected_import_files ) ) {
				// Write error to log file and send an AJAX response with the error.
				Helpers::log_error_and_send_ajax_response(
					$this->selected_import_files->get_error_message(),
					$this->log_file_path,
					esc_html__( 'Downloaded files', 'pt-ocdi' )
				);
			}

			// Add this message to log file.
			$log_added = Helpers::append_to_file(
				sprintf(
					__( 'The import files for: %s were successfully downloaded!', 'pt-ocdi' ),
					$this->import_files[ $this->selected_index ]['demo_name']
				) . Helpers::import_file_info( $this->selected_import_files ),
				$this->log_file_path,
				esc_html__( 'Downloaded files' , 'pt-ocdi' )
			);
		}

		// Save the initial import data as a transient, so other import parts (in new AJAX calls) can use that data.
		Helpers::set_ocdi_import_data_transient( $this->get_current_importer_data() );

		if ( ! $this->before_import_executed ) {
			$this->before_import_executed = true;

			/**
			 * 2). Execute the actions hooked to the 'pt-ocdi/before_content_import_execution' action:
			 *
			 * Default actions:
			 * 1 - Before content import WP action (with priority 10).
			 */
			do_action( 'pt-ocdi/before_content_import_execution', $this->selected_import_files, $this->import_files, $this->selected_index );
		}

		/**
		 * Import content
		 */
		if ($this->import_type == 'full') {
			
			// Import content
			$this->append_to_frontend_error_messages( 
				$this->importer->import_content($this->selected_import_files['content'])
			);
		}
		else {
			unset(
				$this->selected_import_files['widgets'],
				$this->selected_import_files['content']
			);
		}

		/**
		 * Import customizer settings. Will call the hooks set in ImportActions.php
		 */
		do_action('pt-ocdi/customizer_import_execution', $this->selected_import_files);

		/**
		 * Execute the actions hooked to the 'pt-ocdi/after_content_import_execution' action:
		 *
		 * Default actions:
		 * 1 - Before widgets import setup (with priority 10).
		 * 2 - Import widgets (with priority 20).
		 * 3 - Import Redux data (with priority 30).
		 */
		do_action('pt-ocdi/after_content_import_execution', $this->selected_import_files, $this->import_files, $this->selected_index);

		// Save the import data as a transient, so other import parts (in new AJAX calls) can use that data.
		Helpers::set_ocdi_import_data_transient( $this->get_current_importer_data() );

		// Display final messages (success or error messages).

		$response['message'] = '<div class="notice notice-success"><p>All done! Please deactivate and delete the "Bunyad Demo Import" plugin now.</p></div>';
		if ($this->import_type === 'full') {
			
			ob_start();
			?>
			
			<div class="notice notice-success">
				<p><?php echo esc_html__('Import is successful! Just two more steps:', 'pt-ocdi'); ?></p>
				<ol>
					<li><a href="<?php echo admin_url('tools.php?page=regenerate-thumbnails'); ?>" target="_blank"><?php echo esc_html__('Run Re-generate Thumbnails.', 'pt-ocdi'); ?></a></li>
					<li>Once all thumbnails are regenerated, "Bunyad Demo Import" and "Regenerate Thumbnails" plugins aren't needed anymore. De-activate and remove them.</li>
				</ol>
			</div>
			
			<?php
			$response['message'] = apply_filters('bunyad_import_success_message', ob_get_clean());
		}

		if (!empty($this->frontend_error_messages)) {
			$response['message'] .= sprintf(
				__( '%1$sIf you wish to inspect the import log, you can find it in this %2$slog file%3$s %4$s', 'pt-ocdi' ),
				'<div class="notice"><p>',
				'<a href="' . Helpers::get_log_url( $this->log_file_path ) .'" target="_blank">',
				'</a>',
				'</p></div>'
			);
		}

		do_action('bunyad_import_done', $this->selected_index, $this->importer, $this);
		
		// Delete importer data transient for current import.
		delete_transient( 'ocdi_importer_data' );

		wp_send_json($response);
	}

	/**
	 * Get content importer data, so we can continue the import with this new AJAX request.
	 *
	 * @return boolean
	 */
	private function use_existing_importer_data() {
		if ( $data = get_transient( 'ocdi_importer_data' ) ) {
			$this->frontend_error_messages = empty( $data['frontend_error_messages'] ) ? array() : $data['frontend_error_messages'];
			$this->log_file_path           = empty( $data['log_file_path'] ) ? '' : $data['log_file_path'];
			$this->selected_index          = empty( $data['selected_index'] ) ? 0 : $data['selected_index'];
			$this->selected_import_files   = empty( $data['selected_import_files'] ) ? array() : $data['selected_import_files'];
			$this->import_files            = empty( $data['import_files'] ) ? array() : $data['import_files'];
			$this->before_import_executed  = empty( $data['before_import_executed'] ) ? false : $data['before_import_executed'];

			$this->import_type             = empty( $data['import_type'] ) ? '' : $data['import_type'];
			
			$this->importer->set_importer_data( $data );

			return true;
		}
		return false;
	}


	/**
	 * Get the current state of selected data.
	 *
	 * @return array
	 */
	public function get_current_importer_data() {
		return array(
			'frontend_error_messages' => $this->frontend_error_messages,
			'log_file_path'           => $this->log_file_path,
			'selected_index'          => $this->selected_index,
			'selected_import_files'   => $this->selected_import_files,
			'import_files'            => $this->import_files,
			'before_import_executed'  => $this->before_import_executed,

			'import_type'             => $this->import_type,
		);
	}


	/**
	 * Getter function to retrieve the private log_file_path value.
	 *
	 * @return string The log_file_path value.
	 */
	public function get_log_file_path() {
		return $this->log_file_path;
	}


	/**
	 * Setter function to append additional value to the private frontend_error_messages value.
	 *
	 * @param string $additional_value The additional value that will be appended to the existing frontend_error_messages.
	 */
	public function append_to_frontend_error_messages( $text ) {
		$lines = array();

		if ( ! empty( $text ) ) {
			$text = str_replace( '<br>', PHP_EOL, $text );
			$lines = explode( PHP_EOL, $text );
		}

		foreach ( $lines as $line ) {
			if ( ! empty( $line ) && ! in_array( $line , $this->frontend_error_messages ) ) {
				$this->frontend_error_messages[] = $line;
			}
		}
	}


	/**
	 * Display the frontend error messages.
	 *
	 * @return string Text with HTML markup.
	 */
	public function frontend_error_messages_display() {
		$output = '';

		if ( ! empty( $this->frontend_error_messages ) ) {
			foreach ( $this->frontend_error_messages as $line ) {
				$output .= esc_html( $line );
				$output .= '<br>';
			}
		}

		return $output;
	}


	/**
	 * Load the plugin textdomain, so that translations can be made.
	 */
	public function load_textdomain() {
		load_plugin_textdomain( 'pt-ocdi', false, plugin_basename( dirname( dirname( __FILE__ ) ) ) . '/languages' );
	}


	/**
	 * Get data from filters, after the theme has loaded and instantiate the importer.
	 */
	public function setup_plugin_with_filter_data() {
		if ( ! ( is_admin() || ( defined( 'WP_CLI' ) && WP_CLI ) ) ) {
			return;
		}

		// +EDIT: Get info of import data files and filter it.
		$demos = apply_filters('pt-ocdi/import_files', array());
		$this->import_files = apply_filters('bunyad_import_demos', $demos);

		/**
		 * Register all default actions (before content import, widget, customizer import and other actions)
		 * to the 'before_content_import_execution' and the 'pt-ocdi/after_content_import_execution' action hook.
		 */
		$import_actions = new ImportActions();
		$import_actions->register_hooks();

		// Importer options array.
		$importer_options = apply_filters( 'pt-ocdi/importer_options', array(
			'fetch_attachments' => true,
		) );

		// Logger options for the logger used in the importer.
		// Note: Doesn't really work right now as logger just prints non-errors and inc/Importer.php 
		// just discards the output. 
		$logger_options = apply_filters( 'pt-ocdi/logger_options', array(
			'logger_min_level' => 'warning',
		) );

		// Configure logger instance and set it to the importer.
		$logger            = new Logger();
		$logger->min_level = $logger_options['logger_min_level'];

		// Create importer instance with proper parameters.
		$this->importer = new Importer( $importer_options, $logger );
	}
}
PK/3Y�$�
	
	(bunyad-demo-import/inc/ReduxImporter.php<?php
/**
 * Class for the Redux importer used in the One Click Demo Import plugin.
 *
 * @see https://wordpress.org/plugins/redux-framework/
 * @package ocdi
 */

namespace OCDI;

class ReduxImporter {
	/**
	 * Import Redux data from a JSON file, generated by the Redux plugin.
	 *
	 * @param array $import_data Array of arrays. Child array contains 'option_name' and 'file_path'.
	 */
	public static function import( $import_data ) {
		$ocdi          = OneClickDemoImport::get_instance();
		$log_file_path = $ocdi->get_log_file_path();

		// Redux plugin is not active!
		if ( ! class_exists( 'ReduxFramework' ) ) {
			$error_message = esc_html__( 'The Redux plugin is not activated, so the Redux import was skipped!', 'pt-ocdi' );

			// Add any error messages to the frontend_error_messages variable in OCDI main class.
			$ocdi->append_to_frontend_error_messages( $error_message );

			// Write error to log file.
			Helpers::append_to_file(
				$error_message,
				$log_file_path,
				esc_html__( 'Importing Redux settings' , 'pt-ocdi' )
			);

			return;
		}

		foreach ( $import_data as $redux_item ) {
			$redux_options_raw_data = Helpers::data_from_file( $redux_item['file_path'] );

			$redux_options_data = json_decode( $redux_options_raw_data, true );

			$redux_framework = \ReduxFrameworkInstances::get_instance( $redux_item['option_name'] );

			if ( isset( $redux_framework->args['opt_name'] ) ) {
				// Import Redux settings.
				$redux_framework->set_options( $redux_options_data );

				// Add this message to log file.
				$log_added = Helpers::append_to_file(
					sprintf( esc_html__( 'Redux settings import for: %s finished successfully!', 'pt-ocdi' ), $redux_item['option_name'] ),
					$log_file_path,
					esc_html__( 'Importing Redux settings' , 'pt-ocdi' )
				);
			}
			else {
				$error_message = sprintf( esc_html__( 'The Redux option name: %s, was not found in this WP site, so it was not imported!', 'pt-ocdi' ), $redux_item['option_name'] );

				// Add any error messages to the frontend_error_messages variable in OCDI main class.
				$ocdi->append_to_frontend_error_messages( $error_message );

				// Write error to log file.
				Helpers::append_to_file(
					$error_message,
					$log_file_path,
					esc_html__( 'Importing Redux settings' , 'pt-ocdi' )
				);
			}
		}
	}
}
PK/3Y��l�2�2)bunyad-demo-import/inc/WidgetImporter.php<?php
/**
 * Class for the widget importer used in the One Click Demo Import plugin.
 *
 * Code is mostly from the Widget Importer & Exporter plugin.
 *
 * @see https://wordpress.org/plugins/widget-importer-exporter/
 * @package ocdi
 */

namespace OCDI;

class WidgetImporter {
	/**
	 * Import widgets from WIE or JSON file.
	 *
	 * @param string $widget_import_file_path path to the widget import file.
	 */
	public static function import( $widget_import_file_path ) {
		$results       = array();
		$ocdi          = OneClickDemoImport::get_instance();
		$log_file_path = $ocdi->get_log_file_path();

		// Import widgets and return result.
		if ( ! empty( $widget_import_file_path ) ) {
			$results = self::import_widgets( $widget_import_file_path );
		}

		// Check for errors, else write the results to the log file.
		if ( is_wp_error( $results ) ) {
			$error_message = $results->get_error_message();

			// Add any error messages to the frontend_error_messages variable in OCDI main class.
			$ocdi->append_to_frontend_error_messages( $error_message );

			// Write error to log file.
			Helpers::append_to_file(
				$error_message,
				$log_file_path,
				esc_html__( 'Importing widgets', 'pt-ocdi' )
			);
		}
		else {
			ob_start();
				self::format_results_for_log( $results );
			$message = ob_get_clean();

			// Add this message to log file.
			$log_added = Helpers::append_to_file(
				$message,
				$log_file_path,
				esc_html__( 'Importing widgets' , 'pt-ocdi' )
			);
		}

	}


	/**
	 * Imports widgets from a json file.
	 *
	 * @param string $data_file path to json file with WordPress widget export data.
	 */
	private static function import_widgets( $data_file ) {
		// Get widgets data from file.
		$data = self::process_import_file( $data_file );

		// Return from this function if there was an error.
		if ( is_wp_error( $data ) ) {
			return $data;
		}

		// Import the widget data and save the results.
		return self::import_data( $data );
	}

	/**
	 * Process import file - this parses the widget data and returns it.
	 *
	 * @param string $file path to json file.
	 * @return object $data decoded JSON string
	 */
	private static function process_import_file( $file ) {
		// File exists?
		if ( ! file_exists( $file ) ) {
			return new \WP_Error(
				'widget_import_file_not_found',
				__( 'Error: Widget import file could not be found.', 'pt-ocdi' )
			);
		}

		// Get file contents and decode.
		$data = Helpers::data_from_file( $file );

		// Return from this function if there was an error.
		if ( is_wp_error( $data ) ) {
			return $data;
		}

		return json_decode( $data );
	}


	/**
	 * Import widget JSON data
	 *
	 * @global array $wp_registered_sidebars
	 * @param object $data JSON widget data.
	 * @return array $results
	 */
	private static function import_data( $data ) {
		global $wp_registered_sidebars;

		// Have valid data? If no data or could not decode.
		if ( empty( $data ) || ! is_object( $data ) ) {
			return new \WP_Error(
				'corrupted_widget_import_data',
				__( 'Error: Widget import data could not be read. Please try a different file.', 'pt-ocdi' )
			);
		}

		// Hook before import.
		do_action( 'pt-ocdi/widget_importer_before_widgets_import' );
		$data = apply_filters( 'pt-ocdi/before_widgets_import_data', $data );

		// Get all available widgets site supports.
		$available_widgets = self::available_widgets();

		// Get all existing widget instances.
		$widget_instances = array();

		foreach ( $available_widgets as $widget_data ) {
			$widget_instances[ $widget_data['id_base'] ] = get_option( 'widget_' . $widget_data['id_base'] );
		}

		// Begin results.
		$results = array();

		// Loop import data's sidebars.
		foreach ( $data as $sidebar_id => $widgets ) {
			// Skip inactive widgets (should not be in export file).
			if ( 'wp_inactive_widgets' == $sidebar_id ) {
				continue;
			}

			// Check if sidebar is available on this site. Otherwise add widgets to inactive, and say so.
			if ( isset( $wp_registered_sidebars[ $sidebar_id ] ) ) {
				$sidebar_available    = true;
				$use_sidebar_id       = $sidebar_id;
				$sidebar_message_type = 'success';
				$sidebar_message      = '';
			}
			else {
				$sidebar_available    = false;
				$use_sidebar_id       = 'wp_inactive_widgets'; // Add to inactive if sidebar does not exist in theme.
				$sidebar_message_type = 'error';
				$sidebar_message      = __( 'Sidebar does not exist in theme (moving widget to Inactive)', 'pt-ocdi' );
			}

			// Result for sidebar.
			$results[ $sidebar_id ]['name']         = ! empty( $wp_registered_sidebars[ $sidebar_id ]['name'] ) ? $wp_registered_sidebars[ $sidebar_id ]['name'] : $sidebar_id; // Sidebar name if theme supports it; otherwise ID.
			$results[ $sidebar_id ]['message_type'] = $sidebar_message_type;
			$results[ $sidebar_id ]['message']      = $sidebar_message;
			$results[ $sidebar_id ]['widgets']      = array();

			// Loop widgets.
			foreach ( $widgets as $widget_instance_id => $widget ) {
				$fail = false;

				// Get id_base (remove -# from end) and instance ID number.
				$id_base            = preg_replace( '/-[0-9]+$/', '', $widget_instance_id );
				$instance_id_number = str_replace( $id_base . '-', '', $widget_instance_id );

				// Does site support this widget?
				if ( ! $fail && ! isset( $available_widgets[ $id_base ] ) ) {
					$fail                = true;
					$widget_message_type = 'error';
					$widget_message      = __( 'Site does not support widget', 'pt-ocdi' ); // Explain why widget not imported.
				}

				// Filter to modify settings object before conversion to array and import.
				// Leave this filter here for backwards compatibility with manipulating objects (before conversion to array below).
				// Ideally the newer wie_widget_settings_array below will be used instead of this.
				$widget = apply_filters( 'pt-ocdi/widget_settings', $widget ); // Object.

				// Convert multidimensional objects to multidimensional arrays.
				// Some plugins like Jetpack Widget Visibility store settings as multidimensional arrays.
				// Without this, they are imported as objects and cause fatal error on Widgets page.
				// If this creates problems for plugins that do actually intend settings in objects then may need to consider other approach: https://wordpress.org/support/topic/problem-with-array-of-arrays.
				// It is probably much more likely that arrays are used than objects, however.
				$widget = json_decode( json_encode( $widget ), true );

				// Filter to modify settings array.
				// This is preferred over the older wie_widget_settings filter above.
				// Do before identical check because changes may make it identical to end result (such as URL replacements).
				$widget = apply_filters( 'pt-ocdi/widget_settings_array', $widget );

				// Does widget with identical settings already exist in same sidebar?
				if ( ! $fail && isset( $widget_instances[ $id_base ] ) ) {
					// Get existing widgets in this sidebar.
					$sidebars_widgets = get_option( 'sidebars_widgets' );
					$sidebar_widgets  = isset( $sidebars_widgets[ $use_sidebar_id ] ) ? $sidebars_widgets[ $use_sidebar_id ] : array(); // Check Inactive if that's where will go.

					// Loop widgets with ID base.
					$single_widget_instances = ! empty( $widget_instances[ $id_base ] ) ? $widget_instances[ $id_base ] : array();
					foreach ( $single_widget_instances as $check_id => $check_widget ) {
						// Is widget in same sidebar and has identical settings?
						if ( in_array( "$id_base-$check_id", $sidebar_widgets ) && (array) $widget == $check_widget ) {
							$fail                = true;
							$widget_message_type = 'warning';
							$widget_message      = __( 'Widget already exists', 'pt-ocdi' ); // Explain why widget not imported.

							break;
						}
					}
				}

				// No failure.
				if ( ! $fail ) {
					// Add widget instance.
					$single_widget_instances   = get_option( 'widget_' . $id_base ); // All instances for that widget ID base, get fresh every time.
					$single_widget_instances   = ! empty( $single_widget_instances ) ? $single_widget_instances : array( '_multiwidget' => 1 ); // Start fresh if have to.
					$single_widget_instances[] = $widget; // Add it.

					// Get the key it was given.
					end( $single_widget_instances );
					$new_instance_id_number = key( $single_widget_instances );

					// If key is 0, make it 1.
					// When 0, an issue can occur where adding a widget causes data from other widget to load, and the widget doesn't stick (reload wipes it).
					if ( '0' === strval( $new_instance_id_number ) ) {
						$new_instance_id_number                           = 1;
						$single_widget_instances[ $new_instance_id_number ] = $single_widget_instances[0];
						unset( $single_widget_instances[0] );
					}

					// Move _multiwidget to end of array for uniformity.
					if ( isset( $single_widget_instances['_multiwidget'] ) ) {
						$multiwidget = $single_widget_instances['_multiwidget'];
						unset( $single_widget_instances['_multiwidget'] );
						$single_widget_instances['_multiwidget'] = $multiwidget;
					}

					// Update option with new widget.
					update_option( 'widget_' . $id_base, $single_widget_instances );

					// Assign widget instance to sidebar.
					$sidebars_widgets = get_option( 'sidebars_widgets' ); // Which sidebars have which widgets, get fresh every time.

					// Avoid rarely fatal error when the option is an empty string
					// https://github.com/churchthemes/widget-importer-exporter/pull/11.
					if ( ! $sidebars_widgets ) {
						$sidebars_widgets = array();
					}

					$new_instance_id = $id_base . '-' . $new_instance_id_number; // Use ID number from new widget instance.
					$sidebars_widgets[ $use_sidebar_id ][] = $new_instance_id; // Add new instance to sidebar.
					update_option( 'sidebars_widgets', $sidebars_widgets ); // Save the amended data.

					// After widget import action.
					$after_widget_import = array(
						'sidebar'           => $use_sidebar_id,
						'sidebar_old'       => $sidebar_id,
						'widget'            => $widget,
						'widget_type'       => $id_base,
						'widget_id'         => $new_instance_id,
						'widget_id_old'     => $widget_instance_id,
						'widget_id_num'     => $new_instance_id_number,
						'widget_id_num_old' => $instance_id_number,
					);
					do_action( 'pt-ocdi/widget_importer_after_single_widget_import', $after_widget_import );

					// Success message.
					if ( $sidebar_available ) {
						$widget_message_type = 'success';
						$widget_message      = __( 'Imported', 'pt-ocdi' );
					}
					else {
						$widget_message_type = 'warning';
						$widget_message      = __( 'Imported to Inactive', 'pt-ocdi' );
					}
				}

				// Result for widget instance.
				$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['name']         = isset( $available_widgets[ $id_base ]['name'] ) ? $available_widgets[ $id_base ]['name'] : $id_base; // Widget name or ID if name not available (not supported by site).
				$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['title']        = ! empty( $widget['title'] ) ? $widget['title'] : __( 'No Title', 'pt-ocdi' ); // Show "No Title" if widget instance is untitled.
				$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['message_type'] = $widget_message_type;
				$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['message']      = $widget_message;

			}
		}

		// Hook after import.
		do_action( 'pt-ocdi/widget_importer_after_widgets_import' );

		// Return results.
		return apply_filters( 'pt-ocdi/widget_import_results', $results );
	}


	/**
	 * Available widgets.
	 *
	 * Gather site's widgets into array with ID base, name, etc.
	 *
	 * @global array $wp_registered_widget_controls
	 * @return array $available_widgets, Widget information
	 */
	private static function available_widgets() {
		global $wp_registered_widget_controls;

		$widget_controls   = $wp_registered_widget_controls;
		$available_widgets = array();

		foreach ( $widget_controls as $widget ) {
			if ( ! empty( $widget['id_base'] ) && ! isset( $available_widgets[ $widget['id_base'] ] ) ) {
				$available_widgets[ $widget['id_base'] ]['id_base'] = $widget['id_base'];
				$available_widgets[ $widget['id_base'] ]['name']    = $widget['name'];
			}
		}

		return apply_filters( 'pt-ocdi/available_widgets', $available_widgets );
	}


	/**
	 * Format results for log file
	 *
	 * @param array $results widget import results.
	 */
	private static function format_results_for_log( $results ) {
		if ( empty( $results ) ) {
			esc_html_e( 'No results for widget import!', 'pt-ocdi' );
		}

		// Loop sidebars.
		foreach ( $results as $sidebar ) {
			echo esc_html( $sidebar['name'] ) . ' : ' . esc_html( $sidebar['message'] ) . PHP_EOL . PHP_EOL;
			// Loop widgets.
			foreach ( $sidebar['widgets'] as $widget ) {
				echo esc_html( $widget['name'] ) . ' - ' . esc_html( $widget['title'] ) . ' - ' . esc_html( $widget['message'] ) . PHP_EOL;
			}
			echo PHP_EOL;
		}
	}
}
PK/3Y[@�*%*%(bunyad-demo-import/inc/WPCLICommands.php<?php
/**
 * The class for WP-CLI commands for One Click Demo Import plugin.
 *
 * @package ocdi
 */

namespace OCDI;

use WP_CLI;

class WPCLICommands extends \WP_CLI_Command {

	/**
	 * @var object Main OCDI class object.
	 */
	private $ocdi;

	public function __construct() {
		parent::__construct();

		$this->ocdi = OneClickDemoImport::get_instance();

		Helpers::set_demo_import_start_time();

		$this->ocdi->log_file_path = Helpers::get_log_path();
	}

	/**
	 * List all predefined demo imports.
	 */
	public function list_predefined() {
		if ( empty( $this->ocdi->import_files ) ) {
			WP_CLI::error( esc_html__( 'There are no predefined demo imports for currently active theme!', 'pt-ocdi' ) );
		}

		WP_CLI::success( esc_html__( 'Here are the predefined demo imports:', 'pt-ocdi' ) );

		foreach ( $this->ocdi->import_files as $index => $import_file ) {
			WP_CLI::log( sprintf(
				'%d -> %s [content: %s, widgets: %s, customizer: %s, redux: %s]',
				$index,
				$import_file['import_file_name'],
				empty( $import_file['import_file_url'] ) && empty( $import_file['local_import_file'] ) ? 'no' : 'yes',
				empty( $import_file['import_widget_file_url'] ) && empty( $import_file['local_import_widget_file'] ) ? 'no' : 'yes',
				empty( $import_file['import_customizer_file_url'] ) && empty( $import_file['local_import_customizer_file'] ) ? 'no' : 'yes',
				empty( $import_file['import_redux'] ) && empty( $import_file['local_import_redux'] ) ? 'no' : 'yes'
			) );
		}
	}

	/**
	 * Import content/widgets/customizer settings with the OCDI plugin.
	 *
	 * ## OPTIONS
	 *
	 * [--content=<file>]
	 * : Content file (XML), that will be used to import the content.
	 *
	 * [--widgets=<file>]
	 * : Widgets file (JSON or WIE), that will be used to import the widgets.
	 *
	 * [--customizer=<file>]
	 * : Customizer file (DAT), that will be used to import the customizer settings.
	 *
	 * [--predefined=<index>]
	 * : The index of the predefined demo imports (use the 'list_predefined' command to check the predefined demo imports)
	 */
	public function import( $args, $assoc_args ) {
		if ( ! $this->any_import_options_set( $assoc_args ) ) {
			WP_CLI::error( esc_html__( 'At least one of the possible options should be set! Check them with --help', 'pt-ocdi' ) );
		}

		if ( isset( $assoc_args['predefined'] ) ) {
			$this->import_predefined( $assoc_args['predefined'] );
		}

		if ( ! empty( $assoc_args['content'] ) ) {
			$this->import_content( $assoc_args['content'] );
		}

		if ( ! empty( $assoc_args['widgets'] ) ) {
			$this->import_widgets( $assoc_args['widgets'] );
		}

		if ( ! empty( $assoc_args['customizer'] ) ) {
			$this->import_customizer( $assoc_args['customizer'] );
		}
	}

	/**
	 * Check if any of the possible options are set.
	 *
	 * @param array $options
	 *
	 * @return bool
	 */
	private function any_import_options_set( $options ) {
		$possible_options = array(
			'content',
			'widgets',
			'customizer',
			'predefined',
		);

		foreach ( $possible_options as $option ) {
			if ( array_key_exists( $option, $options ) ) {
				return true;
			}
		}

		return false;
	}

	/**
	 * Import the predefined demo content/widgets/customizer settings with OCDI.
	 *
	 * @param int $predefined_index Index of a OCDI predefined demo import.
	 */
	private function import_predefined( $predefined_index ) {
		if ( ! is_numeric( $predefined_index ) ) {
			WP_CLI::error( esc_html__( 'The "predefined" parameter should be a number (an index of the OCDI predefined demo import)!', 'pt-ocdi' ) );
		}

		$predefined_index = absint( $predefined_index );

		if ( ! array_key_exists( $predefined_index, $this->ocdi->import_files ) ) {
			WP_CLI::warning( esc_html__( 'The supplied predefined index does not exist! Please take a look at the available predefined demo imports:', 'pt-ocdi' ) );

			$this->list_predefined();

			return false;
		}

		WP_CLI::log( esc_html__( 'Predefined demo import started! All other parameters will be ignored!', 'pt-ocdi' ) );

		$selected_files = $this->ocdi->import_files[ $predefined_index ];

		if ( ! empty( $selected_files['import_file_name'] ) ) {
			WP_CLI::log( sprintf( esc_html__( 'Selected predefined demo import: %s', 'pt-ocdi' ), $selected_files['import_file_name'] ) );
		}

		WP_CLI::log( esc_html__( 'Preparing the demo import files...', 'pt-ocdi' ) );

		$import_files =	Helpers::download_import_files( $selected_files );

		if ( empty( $import_files ) ) {
			WP_CLI::error( esc_html__( 'Demo import files could not be retrieved!', 'pt-ocdi' ) );
		}

		WP_CLI::log( esc_html__( 'Demo import files retrieved successfully!', 'pt-ocdi' ) );

		WP_CLI::log( esc_html__( 'Importing...', 'pt-ocdi' ) );

		if ( ! empty( $import_files['content'] ) ) {
			$this->do_action( 'pt-ocdi/before_content_import_execution', $import_files, $this->ocdi->import_files, $predefined_index );

			$this->import_content( $import_files['content'] );
		}

		if ( ! empty( $import_files['widgets'] ) ) {
			$this->do_action( 'pt-ocdi/before_widgets_import', $import_files );

			$this->import_widgets( $import_files['widgets'] );
		}

		if ( ! empty( $import_files['customizer'] ) ) {
			$this->import_customizer( $import_files['customizer'] );
		}

		$this->do_action( 'pt-ocdi/after_all_import_execution', $import_files, $this->ocdi->import_files, $predefined_index );

		WP_CLI::log( esc_html__( 'Predefined import finished!', 'pt-ocdi' ) );
	}

	/**
	 * Import the content with OCDI.
	 *
	 * @param string $relative_file_path Relative file path to the content import file.
	 */
	private function import_content( $relative_file_path ) {
		$content_import_file_path = realpath( $relative_file_path );

		if ( ! file_exists( $content_import_file_path ) ) {
			WP_CLI::warning( esc_html__( 'Content import file provided does not exist! Skipping this import!', 'pt-ocdi' ) );
			return false;
		}

		// Change the single AJAX call duration so the whole content import will be done in one go.
		add_filter( 'pt-ocdi/time_for_one_ajax_call', function() {
			return 3600;
		} );

		WP_CLI::log( esc_html__( 'Importing content (this might take a while)...', 'pt-ocdi' ) );

		Helpers::append_to_file( '', $this->ocdi->log_file_path, esc_html__( 'Importing content' , 'pt-ocdi' ) );

		$this->ocdi->append_to_frontend_error_messages( $this->ocdi->importer->import_content( $content_import_file_path ) );

		if( empty( $this->ocdi->frontend_error_messages ) ) {
			WP_CLI::success( esc_html__( 'Content import finished!', 'pt-ocdi' ) );
		}
		else {
			WP_CLI::warning( esc_html__( 'There were some issues while importing the content!', 'pt-ocdi' ) );

			foreach ( $this->ocdi->frontend_error_messages as $line ) {
				WP_CLI::log( $line );
			}

			$this->ocdi->frontend_error_messages = array();
		}
	}

	/**
	 * Import the widgets with OCDI.
	 *
	 * @param string $relative_file_path Relative file path to the widgets import file.
	 */
	private function import_widgets( $relative_file_path ) {
		$widgets_import_file_path = realpath( $relative_file_path );

		if ( ! file_exists( $widgets_import_file_path ) ) {
			WP_CLI::warning( esc_html__( 'Widgets import file provided does not exist! Skipping this import!', 'pt-ocdi' ) );
			return false;
		}

		WP_CLI::log( esc_html__( 'Importing widgets...', 'pt-ocdi' ) );

		WidgetImporter::import( $widgets_import_file_path );

		if( empty( $this->ocdi->frontend_error_messages ) ) {
			WP_CLI::success( esc_html__( 'Widgets imported successfully!', 'pt-ocdi' ) );
		}
		else {
			WP_CLI::warning( esc_html__( 'There were some issues while importing widgets!', 'pt-ocdi' ) );

			foreach ( $this->ocdi->frontend_error_messages as $line ) {
				WP_CLI::log( $line );
			}

			$this->ocdi->frontend_error_messages = array();
		}
	}

	/**
	 * Import the customizer settings with OCDI.
	 *
	 * @param string $relative_file_path Relative file path to the customizer import file.
	 */
	private function import_customizer( $relative_file_path ) {
		$customizer_import_file_path = realpath( $relative_file_path );

		if ( ! file_exists( $customizer_import_file_path ) ) {
			WP_CLI::warning( esc_html__( 'Customizer import file provided does not exist! Skipping this import!', 'pt-ocdi' ) );
			return false;
		}

		WP_CLI::log( esc_html__( 'Importing customizer settings...', 'pt-ocdi' ) );

		CustomizerImporter::import( $customizer_import_file_path );

		if( empty( $this->ocdi->frontend_error_messages ) ) {
			WP_CLI::success( esc_html__( 'Customizer settings imported successfully!', 'pt-ocdi' ) );
		}
		else {
			WP_CLI::warning( esc_html__( 'There were some issues while importing customizer settings!', 'pt-ocdi' ) );

			foreach ( $this->ocdi->frontend_error_messages as $line ) {
				WP_CLI::log( $line );
			}

			$this->ocdi->frontend_error_messages = array();
		}
	}

	/**
	 * Run the registered actions.
	 *
	 * @param string $action            Name of the action.
	 * @param array  $selected_files    Selected import files.
	 * @param array  $all_import_files  All predefined demos.
	 * @param null   $selected_index    Selected predefined index.
	 */
	private function do_action( $action, $import_files = array(), $all_import_files = array(), $selected_index = null ) {
		if ( false !== has_action( $action ) ) {
			WP_CLI::log( sprintf( esc_html__( 'Executing action: %s ...', 'pt-ocdi' ), $action ) );

			ob_start();
				do_action( $action, $import_files, $all_import_files, $selected_index );
			$message = ob_get_clean();

			Helpers::append_to_file( $message, $this->ocdi->log_file_path, $action );
		}
	}
}
PK/3Y���2��&bunyad-demo-import/inc/WXRImporter.php<?php
/**
 * WXR importer class used in the One Click Demo Import plugin.
 * Needed to extend the WXR_Importer class to get/set the importer protected variables,
 * for use in the multiple AJAX calls.
 *
 * @package ocdi
 */

namespace OCDI;

class WXRImporter extends \AwesomeMotive\WPContentImporter2\WXRImporter {

	protected $can_download_local = null;

	/**
	 * Add a check if the attachment file is already available locally.
	 * 
	 * +EDIT: Bunyad
	 */
	protected function process_attachment( $post, $meta, $remote_url ) {

		if ($this->can_download_local === null) {
			// +EDIT: Bunyad add a test if local URLs work.
			$test = wp_remote_head(PT_OCDI_URL . 'assets/js/main.js');
			if (!is_wp_error($test) && wp_remote_retrieve_response_code($test) === 200) {
				$this->can_download_local = true;
			} else {
				$this->can_download_local = false;
			}
		}
		
		// We already have downloaded this file. Use the local URL.
		if ($this->can_download_local && isset($this->url_remap[ $remote_url ])) {
			$remote_url = $this->url_remap[ $remote_url ];
		}

		return parent::process_attachment($post, $meta, $remote_url);
	}

	/**
	 * Constructor method.
	 *
	 * @param array $options Importer options.
	 */
	public function __construct( $options = array() ) {
		parent::__construct( $options );

		// Set current user to $mapping variable.
		// Fixes the [WARNING] Could not find the author for ... log warning messages.
		$current_user_obj = wp_get_current_user();
		$this->mapping['user_slug'][ $current_user_obj->user_login ] = $current_user_obj->ID;

		// WooCommerce product attributes registration.
		if ( class_exists( 'WooCommerce' ) ) {
			add_filter( 'wxr_importer.pre_process.term', array( $this, 'woocommerce_product_attributes_registration' ), 10, 1 );
		}
	}

	/**
	 * Get all protected variables from the WXR_Importer needed for continuing the import.
	 */
	public function get_importer_data() {
		return array(
			'mapping'            => $this->mapping,
			'requires_remapping' => $this->requires_remapping,
			'exists'             => $this->exists,
			'user_slug_override' => $this->user_slug_override,
			'url_remap'          => $this->url_remap,
			'featured_images'    => $this->featured_images,
		);
	}

	/**
	 * Sets all protected variables from the WXR_Importer needed for continuing the import.
	 *
	 * @param array $data with set variables.
	 */
	public function set_importer_data( $data ) {
		$this->mapping            = empty( $data['mapping'] ) ? array() : $data['mapping'];
		$this->requires_remapping = empty( $data['requires_remapping'] ) ? array() : $data['requires_remapping'];
		$this->exists             = empty( $data['exists'] ) ? array() : $data['exists'];
		$this->user_slug_override = empty( $data['user_slug_override'] ) ? array() : $data['user_slug_override'];
		$this->url_remap          = empty( $data['url_remap'] ) ? array() : $data['url_remap'];
		$this->featured_images    = empty( $data['featured_images'] ) ? array() : $data['featured_images'];
	}

	/**
	 * Hook into the pre-process term filter of the content import and register the
	 * custom WooCommerce product attributes, so that the terms can then be imported normally.
	 *
	 * This should probably be removed once the WP importer 2.0 support is added in WooCommerce.
	 *
	 * Fixes: [WARNING] Failed to import pa_size L warnings in content import.
	 * Code from: woocommerce/includes/admin/class-wc-admin-importers.php (ver 2.6.9).
	 *
	 * Github issue: https://github.com/proteusthemes/one-click-demo-import/issues/71
	 *
	 * @param  array $date The term data to import.
	 * @return array       The unchanged term data.
	 */
	public function woocommerce_product_attributes_registration( $data ) {
		global $wpdb;

		if ( strstr( $data['taxonomy'], 'pa_' ) ) {
			if ( ! taxonomy_exists( $data['taxonomy'] ) ) {
				$attribute_name = wc_sanitize_taxonomy_name( str_replace( 'pa_', '', $data['taxonomy'] ) );

				// Create the taxonomy
				if ( ! in_array( $attribute_name, wc_get_attribute_taxonomies() ) ) {
					$attribute = array(
						'attribute_label'   => $attribute_name,
						'attribute_name'    => $attribute_name,
						'attribute_type'    => 'select',
						'attribute_orderby' => 'menu_order',
						'attribute_public'  => 0
					);
					$wpdb->insert( $wpdb->prefix . 'woocommerce_attribute_taxonomies', $attribute );
					delete_transient( 'wc_attribute_taxonomies' );
				}

				// Register the taxonomy now so that the import works!
				register_taxonomy(
					$data['taxonomy'],
					apply_filters( 'woocommerce_taxonomy_objects_' . $data['taxonomy'], array( 'product' ) ),
					apply_filters( 'woocommerce_taxonomy_args_' . $data['taxonomy'], array(
						'hierarchical' => true,
						'show_ui'      => false,
						'query_var'    => true,
						'rewrite'      => false,
					) )
				);
			}
		}

		return $data;
	}
}
PK/3Y9��(2(2(bunyad-demo-import/languages/pt-ocdi.pot# Copyright (C) 2020 Awesome Motive 
# This file is distributed under the GPL 2.0.
msgid ""
msgstr ""
"Project-Id-Version: One Click Demo Import 2.6.1\n"
"Report-Msgid-Bugs-To: "
"https://wordpress.org/support/plugin/one-click-demo-import/\n"
"POT-Creation-Date: 2016-05-14 09:53:17+00:00\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"PO-Revision-Date: 2020-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
"X-Generator: grunt-wp-i18n 0.5.4\n"
"X-Poedit-KeywordsList: "
"__;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;_nx_noop:1,2,3c;esc_"
"attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;esc_html_x:1,2c;\n"
"Language: en\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Poedit-Country: United States\n"
"X-Poedit-SourceCharset: UTF-8\n"
"X-Poedit-Basepath: ../\n"
"X-Poedit-SearchPath-0: .\n"
"X-Poedit-Bookmarks: \n"
"X-Textdomain-Support: yes\n"

#: inc/CustomizerImporter.php:37 inc/CustomizerImporter.php:45
msgid "Importing customizer settings"
msgstr ""

#: inc/CustomizerImporter.php:43
msgid "Customizer settings import finished!"
msgstr ""

#: inc/CustomizerImporter.php:73
msgid "Error: The customizer import file is missing! File path: %s"
msgstr ""

#: inc/CustomizerImporter.php:93
msgid ""
"Error: The customizer import file is not in a correct format. Please make "
"sure to use the correct customizer import file."
msgstr ""

#: inc/CustomizerImporter.php:99
msgid ""
"Error: The customizer import file is not suitable for current theme. You "
"can only import customizer settings for the same theme or a child theme."
msgstr ""

#: inc/Downloader.php:58
msgid "Missing URL for downloading a file!"
msgstr ""

#: inc/Downloader.php:76
msgid ""
"An error occurred while fetching file from: %1$s%2$s%3$s!%4$sReason: %5$s - "
"%6$s."
msgstr ""

#: inc/Helpers.php:199 inc/Helpers.php:242
msgid ""
"An error occurred while writing file to your server! Tried to write a file "
"to: %s%s."
msgstr ""

#: inc/Helpers.php:276
msgid ""
"An error occurred while reading a file from your server! Tried reading file "
"from path: %s%s."
msgstr ""

#: inc/Helpers.php:299
msgid ""
"This WordPress page does not have %sdirect%s write file access. This plugin "
"needs it in order to save the demo import xml file to the upload directory "
"of your site. You can change this setting with these instructions: %s."
msgstr ""

#. Plugin Name of the plugin/theme
msgid "One Click Demo Import"
msgstr ""

#: inc/Helpers.php:311 inc/OneClickDemoImport.php:138 views/plugin-page.php:124
#: views/plugin-page.php:136
msgid "Import Demo Data"
msgstr ""

#: inc/Helpers.php:323
msgid ""
"An error occurred while retrieving reading/writing permissions to your "
"server (could not retrieve WP filesystem credentials)!"
msgstr ""

#: inc/Helpers.php:331
msgid "Your WordPress login credentials don't allow to use WP_Filesystem!"
msgstr ""

#: inc/Helpers.php:371
msgid "One Click Demo Import - "
msgstr ""

#: inc/Helpers.php:405
msgid ""
"%sYour user role isn't high enough. You don't have permission to import "
"demo data.%s"
msgstr ""

#: inc/Helpers.php:438
msgid "No file provided."
msgstr ""

#: inc/Helpers.php:467
msgid "Content file was not uploaded. Error: %s"
msgstr ""

#: inc/Helpers.php:471 inc/Helpers.php:488 inc/Helpers.php:505
#: inc/Helpers.php:516 inc/Helpers.php:536 inc/Helpers.php:544
msgid "Upload files"
msgstr ""

#: inc/Helpers.php:484
msgid "Widget file was not uploaded. Error: %s"
msgstr ""

#: inc/Helpers.php:501
msgid "Customizer file was not uploaded. Error: %s"
msgstr ""

#: inc/Helpers.php:514
msgid "Missing Redux option name! Please also enter the Redux option name!"
msgstr ""

#: inc/Helpers.php:532
msgid "Redux file was not uploaded. Error: %s"
msgstr ""

#: inc/Helpers.php:542
msgid "The import files were successfully uploaded!"
msgstr ""

#: inc/Helpers.php:568
msgid "Initial max execution time = %s"
msgstr ""

#: inc/Helpers.php:572
msgid ""
"Files info:%1$sSite URL = %2$s%1$sData file = %3$s%1$sWidget file = "
"%4$s%1$sCustomizer file = %5$s%1$sRedux files:%1$s%6$s"
msgstr ""

#: inc/Helpers.php:575 inc/Helpers.php:576 inc/Helpers.php:577
#: inc/Helpers.php:578
msgid "not defined!"
msgstr ""

#: inc/Importer.php:174
msgid "New AJAX call!"
msgstr ""

#: inc/OneClickDemoImport.php:189
msgid "No preview image defined for this import."
msgstr ""

#: inc/OneClickDemoImport.php:190
msgid "Are you sure?"
msgstr ""

#: inc/OneClickDemoImport.php:191
msgid "Cancel"
msgstr ""

#: inc/OneClickDemoImport.php:192
msgid "Yes, import!"
msgstr ""

#: inc/OneClickDemoImport.php:193
msgid "Selected demo import:"
msgstr ""

#: inc/OneClickDemoImport.php:240
msgid "Manually uploaded files"
msgstr ""

#: inc/OneClickDemoImport.php:253 inc/OneClickDemoImport.php:264
msgid "Downloaded files"
msgstr ""

#: inc/OneClickDemoImport.php:260
msgid "The import files for: %s were successfully downloaded!"
msgstr ""

#: inc/OneClickDemoImport.php:269
msgid "No import files specified!"
msgstr ""

#: inc/OneClickDemoImport.php:390
msgid ""
"Just used One Click Demo Import plugin and it was awesome! Thanks "
"@ProteusThemes! #OCDI https://www.proteusthemes.com/"
msgstr ""

#: inc/OneClickDemoImport.php:393
msgid ""
"%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"
msgstr ""

#: inc/OneClickDemoImport.php:406
msgid ""
"%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$sOne Click Demo Import%4$s plugin, because "
"it has done its job.%5$s"
msgstr ""

#: inc/OneClickDemoImport.php:417
msgid ""
"%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"
msgstr ""

#: inc/ReduxImporter.php:23
msgid "The Redux plugin is not activated, so the Redux import was skipped!"
msgstr ""

#: inc/ReduxImporter.php:32 inc/ReduxImporter.php:53 inc/ReduxImporter.php:66
msgid "Importing Redux settings"
msgstr ""

#: inc/ReduxImporter.php:51
msgid "Redux settings import for: %s finished successfully!"
msgstr ""

#: inc/ReduxImporter.php:57
msgid ""
"The Redux option name: %s, was not found in this WP site, so it was not "
"imported!"
msgstr ""

#: inc/WPCLICommands.php:34
msgid "There are no predefined demo imports for currently active theme!"
msgstr ""

#: inc/WPCLICommands.php:37
msgid "Here are the predefined demo imports:"
msgstr ""

#: inc/WPCLICommands.php:71
msgid "At least one of the possible options should be set! Check them with --help"
msgstr ""

#: inc/WPCLICommands.php:122
msgid ""
"The \"predefined\" parameter should be a number (an index of the OCDI "
"predefined demo import)!"
msgstr ""

#: inc/WPCLICommands.php:128
msgid ""
"The supplied predefined index does not exist! Please take a look at the "
"available predefined demo imports:"
msgstr ""

#: inc/WPCLICommands.php:135
msgid "Predefined demo import started! All other parameters will be ignored!"
msgstr ""

#: inc/WPCLICommands.php:140
msgid "Selected predefined demo import: %s"
msgstr ""

#: inc/WPCLICommands.php:143
msgid "Preparing the demo import files..."
msgstr ""

#: inc/WPCLICommands.php:148
msgid "Demo import files could not be retrieved!"
msgstr ""

#: inc/WPCLICommands.php:151
msgid "Demo import files retrieved successfully!"
msgstr ""

#: inc/WPCLICommands.php:153
msgid "Importing..."
msgstr ""

#: inc/WPCLICommands.php:173
msgid "Predefined import finished!"
msgstr ""

#: inc/WPCLICommands.php:185
msgid "Content import file provided does not exist! Skipping this import!"
msgstr ""

#: inc/WPCLICommands.php:194
msgid "Importing content (this might take a while)..."
msgstr ""

#: inc/WPCLICommands.php:196
msgid "Importing content"
msgstr ""

#: inc/WPCLICommands.php:201
msgid "Content import finished!"
msgstr ""

#: inc/WPCLICommands.php:204
msgid "There were some issues while importing the content!"
msgstr ""

#: inc/WPCLICommands.php:223
msgid "Widgets import file provided does not exist! Skipping this import!"
msgstr ""

#: inc/WPCLICommands.php:227
msgid "Importing widgets..."
msgstr ""

#: inc/WPCLICommands.php:232
msgid "Widgets imported successfully!"
msgstr ""

#: inc/WPCLICommands.php:235
msgid "There were some issues while importing widgets!"
msgstr ""

#: inc/WPCLICommands.php:254
msgid "Customizer import file provided does not exist! Skipping this import!"
msgstr ""

#: inc/WPCLICommands.php:258
msgid "Importing customizer settings..."
msgstr ""

#: inc/WPCLICommands.php:263
msgid "Customizer settings imported successfully!"
msgstr ""

#: inc/WPCLICommands.php:266
msgid "There were some issues while importing customizer settings!"
msgstr ""

#: inc/WPCLICommands.php:286
msgid "Executing action: %s ..."
msgstr ""

#: inc/WidgetImporter.php:40 inc/WidgetImporter.php:52
msgid "Importing widgets"
msgstr ""

#: inc/WidgetImporter.php:88
msgid "Error: Widget import file could not be found."
msgstr ""

#: inc/WidgetImporter.php:118
msgid "Error: Widget import data could not be read. Please try a different file."
msgstr ""

#: inc/WidgetImporter.php:157
msgid "Sidebar does not exist in theme (moving widget to Inactive)"
msgstr ""

#: inc/WidgetImporter.php:178
msgid "Site does not support widget"
msgstr ""

#: inc/WidgetImporter.php:211
msgid "Widget already exists"
msgstr ""

#: inc/WidgetImporter.php:276
msgid "Imported"
msgstr ""

#: inc/WidgetImporter.php:280
msgid "Imported to Inactive"
msgstr ""

#: inc/WidgetImporter.php:286
msgid "No Title"
msgstr ""

#: inc/WidgetImporter.php:333
msgid "No results for widget import!"
msgstr ""

#: one-click-demo-import.php:57
msgid ""
"The %2$sOne Click Demo Import%3$s plugin requires %2$sPHP 5.3.2+%3$s to run "
"properly. Please contact your hosting company and ask them to update the "
"PHP version of your site to at least PHP 5.3.2.%4$s Your current version of "
"PHP: %2$s%1$s%3$s"
msgstr ""

#: views/plugin-page.php:35
msgid ""
"%sWarning: your server is using %sPHP safe mode%s. This means that you "
"might experience server timeout errors.%s"
msgstr ""

#: views/plugin-page.php:48
msgid "Before you begin, make sure all the required plugins are activated."
msgstr ""

#: views/plugin-page.php:53
msgid ""
"Importing demo data (post, pages, images, theme settings, ...) is the "
"easiest way to setup your theme."
msgstr ""

#: views/plugin-page.php:54
msgid ""
"It will allow you to quickly edit everything instead of creating content "
"from scratch."
msgstr ""

#: views/plugin-page.php:59
msgid "When you import the data, the following things might happen:"
msgstr ""

#: views/plugin-page.php:62
msgid ""
"No existing posts, pages, categories, images, custom post types or any "
"other data will be deleted or modified."
msgstr ""

#: views/plugin-page.php:63
msgid ""
"Posts, pages, images, widgets, menus and other theme settings will get "
"imported."
msgstr ""

#: views/plugin-page.php:64
msgid ""
"Please click on the Import button only once and wait, it can take a couple "
"of minutes."
msgstr ""

#: views/plugin-page.php:69
msgid "Switch to manual import!"
msgstr ""

#: views/plugin-page.php:71
msgid "Switch back to theme predefined imports!"
msgstr ""

#: views/plugin-page.php:87
msgid ""
"There are no predefined import files available in this theme. Please upload "
"the import files manually!"
msgstr ""

#: views/plugin-page.php:94
msgid "Manual demo files upload"
msgstr ""

#: views/plugin-page.php:97
msgid "Choose a XML file for content import:"
msgstr ""

#: views/plugin-page.php:102
msgid "Choose a WIE or JSON file for widget import:"
msgstr ""

#: views/plugin-page.php:107
msgid "Choose a DAT file for customizer import:"
msgstr ""

#: views/plugin-page.php:113
msgid "Choose a JSON file for Redux import:"
msgstr ""

#: views/plugin-page.php:116
msgid "Enter the Redux option name:"
msgstr ""

#: views/plugin-page.php:151
msgid "All"
msgstr ""

#: views/plugin-page.php:158
msgid "Search demos..."
msgstr ""

#: views/plugin-page.php:179
msgid "No preview image."
msgstr ""

#: views/plugin-page.php:184
msgid "Import"
msgstr ""

#: views/plugin-page.php:186
msgid "Preview"
msgstr ""

#: views/plugin-page.php:199
msgid "Importing, please wait!"
msgstr ""

#. Plugin URI of the plugin/theme
msgid "https://wordpress.org/plugins/one-click-demo-import/"
msgstr ""

#. Description of the plugin/theme
msgid ""
"Import your content, widgets and theme settings with one click. Theme "
"authors! Enable simple demo import for your theme demo data."
msgstr ""

#. Author of the plugin/theme
msgid "ProteusThemes"
msgstr ""

#. Author URI of the plugin/theme
msgid "http://www.proteusthemes.com"
msgstr ""PK/3Y�wb_��&bunyad-demo-import/vendor/autoload.php<?php

// autoload.php @generated by Composer

require_once __DIR__ . '/composer/autoload_real.php';

return ComposerAutoloaderInitef3a658a88d521398d72929dc54fa111::getLoader();
PK/3Y4��+��Lbunyad-demo-import/vendor/awesomemotive/wp-content-importer-v2/composer.json{
  "name": "awesomemotive/wp-content-importer-v2",
  "description": "Improved WP content importer used in OCDI plugin.",
  "keywords": ["wp", "wordpress", "awesomemotive", "theme", "import", "content"],
  "license": "GPL-2.0+",
  "authors": [
    {
      "name":  "Gregor Capuder",
      "email": "[email protected]"
    },
    {
      "name":  "Primoz Cigler",
      "email": "[email protected]"
    },
    {
      "name"     : "Humanmade contributors",
      "homepage" : "https://github.com/humanmade/WordPress-Importer/graphs/contributors"
    }
  ],
  "autoload": {
    "psr-4": {
      "AwesomeMotive\\WPContentImporter2\\": "src/"
    }
  }
}
PK/3Yp�����Hbunyad-demo-import/vendor/awesomemotive/wp-content-importer-v2/README.md# WP content importer used in OCDI

List of files from the [original repo](https://github.com/humanmade/WordPress-Importer/):

- class-logger-cli.php,
- class-logger.php,
- class-wxr-importer.php


One click demo import plugin page: https://wordpress.org/plugins/one-click-demo-import/

One click demo import github page: https://github.com/awesomemotive/one-click-demo-import

## Changelog

*July 21st 2020*
- Fixed incorrect post meta import.
- Fixed Elementor import after `wp_slash` updates in this repo.

*July 14th 2020*
- Fixed incorrect post and post meta import (unicode and other special characters were not escaped properly).

*February 7th 2018*
- Clean up the WXRImporter code
- Created a "wrapper" class `Importer.php` with additional functionality (importing by smaller parts -> users, categories, tags, terms and posts)
- tagging version 2.0

*October 29th 2016*

- Cleaned up this forked repo, to only include the thing we need in the OCDI plugin.
- Changed the class names and use psr-4 autoloading in composer.json

*October 26th 2016*

- made a fork from the original repo
- merged a pull request for "term meta data" from the original repo: https://github.com/humanmade/WordPress-Importer/pull/18
PK/3Y
��L3@3@Obunyad-demo-import/vendor/awesomemotive/wp-content-importer-v2/src/Importer.php<?php
/**
 * The main importer class, extending the slightly modified WP importer 2.0 class WXRImporter
 */

namespace AwesomeMotive\WPContentImporter2;

use XMLReader;

class Importer extends WXRImporter {

	/**
	 * Time in milliseconds, marking the beginning of the import.
	 *
	 * @var float
	 */
	private $start_time;

	/**
	 * Importer constructor.
	 * Look at the parent constructor for the options parameters.
	 *
	 * @param array  $options The importer options.
	 * @param object $logger  The logger object.
	 */
	public function __construct( $options = array(), $logger = null ) {
		parent::__construct( $options );

		$this->set_logger( $logger );

		// Check, if a new AJAX request is required.
		add_filter( 'wxr_importer.pre_process.post', array( $this, 'new_ajax_request_maybe' ) );

		// WooCommerce product attributes registration.
		if ( class_exists( 'WooCommerce' ) ) {
			add_filter( 'wxr_importer.pre_process.term', array( $this, 'woocommerce_product_attributes_registration' ), 10, 1 );
		}
	}

	/**
	 * Get the XML reader for the file.
	 *
	 * @param string $file Path to the XML file.
	 *
	 * @return XMLReader|boolean Reader instance on success, false otherwise.
	 */
	protected function get_reader( $file ) {
		// Avoid loading external entities for security
		$old_value = null;
		if ( function_exists( 'libxml_disable_entity_loader' ) ) {
			// $old_value = libxml_disable_entity_loader( true );
		}

		if ( ! class_exists( 'XMLReader' ) ) {
			$this->logger->critical( __( 'The XMLReader class is missing! Please install the XMLReader PHP extension on your server', 'wordpress-importer' ) );

			return false;
		}

		$reader = new XMLReader();
		$status = $reader->open( $file );

		if ( ! is_null( $old_value ) ) {
			// libxml_disable_entity_loader( $old_value );
		}

		if ( ! $status ) {
			$this->logger->error( __( 'Could not open the XML file for parsing!', 'wordpress-importer' ) );

			return false;
		}

		return $reader;
	}

	/**
	 * Get the basic import content data.
	 * Which elements are present in this import file (check possible elements in the $data variable)?
	 *
	 * @param $file
	 *
	 * @return array|bool
	 */
	public function get_basic_import_content_data( $file ) {
		$data = array(
			'users'      => false,
			'categories' => false,
			'tags'       => false,
			'terms'      => false,
			'posts'      => false,
		);

		// Get the XML reader and open the file.
		$reader = $this->get_reader( $file );

		if ( empty( $reader ) ) {
			return false;
		}

		// Start parsing!
		while ( $reader->read() ) {
			// Only deal with element opens.
			if ( $reader->nodeType !== XMLReader::ELEMENT ) {
				continue;
			}

			switch ( $reader->name ) {
				case 'wp:author':
					// Skip, if the users were already detected.
					if ( $data['users'] ) {
						$reader->next();
						break;
					}

					$node   = $reader->expand();
					$parsed = $this->parse_author_node( $node );

					// Skip, if there was an error in parsing the author node.
					if ( is_wp_error( $parsed ) ) {
						$reader->next();
						break;
					}

					$data['users'] = true;

					// Handled everything in this node, move on to the next.
					$reader->next();
					break;

				case 'item':
					// Skip, if the posts were already detected.
					if ( $data['posts'] ) {
						$reader->next();
						break;
					}

					$node   = $reader->expand();
					$parsed = $this->parse_post_node( $node );

					// Skip, if there was an error in parsing the item node.
					if ( is_wp_error( $parsed ) ) {
						$reader->next();
						break;
					}

					$data['posts'] = true;

					// Handled everything in this node, move on to the next
					$reader->next();
					break;

				case 'wp:category':
					$data['categories'] = true;

					// Handled everything in this node, move on to the next
					$reader->next();
					break;
				case 'wp:tag':
					$data['tags'] = true;

					// Handled everything in this node, move on to the next
					$reader->next();
					break;
				case 'wp:term':
					$data['terms'] = true;

					// Handled everything in this node, move on to the next
					$reader->next();
					break;
			}
		}

		return $data;
	}


	/**
	 * Get the number of posts (posts, pages, CPT, attachments), that the import file has.
	 *
	 * @param $file
	 *
	 * @return int
	 */
	public function get_number_of_posts_to_import( $file ) {
		$reader  = $this->get_reader( $file );
		$counter = 0;

		if ( empty( $reader ) ) {
			return $counter;
		}

		// Start parsing!
		while ( $reader->read() ) {
			// Only deal with element opens.
			if ( $reader->nodeType !== XMLReader::ELEMENT ) {
				continue;
			}

			if ( 'item' == $reader->name ) {
				$node   = $reader->expand();
				$parsed = $this->parse_post_node( $node );

				// Skip, if there was an error in parsing the item node.
				if ( is_wp_error( $parsed ) ) {
					$reader->next();
					continue;
				}

				$counter++;
			}
		}

		return $counter;
	}

	/**
	 * The main controller for the actual import stage.
	 *
	 * @param string $file    Path to the WXR file for importing.
	 * @param array  $options Import options (which parts to import).
	 *
	 * @return boolean
	 */
	public function import( $file, $options = array() ) {
		add_filter( 'import_post_meta_key', array( $this, 'is_valid_meta_key' ) );
		add_filter( 'http_request_timeout', array( &$this, 'bump_request_timeout' ) );

		// Start the import timer.
		$this->start_time = microtime( true );

		// Set the existing import data, from previous AJAX call, if any.
		$this->restore_import_data_transient();

		// Set the import options defaults.
		if ( empty( $options ) ) {
			$options = array(
				'users'      => false,
				'categories' => true,
				'tags'       => true,
				'terms'      => true,
				'posts'      => true,
			);
		}

		$result = $this->import_start( $file );

		if ( is_wp_error( $result ) ) {
			$this->logger->error( __( 'Content import start error: ', 'wordpress-importer' ) . $result->get_error_message() );

			return false;
		}

		// Get the actual XML reader.
		$reader = $this->get_reader( $file );

		if ( empty( $reader ) ) {
			return false;
		}

		// Set the version to compatibility mode first
		$this->version = '1.0';

		// Reset other variables
		$this->base_url = '';

		// Start parsing!
		while ( $reader->read() ) {
			// Only deal with element opens.
			if ( $reader->nodeType !== XMLReader::ELEMENT ) {
				continue;
			}

			switch ( $reader->name ) {
				case 'wp:wxr_version':
					// Upgrade to the correct version
					$this->version = $reader->readString();

					if ( version_compare( $this->version, self::MAX_WXR_VERSION, '>' ) ) {
						$this->logger->warning( sprintf(
							__( 'This WXR file (version %s) is newer than the importer (version %s) and may not be supported. Please consider updating.', 'wordpress-importer' ),
							$this->version,
							self::MAX_WXR_VERSION
						) );
					}

					// Handled everything in this node, move on to the next
					$reader->next();
					break;

				case 'wp:base_site_url':
					$this->base_url = $reader->readString();

					// Handled everything in this node, move on to the next
					$reader->next();
					break;

				case 'item':
					if ( empty( $options['posts'] ) ) {
						$reader->next();
						break;
					}

					$node   = $reader->expand();
					$parsed = $this->parse_post_node( $node );

					if ( is_wp_error( $parsed ) ) {
						$this->log_error( $parsed );

						// Skip the rest of this post
						$reader->next();
						break;
					}

					$this->process_post( $parsed['data'], $parsed['meta'], $parsed['comments'], $parsed['terms'] );

					// Handled everything in this node, move on to the next
					$reader->next();
					break;

				case 'wp:author':
					if ( empty( $options['users'] ) ) {
						$reader->next();
						break;
					}

					$node   = $reader->expand();
					$parsed = $this->parse_author_node( $node );

					if ( is_wp_error( $parsed ) ) {
						$this->log_error( $parsed );

						// Skip the rest of this post
						$reader->next();
						break;
					}

					$status = $this->process_author( $parsed['data'], $parsed['meta'] );

					if ( is_wp_error( $status ) ) {
						$this->log_error( $status );
					}

					// Handled everything in this node, move on to the next
					$reader->next();
					break;

				case 'wp:category':
					if ( empty( $options['categories'] ) ) {
						$reader->next();
						break;
					}

					$node   = $reader->expand();
					$parsed = $this->parse_term_node( $node, 'category' );

					if ( is_wp_error( $parsed ) ) {
						$this->log_error( $parsed );

						// Skip the rest of this post
						$reader->next();
						break;
					}

					$status = $this->process_term( $parsed['data'], $parsed['meta'] );

					// Handled everything in this node, move on to the next
					$reader->next();
					break;

				case 'wp:tag':
					if ( empty( $options['tags'] ) ) {
						$reader->next();
						break;
					}

					$node   = $reader->expand();
					$parsed = $this->parse_term_node( $node, 'tag' );

					if ( is_wp_error( $parsed ) ) {
						$this->log_error( $parsed );

						// Skip the rest of this post
						$reader->next();
						break;
					}

					$status = $this->process_term( $parsed['data'], $parsed['meta'] );

					// Handled everything in this node, move on to the next
					$reader->next();
					break;

				case 'wp:term':
					if ( empty( $options['terms'] ) ) {
						$reader->next();
						break;
					}

					$node   = $reader->expand();
					$parsed = $this->parse_term_node( $node );

					if ( is_wp_error( $parsed ) ) {
						$this->log_error( $parsed );

						// Skip the rest of this post
						$reader->next();
						break;
					}

					$status = $this->process_term( $parsed['data'], $parsed['meta'] );

					// Handled everything in this node, move on to the next
					$reader->next();
					break;

				default:
					// Skip this node, probably handled by something already
					break;
			}
		}

		// Now that we've done the main processing, do any required
		// post-processing and remapping.
		$this->post_process();

		if ( $this->options['aggressive_url_search'] ) {
			$this->replace_attachment_urls_in_content();
		}

		$this->remap_featured_images();

		$this->import_end();

		// Set the current importer state, so the data can be used on the next AJAX call.
		$this->set_current_importer_data();

		return true;
	}

	/**
	 * Import users only.
	 *
	 * @param string $file Path to the import file.
	 */
	public function import_users( $file ) {
		return $this->import( $file, array( 'users' => true ) );
	}

	/**
	 * Import categories only.
	 *
	 * @param string $file Path to the import file.
	 */
	public function import_categories( $file ) {
		return $this->import( $file, array( 'categories' => true ) );
	}

	/**
	 * Import tags only.
	 *
	 * @param string $file Path to the import file.
	 */
	public function import_tags( $file ) {
		return $this->import( $file, array( 'tags' => true ) );
	}

	/**
	 * Import terms only.
	 *
	 * @param string $file Path to the import file.
	 */
	public function import_terms( $file ) {
		return $this->import( $file, array( 'terms' => true ) );
	}

	/**
	 * Import posts only.
	 *
	 * @param string $file Path to the import file.
	 */
	public function import_posts( $file ) {
		return $this->import( $file, array( 'posts' => true ) );
	}

	/**
	 * Check if we need to create a new AJAX request, so that server does not timeout.
	 * And fix the import warning for missing post author.
	 *
	 * @param array $data current post data.
	 * @return array
	 */
	public function new_ajax_request_maybe( $data ) {
		$time = microtime( true ) - $this->start_time;

		// We should make a new ajax call, if the time is right.
		if ( $time > apply_filters( 'pt-importer/time_for_one_ajax_call', 20 ) ) {
			$response = apply_filters( 'pt-importer/new_ajax_request_response_data', array(
				'status'                => 'newAJAX',
				'log'                   => 'Time for new AJAX request!: ' . $time,
				'num_of_imported_posts' => count( $this->mapping['post'] ),
			) );

			// Add message to log file.
			$this->logger->info( __( 'New AJAX call!', 'wordpress-importer' ) );

			// Set the current importer state, so it can be continued on the next AJAX call.
			$this->set_current_importer_data();

			// Send the request for a new AJAX call.
			wp_send_json( $response );
		}

		// Set importing author to the current user.
		// Fixes the [WARNING] Could not find the author for ... log warning messages.
		$current_user_obj    = wp_get_current_user();
		$data['post_author'] = $current_user_obj->user_login;

		return $data;
	}

	/**
	 * Save current importer data to the DB, for later use.
	 */
	public function set_current_importer_data() {
		$data = apply_filters( 'pt-importer/set_current_importer_data', array(
			'options'            => $this->options,
			'mapping'            => $this->mapping,
			'requires_remapping' => $this->requires_remapping,
			'exists'             => $this->exists,
			'user_slug_override' => $this->user_slug_override,
			'url_remap'          => $this->url_remap,
			'featured_images'    => $this->featured_images,
		) );

		$this->save_current_import_data_transient( $data );
	}

	/**
	 * Set the importer data to the transient.
	 *
	 * @param array $data Data to be saved to the transient.
	 */
	public function save_current_import_data_transient( $data ) {
		set_transient( 'pt_importer_data', $data, MINUTE_IN_SECONDS );
	}

	/**
	 * Restore the importer data from the transient.
	 *
	 * @return boolean
	 */
	public function restore_import_data_transient() {
		if ( $data = get_transient( 'pt_importer_data' ) ) {
			$this->options            = empty( $data['options'] ) ? array() : $data['options'];
			$this->mapping            = empty( $data['mapping'] ) ? array() : $data['mapping'];
			$this->requires_remapping = empty( $data['requires_remapping'] ) ? array() : $data['requires_remapping'];
			$this->exists             = empty( $data['exists'] ) ? array() : $data['exists'];
			$this->user_slug_override = empty( $data['user_slug_override'] ) ? array() : $data['user_slug_override'];
			$this->url_remap          = empty( $data['url_remap'] ) ? array() : $data['url_remap'];
			$this->featured_images    = empty( $data['featured_images'] ) ? array() : $data['featured_images'];

			do_action( 'pt-importer/restore_import_data_transient' );

			return true;
		}

		return false;
	}

	/**
	 * Get the importer mapping data.
	 *
	 * @return array An empty array or an array of mapping data.
	 */
	public function get_mapping() {
		return $this->mapping;
	}

	/**
	 * Hook into the pre-process term filter of the content import and register the
	 * custom WooCommerce product attributes, so that the terms can then be imported normally.
	 *
	 * This should probably be removed once the WP importer 2.0 support is added in WooCommerce.
	 *
	 * Fixes: [WARNING] Failed to import pa_size L warnings in content import.
	 * Code from: woocommerce/includes/admin/class-wc-admin-importers.php (ver 2.6.9).
	 *
	 * Github issue: https://github.com/awesomemotive/one-click-demo-import/issues/71
	 *
	 * @param  array $date The term data to import.
	 * @return array       The unchanged term data.
	 */
	public function woocommerce_product_attributes_registration( $data ) {
		global $wpdb;

		if ( strstr( $data['taxonomy'], 'pa_' ) ) {
			if ( ! taxonomy_exists( $data['taxonomy'] ) ) {
				$attribute_name = wc_sanitize_taxonomy_name( str_replace( 'pa_', '', $data['taxonomy'] ) );

				// Create the taxonomy
				if ( ! in_array( $attribute_name, wc_get_attribute_taxonomies() ) ) {
					$attribute = array(
						'attribute_label'   => $attribute_name,
						'attribute_name'    => $attribute_name,
						'attribute_type'    => 'select',
						'attribute_orderby' => 'menu_order',
						'attribute_public'  => 0
					);
					$wpdb->insert( $wpdb->prefix . 'woocommerce_attribute_taxonomies', $attribute );
					delete_transient( 'wc_attribute_taxonomies' );
				}

				// Register the taxonomy now so that the import works!
				register_taxonomy(
					$data['taxonomy'],
					apply_filters( 'woocommerce_taxonomy_objects_' . $data['taxonomy'], array( 'product' ) ),
					apply_filters( 'woocommerce_taxonomy_args_' . $data['taxonomy'], array(
						'hierarchical' => true,
						'show_ui'      => false,
						'query_var'    => true,
						'rewrite'      => false,
					) )
				);
			}
		}

		return $data;
	}
}
PK/3Y�h”R
R
Wbunyad-demo-import/vendor/awesomemotive/wp-content-importer-v2/src/WPImporterLogger.php<?php
namespace AwesomeMotive\WPContentImporter2;

/**
 * Describes a logger instance
 *
 * Based on PSR-3: http://www.php-fig.org/psr/psr-3/
 *
 * The message MUST be a string or object implementing __toString().
 *
 * The message MAY contain placeholders in the form: {foo} where foo
 * will be replaced by the context data in key "foo".
 *
 * The context array can contain arbitrary data, the only assumption that
 * can be made by implementors is that if an Exception instance is given
 * to produce a stack trace, it MUST be in a key named "exception".
 *
 * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
 * for the full interface specification.
 */
class WPImporterLogger {
	/**
	 * System is unusable.
	 *
	 * @param string $message
	 * @param array $context
	 * @return null
	 */
	public function emergency( $message, array $context = array() ) {
		return $this->log( 'emergency', $message, $context );
	}

	/**
	 * Action must be taken immediately.
	 *
	 * Example: Entire website down, database unavailable, etc. This should
	 * trigger the SMS alerts and wake you up.
	 *
	 * @param string $message
	 * @param array $context
	 * @return null
	 */
	public function alert( $message, array $context = array() ) {
		return $this->log( 'alert', $message, $context );
	}

	/**
	 * Critical conditions.
	 *
	 * Example: Application component unavailable, unexpected exception.
	 *
	 * @param string $message
	 * @param array $context
	 * @return null
	 */
	public function critical( $message, array $context = array() ) {
		return $this->log( 'critical', $message, $context );
	}

	/**
	 * Runtime errors that do not require immediate action but should typically
	 * be logged and monitored.
	 *
	 * @param string $message
	 * @param array $context
	 * @return null
	 */
	public function error( $message, array $context = array()) {
		return $this->log( 'error', $message, $context );
	}

	/**
	 * Exceptional occurrences that are not errors.
	 *
	 * Example: Use of deprecated APIs, poor use of an API, undesirable things
	 * that are not necessarily wrong.
	 *
	 * @param string $message
	 * @param array $context
	 * @return null
	 */
	public function warning( $message, array $context = array() ) {
		return $this->log( 'warning', $message, $context );
	}

	/**
	 * Normal but significant events.
	 *
	 * @param string $message
	 * @param array $context
	 * @return null
	 */
	public function notice( $message, array $context = array() ) {
		return $this->log( 'notice', $message, $context );
	}

	/**
	 * Interesting events.
	 *
	 * Example: User logs in, SQL logs.
	 *
	 * @param string $message
	 * @param array $context
	 * @return null
	 */
	public function info( $message, array $context = array() ) {
		return $this->log( 'info', $message, $context );
	}

	/**
	 * Detailed debug information.
	 *
	 * @param string $message
	 * @param array $context
	 * @return null
	 */
	public function debug( $message, array $context = array() ) {
		return $this->log( 'debug', $message, $context );
	}

	/**
	 * Logs with an arbitrary level.
	 *
	 * @param mixed $level
	 * @param string $message
	 * @param array $context
	 * @return null
	 */
	public function log( $level, $message, array $context = array() ) {
		$this->messages[] = array(
			'timestamp' => time(),
			'level'     => $level,
			'message'   => $message,
			'context'   => $context,
		);
	}
}
PK/3Y��ǼffZbunyad-demo-import/vendor/awesomemotive/wp-content-importer-v2/src/WPImporterLoggerCLI.php<?php
namespace AwesomeMotive\WPContentImporter2;

class WPImporterLoggerCLI extends WPImporterLogger {
	public $min_level = 'notice';

	/**
	 * Logs with an arbitrary level.
	 *
	 * @param mixed $level
	 * @param string $message
	 * @param array $context
	 * @return null
	 */
	public function log( $level, $message, array $context = array() ) {
		if ( $this->level_to_numeric( $level ) < $this->level_to_numeric( $this->min_level ) ) {
			return;
		}

		printf(
			'[%s] %s' . PHP_EOL,
			strtoupper( $level ),
			$message
		);
	}

	public static function level_to_numeric( $level ) {
		$levels = array(
			'emergency' => 8,
			'alert'     => 7,
			'critical'  => 6,
			'error'     => 5,
			'warning'   => 4,
			'notice'    => 3,
			'info'      => 2,
			'debug'     => 1,
		);
		if ( ! isset( $levels[ $level ] ) ) {
			return 0;
		}

		return $levels[ $level ];
	}
}
PK/3Yv��'�'Rbunyad-demo-import/vendor/awesomemotive/wp-content-importer-v2/src/WXRImporter.php<?php
namespace AwesomeMotive\WPContentImporter2;

use WP_Error;
use XMLReader;

class WXRImporter extends \WP_Importer {
	/**
	 * Maximum supported WXR version
	 */
	const MAX_WXR_VERSION = 1.2;

	/**
	 * Regular expression for checking if a post references an attachment
	 *
	 * Note: This is a quick, weak check just to exclude text-only posts. More
	 * vigorous checking is done later to verify.
	 */
	const REGEX_HAS_ATTACHMENT_REFS = '!
		(
			# Match anything with an image or attachment class
			class=[\'"].*?\b(wp-image-\d+|attachment-[\w\-]+)\b
		|
			# Match anything that looks like an upload URL
			src=[\'"][^\'"]*(
				[0-9]{4}/[0-9]{2}/[^\'"]+\.(jpg|jpeg|png|gif)
			|
				content/uploads[^\'"]+
			)[\'"]
		)!ix';

	/**
	 * Version of WXR we're importing.
	 *
	 * Defaults to 1.0 for compatibility. Typically overridden by a
	 * `<wp:wxr_version>` tag at the start of the file.
	 *
	 * @var string
	 */
	protected $version = '1.0';

	// information to import from WXR file
	protected $categories = array();
	protected $tags = array();
	protected $base_url = '';

	// TODO: REMOVE THESE
	protected $processed_terms = array();
	protected $processed_posts = array();
	protected $processed_menu_items = array();
	protected $menu_item_orphans = array();
	protected $missing_menu_items = array();

	// NEW STYLE
	public $options = array();
	protected $mapping = array();
	protected $requires_remapping = array();
	protected $exists = array();
	protected $user_slug_override = array();

	protected $url_remap = array();
	protected $featured_images = array();

	/**
	 * Logger instance.
	 *
	 * @var WPImporterLogger
	 */
	protected $logger;

	/**
	 * Constructor
	 *
	 * @param array $options {
	 *     @var bool $prefill_existing_posts Should we prefill `post_exists` calls? (True prefills and uses more memory, false checks once per imported post and takes longer. Default is true.)
	 *     @var bool $prefill_existing_comments Should we prefill `comment_exists` calls? (True prefills and uses more memory, false checks once per imported comment and takes longer. Default is true.)
	 *     @var bool $prefill_existing_terms Should we prefill `term_exists` calls? (True prefills and uses more memory, false checks once per imported term and takes longer. Default is true.)
	 *     @var bool $update_attachment_guids Should attachment GUIDs be updated to the new URL? (True updates the GUID, which keeps compatibility with v1, false doesn't update, and allows duplication and reimporting. Default is false.)
	 *     @var bool $fetch_attachments Fetch attachments from the remote server. (True fetches and creates attachment posts, false skips attachments. Default is false.)
	 *     @var bool $aggressive_url_search Should we search/replace for URLs aggressively? (True searches all posts' content for old URLs and replaces, false checks for `<img class="wp-image-*">` only. Default is false.)
	 *     @var int $default_author User ID to use if author is missing or invalid. (Default is null, which leaves posts unassigned.)
	 * }
	 */
	public function __construct( $options = array() ) {
		// Initialize some important variables
		$empty_types = array(
			'post'    => array(),
			'comment' => array(),
			'term'    => array(),
			'user'    => array(),
		);

		$this->mapping = $empty_types;
		$this->mapping['user_slug'] = array();
		$this->mapping['term_id'] = array();
		$this->requires_remapping = $empty_types;
		$this->exists = $empty_types;

		$this->options = wp_parse_args( $options, array(
			'prefill_existing_posts'    => true,
			'prefill_existing_comments' => true,
			'prefill_existing_terms'    => true,
			'update_attachment_guids'   => false,
			'fetch_attachments'         => false,
			'aggressive_url_search'     => false,
			'default_author'            => null,
		) );
	}

	public function set_logger( $logger ) {
		$this->logger = $logger;
	}

	/**
	 * Get a stream reader for the file.
	 *
	 * @param string $file Path to the XML file.
	 * @return XMLReader|WP_Error Reader instance on success, error otherwise.
	 */
	protected function get_reader( $file ) {
		// Avoid loading external entities for security
		$old_value = null;
		if ( function_exists( 'libxml_disable_entity_loader' ) ) {
			// $old_value = libxml_disable_entity_loader( true );
		}

		$reader = new XMLReader();
		$status = $reader->open( $file );

		if ( ! is_null( $old_value ) ) {
			// libxml_disable_entity_loader( $old_value );
		}

		if ( ! $status ) {
			return new WP_Error( 'wxr_importer.cannot_parse', __( 'Could not open the file for parsing', 'wordpress-importer' ) );
		}

		return $reader;
	}

	/**
	 * The main controller for the actual import stage.
	 *
	 * @param string $file Path to the WXR file for importing
	 *
	 * @return WXRImportInfo|WP_Error
	 */
	public function get_preliminary_information( $file ) {
		// Let's run the actual importer now, woot
		$reader = $this->get_reader( $file );
		if ( is_wp_error( $reader ) ) {
			return $reader;
		}

		// Set the version to compatibility mode first
		$this->version = '1.0';

		// Start parsing!
		$data = new WXRImportInfo();
		while ( $reader->read() ) {
			// Only deal with element opens
			if ( $reader->nodeType !== XMLReader::ELEMENT ) {
				continue;
			}

			switch ( $reader->name ) {
				case 'wp:wxr_version':
					// Upgrade to the correct version
					$this->version = $reader->readString();

					if ( version_compare( $this->version, self::MAX_WXR_VERSION, '>' ) ) {
						$this->logger->warning( sprintf(
							__( 'This WXR file (version %s) is newer than the importer (version %s) and may not be supported. Please consider updating.', 'wordpress-importer' ),
							$this->version,
							self::MAX_WXR_VERSION
						) );
					}

					// Handled everything in this node, move on to the next
					$reader->next();
					break;

				case 'generator':
					$data->generator = $reader->readString();
					$reader->next();
					break;

				case 'title':
					$data->title = $reader->readString();
					$reader->next();
					break;

				case 'wp:base_site_url':
					$data->siteurl = $reader->readString();
					$reader->next();
					break;

				case 'wp:base_blog_url':
					$data->home = $reader->readString();
					$reader->next();
					break;

				case 'wp:author':
					$node = $reader->expand();

					$parsed = $this->parse_author_node( $node );
					if ( is_wp_error( $parsed ) ) {
						$this->log_error( $parsed );

						// Skip the rest of this post
						$reader->next();
						break;
					}

					$data->users[] = $parsed;

					// Handled everything in this node, move on to the next
					$reader->next();
					break;

				case 'item':
					$node = $reader->expand();
					$parsed = $this->parse_post_node( $node );
					if ( is_wp_error( $parsed ) ) {
						$this->log_error( $parsed );

						// Skip the rest of this post
						$reader->next();
						break;
					}

					if ( $parsed['data']['post_type'] === 'attachment' ) {
						$data->media_count++;
					} else {
						$data->post_count++;
					}
					$data->comment_count += count( $parsed['comments'] );

					// Handled everything in this node, move on to the next
					$reader->next();
					break;

				case 'wp:category':
				case 'wp:tag':
				case 'wp:term':
					$data->term_count++;

					// Handled everything in this node, move on to the next
					$reader->next();
					break;
			}
		}

		$data->version = $this->version;

		return $data;
	}

	/**
	 * The main controller for the actual import stage.
	 *
	 * @param string $file Path to the WXR file for importing
	 *
	 * @return array|WP_Error
	 */
	public function parse_authors( $file ) {
		// Let's run the actual importer now, woot
		$reader = $this->get_reader( $file );
		if ( is_wp_error( $reader ) ) {
			return $reader;
		}

		// Set the version to compatibility mode first
		$this->version = '1.0';

		// Start parsing!
		$authors = array();
		while ( $reader->read() ) {
			// Only deal with element opens
			if ( $reader->nodeType !== XMLReader::ELEMENT ) {
				continue;
			}

			switch ( $reader->name ) {
				case 'wp:wxr_version':
					// Upgrade to the correct version
					$this->version = $reader->readString();

					if ( version_compare( $this->version, self::MAX_WXR_VERSION, '>' ) ) {
						$this->logger->warning( sprintf(
							__( 'This WXR file (version %s) is newer than the importer (version %s) and may not be supported. Please consider updating.', 'wordpress-importer' ),
							$this->version,
							self::MAX_WXR_VERSION
						) );
					}

					// Handled everything in this node, move on to the next
					$reader->next();
					break;

				case 'wp:author':
					$node = $reader->expand();

					$parsed = $this->parse_author_node( $node );
					if ( is_wp_error( $parsed ) ) {
						$this->log_error( $parsed );

						// Skip the rest of this post
						$reader->next();
						break;
					}

					$authors[] = $parsed;

					// Handled everything in this node, move on to the next
					$reader->next();
					break;
			}
		}

		return $authors;
	}

	/**
	 * The main controller for the actual import stage.
	 *
	 * @param string $file Path to the WXR file for importing.
	 */
	public function import( $file ) {
		add_filter( 'import_post_meta_key', array( $this, 'is_valid_meta_key' ) );
		add_filter( 'http_request_timeout', array( &$this, 'bump_request_timeout' ) );

		/*
		 * Elementor fix for excessive use of `wp_slash` after our update v3.0.2.
		 * Method in Elementor: \Elementor\Compatibility::register_actions
		 * https://wordpress.org/support/topic/version-2-6-0-breaks-every-elementor-theme/
		 *
		 * This can be removed after Elementor skips the functionality in above method if our plugin is in use.
		 */
		if ( method_exists( '\Elementor\Compatibility', 'on_wxr_importer_pre_process_post_meta' ) ) {
			remove_action( 'wxr_importer.pre_process.post_meta', array( 'Elementor\Compatibility', 'on_wxr_importer_pre_process_post_meta' ) );
		}

		$result = $this->import_start( $file );
		if ( is_wp_error( $result ) ) {
			return $result;
		}

		// Let's run the actual importer now, woot
		$reader = $this->get_reader( $file );
		if ( is_wp_error( $reader ) ) {
			return $reader;
		}

		// Set the version to compatibility mode first
		$this->version = '1.0';

		// Reset other variables
		$this->base_url = '';

		// Start parsing!
		while ( $reader->read() ) {
			// Only deal with element opens
			if ( $reader->nodeType !== XMLReader::ELEMENT ) {
				continue;
			}

			switch ( $reader->name ) {
				case 'wp:wxr_version':
					// Upgrade to the correct version
					$this->version = $reader->readString();

					if ( version_compare( $this->version, self::MAX_WXR_VERSION, '>' ) ) {
						$this->logger->warning( sprintf(
							__( 'This WXR file (version %s) is newer than the importer (version %s) and may not be supported. Please consider updating.', 'wordpress-importer' ),
							$this->version,
							self::MAX_WXR_VERSION
						) );
					}

					// Handled everything in this node, move on to the next
					$reader->next();
					break;

				case 'wp:base_site_url':
					$this->base_url = $reader->readString();

					// Handled everything in this node, move on to the next
					$reader->next();
					break;

				case 'item':
					$node = $reader->expand();
					$parsed = $this->parse_post_node( $node );
					if ( is_wp_error( $parsed ) ) {
						$this->log_error( $parsed );

						// Skip the rest of this post
						$reader->next();
						break;
					}

					$this->process_post( $parsed['data'], $parsed['meta'], $parsed['comments'], $parsed['terms'] );

					// Handled everything in this node, move on to the next
					$reader->next();
					break;

				case 'wp:author':
					$node = $reader->expand();

					$parsed = $this->parse_author_node( $node );
					if ( is_wp_error( $parsed ) ) {
						$this->log_error( $parsed );

						// Skip the rest of this post
						$reader->next();
						break;
					}

					$status = $this->process_author( $parsed['data'], $parsed['meta'] );
					if ( is_wp_error( $status ) ) {
						$this->log_error( $status );
					}

					// Handled everything in this node, move on to the next
					$reader->next();
					break;

				case 'wp:category':
					$node = $reader->expand();

					$parsed = $this->parse_term_node( $node, 'category' );
					if ( is_wp_error( $parsed ) ) {
						$this->log_error( $parsed );

						// Skip the rest of this post
						$reader->next();
						break;
					}

					$status = $this->process_term( $parsed['data'], $parsed['meta'] );

					// Handled everything in this node, move on to the next
					$reader->next();
					break;

				case 'wp:tag':
					$node = $reader->expand();

					$parsed = $this->parse_term_node( $node, 'tag' );
					if ( is_wp_error( $parsed ) ) {
						$this->log_error( $parsed );

						// Skip the rest of this post
						$reader->next();
						break;
					}

					$status = $this->process_term( $parsed['data'], $parsed['meta'] );

					// Handled everything in this node, move on to the next
					$reader->next();
					break;

				case 'wp:term':
					$node = $reader->expand();

					$parsed = $this->parse_term_node( $node );
					if ( is_wp_error( $parsed ) ) {
						$this->log_error( $parsed );

						// Skip the rest of this post
						$reader->next();
						break;
					}

					$status = $this->process_term( $parsed['data'], $parsed['meta'] );

					// Handled everything in this node, move on to the next
					$reader->next();
					break;

				default:
					// Skip this node, probably handled by something already
					break;
			}
		}

		// Now that we've done the main processing, do any required
		// post-processing and remapping.
		$this->post_process();

		if ( $this->options['aggressive_url_search'] ) {
			$this->replace_attachment_urls_in_content();
		}

		$this->remap_featured_images();

		$this->import_end();
	}

	/**
	 * Log an error instance to the logger.
	 *
	 * @param WP_Error $error Error instance to log.
	 */
	protected function log_error( WP_Error $error ) {
		$this->logger->warning( $error->get_error_message() );

		// Log the data as debug info too
		$data = $error->get_error_data();
		if ( ! empty( $data ) ) {
			$this->logger->debug( var_export( $data, true ) );
		}
	}

	/**
	 * Parses the WXR file and prepares us for the task of processing parsed data
	 *
	 * @param string $file Path to the WXR file for importing
	 */
	protected function import_start( $file ) {
		if ( ! is_file( $file ) ) {
			return new WP_Error( 'wxr_importer.file_missing', __( 'The file does not exist, please try again.', 'wordpress-importer' ) );
		}

		// Suspend bunches of stuff in WP core
		wp_defer_term_counting( true );
		wp_defer_comment_counting( true );
		wp_suspend_cache_invalidation( true );

		// Prefill exists calls if told to
		if ( $this->options['prefill_existing_posts'] ) {
			$this->prefill_existing_posts();
		}
		if ( $this->options['prefill_existing_comments'] ) {
			$this->prefill_existing_comments();
		}
		if ( $this->options['prefill_existing_terms'] ) {
			$this->prefill_existing_terms();
		}

		/**
		 * Begin the import.
		 *
		 * Fires before the import process has begun. If you need to suspend
		 * caching or heavy processing on hooks, do so here.
		 */
		do_action( 'import_start' );
	}

	/**
	 * Performs post-import cleanup of files and the cache
	 */
	protected function import_end() {
		// Re-enable stuff in core
		wp_suspend_cache_invalidation( false );
		wp_cache_flush();

		foreach ( get_taxonomies() as $tax ) {
			delete_option( "{$tax}_children" );
			_get_term_hierarchy( $tax );
		}

		wp_defer_term_counting( false );
		wp_defer_comment_counting( false );

		flush_rewrite_rules();

		/**
		 * Complete the import.
		 *
		 * Fires after the import process has finished. If you need to update
		 * your cache or re-enable processing, do so here.
		 */
		do_action( 'import_end' );
	}

	/**
	 * Set the user mapping.
	 *
	 * @param array $mapping List of map arrays (containing `old_slug`, `old_id`, `new_id`)
	 */
	public function set_user_mapping( $mapping ) {
		foreach ( $mapping as $map ) {
			if ( empty( $map['old_slug'] ) || empty( $map['old_id'] ) || empty( $map['new_id'] ) ) {
				$this->logger->warning( __( 'Invalid author mapping', 'wordpress-importer' ) );
				$this->logger->debug( var_export( $map, true ) );
				continue;
			}

			$old_slug = $map['old_slug'];
			$old_id   = $map['old_id'];
			$new_id   = $map['new_id'];

			$this->mapping['user'][ $old_id ]        = $new_id;
			$this->mapping['user_slug'][ $old_slug ] = $new_id;
		}
	}

	/**
	 * Set the user slug overrides.
	 *
	 * Allows overriding the slug in the import with a custom/renamed version.
	 *
	 * @param string[] $overrides Map of old slug to new slug.
	 */
	public function set_user_slug_overrides( $overrides ) {
		foreach ( $overrides as $original => $renamed ) {
			$this->user_slug_override[ $original ] = $renamed;
		}
	}

	/**
	 * Parse a post node into post data.
	 *
	 * @param \DOMNode $node Parent node of post data (typically `item`).
	 * @return array|WP_Error Post data array on success, error otherwise.
	 */
	protected function parse_post_node( $node ) {
		$data = array();
		$meta = array();
		$comments = array();
		$terms = array();

		foreach ( $node->childNodes as $child ) {
			// We only care about child elements
			if ( $child->nodeType !== XML_ELEMENT_NODE ) {
				continue;
			}

			switch ( $child->tagName ) {
				case 'wp:post_type':
					$data['post_type'] = $child->textContent;
					break;

				case 'title':
					$data['post_title'] = $child->textContent;
					break;

				case 'guid':
					$data['guid'] = $child->textContent;
					break;

				case 'dc:creator':
					$data['post_author'] = $child->textContent;
					break;

				case 'content:encoded':
					$data['post_content'] = $child->textContent;
					break;

				case 'excerpt:encoded':
					$data['post_excerpt'] = $child->textContent;
					break;

				case 'wp:post_id':
					$data['post_id'] = $child->textContent;
					break;

				case 'wp:post_date':
					$data['post_date'] = $child->textContent;
					break;

				case 'wp:post_date_gmt':
					$data['post_date_gmt'] = $child->textContent;
					break;

				case 'wp:comment_status':
					$data['comment_status'] = $child->textContent;
					break;

				case 'wp:ping_status':
					$data['ping_status'] = $child->textContent;
					break;

				case 'wp:post_name':
					$data['post_name'] = $child->textContent;
					break;

				case 'wp:status':
					$data['post_status'] = $child->textContent;

					if ( $data['post_status'] === 'auto-draft' ) {
						// Bail now
						return new WP_Error(
							'wxr_importer.post.cannot_import_draft',
							__( 'Cannot import auto-draft posts' ),
							$data
						);
					}
					break;

				case 'wp:post_parent':
					$data['post_parent'] = $child->textContent;
					break;

				case 'wp:menu_order':
					$data['menu_order'] = $child->textContent;
					break;

				case 'wp:post_password':
					$data['post_password'] = $child->textContent;
					break;

				case 'wp:is_sticky':
					$data['is_sticky'] = $child->textContent;
					break;

				case 'wp:attachment_url':
					$data['attachment_url'] = $child->textContent;
					break;

				case 'wp:postmeta':
					$meta_item = $this->parse_meta_node( $child );
					if ( ! empty( $meta_item ) ) {
						$meta[] = $meta_item;
					}
					break;

				case 'wp:comment':
					$comment_item = $this->parse_comment_node( $child );
					if ( ! empty( $comment_item ) ) {
						$comments[] = $comment_item;
					}
					break;

				case 'category':
					$term_item = $this->parse_category_node( $child );
					if ( ! empty( $term_item ) ) {
						$terms[] = $term_item;
					}
					break;
			}
		}

		return compact( 'data', 'meta', 'comments', 'terms' );
	}

	/**
	 * Create new posts based on import information
	 *
	 * Posts marked as having a parent which doesn't exist will become top level items.
	 * Doesn't create a new post if: the post type doesn't exist, the given post ID
	 * is already noted as imported or a post with the same title and date already exists.
	 * Note that new/updated terms, comments and meta are imported for the last of the above.
	 *
	 * @param array $data     Post data.
	 * @param array $meta     Meta data.
	 * @param array $comments Comments on the post.
	 * @param array $terms    Terms on the post.
	 */
	protected function process_post( $data, $meta, $comments, $terms ) {
		/**
		 * Pre-process post data.
		 *
		 * @param array $data Post data. (Return empty to skip.)
		 * @param array $meta Meta data.
		 * @param array $comments Comments on the post.
		 * @param array $terms Terms on the post.
		 */
		$data = apply_filters( 'wxr_importer.pre_process.post', $data, $meta, $comments, $terms );
		if ( empty( $data ) ) {
			return false;
		}

		$original_id = isset( $data['post_id'] )     ? (int) $data['post_id']     : 0;
		$parent_id   = isset( $data['post_parent'] ) ? (int) $data['post_parent'] : 0;

		// Have we already processed this?
		if ( isset( $this->mapping['post'][ $original_id ] ) ) {
			return false;
		}

		$post_type_object = get_post_type_object( $data['post_type'] );

		// Is this type even valid?
		if ( ! $post_type_object ) {
			$this->logger->warning( sprintf(
				__( 'Failed to import "%s": Invalid post type %s', 'wordpress-importer' ),
				$data['post_title'],
				$data['post_type']
			) );
			return false;
		}

		$post_exists = $this->post_exists( $data );
		if ( $post_exists ) {
			$this->logger->info( sprintf(
				__( '%s "%s" already exists.', 'wordpress-importer' ),
				$post_type_object->labels->singular_name,
				$data['post_title']
			) );

			// Even though this post already exists, new comments might need importing
			$this->process_comments( $comments, $original_id, $data, $post_exists );

			return false;
		}

		// Map the parent post, or mark it as one we need to fix
		$requires_remapping = false;
		if ( $parent_id ) {
			if ( isset( $this->mapping['post'][ $parent_id ] ) ) {
				$data['post_parent'] = $this->mapping['post'][ $parent_id ];
			} else {
				$meta[] = array( 'key' => '_wxr_import_parent', 'value' => $parent_id );
				$requires_remapping = true;

				$data['post_parent'] = 0;
			}
		}

		// Map the author, or mark it as one we need to fix
		$author = sanitize_user( $data['post_author'], true );
		if ( empty( $author ) ) {
			// Missing or invalid author, use default if available.
			$data['post_author'] = $this->options['default_author'];
		} elseif ( isset( $this->mapping['user_slug'][ $author ] ) ) {
			$data['post_author'] = $this->mapping['user_slug'][ $author ];
		} else {
			$meta[] = array( 'key' => '_wxr_import_user_slug', 'value' => $author );
			$requires_remapping = true;

			$data['post_author'] = (int) get_current_user_id();
		}

		// Does the post look like it contains attachment images?
		if ( preg_match( self::REGEX_HAS_ATTACHMENT_REFS, $data['post_content'] ) ) {
			$meta[] = array( 'key' => '_wxr_import_has_attachment_refs', 'value' => true );
			$requires_remapping = true;
		}

		// Whitelist to just the keys we allow
		$postdata = array(
			'import_id' => $data['post_id'],
		);
		$allowed = array(
			'post_author'    => true,
			'post_date'      => true,
			'post_date_gmt'  => true,
			'post_content'   => true,
			'post_excerpt'   => true,
			'post_title'     => true,
			'post_status'    => true,
			'post_name'      => true,
			'comment_status' => true,
			'ping_status'    => true,
			'guid'           => true,
			'post_parent'    => true,
			'menu_order'     => true,
			'post_type'      => true,
			'post_password'  => true,
		);
		foreach ( $data as $key => $value ) {
			if ( ! isset( $allowed[ $key ] ) ) {
				continue;
			}

			$postdata[ $key ] = $data[ $key ];
		}

		$postdata = apply_filters( 'wp_import_post_data_processed', wp_slash( $postdata ), $data );

		if ( 'attachment' === $postdata['post_type'] ) {
			if ( ! $this->options['fetch_attachments'] ) {
				$this->logger->notice( sprintf(
					__( 'Skipping attachment "%s", fetching attachments disabled' ),
					$data['post_title']
				) );
				return false;
			}
			$remote_url = ! empty( $data['attachment_url'] ) ? $data['attachment_url'] : $data['guid'];
			$post_id = $this->process_attachment( $postdata, $meta, $remote_url );
		} else {
			$post_id = wp_insert_post( $postdata, true );
			do_action( 'wp_import_insert_post', $post_id, $original_id, $postdata, $data );
		}

		if ( is_wp_error( $post_id ) ) {
			$this->logger->error( sprintf(
				__( 'Failed to import "%s" (%s)', 'wordpress-importer' ),
				$data['post_title'],
				$post_type_object->labels->singular_name
			) );
			$this->logger->debug( $post_id->get_error_message() );

			/**
			 * Post processing failed.
			 *
			 * @param WP_Error $post_id Error object.
			 * @param array $data Raw data imported for the post.
			 * @param array $meta Raw meta data, already processed by {@see process_post_meta}.
			 * @param array $comments Raw comment data, already processed by {@see process_comments}.
			 * @param array $terms Raw term data, already processed.
			 */
			do_action( 'wxr_importer.process_failed.post', $post_id, $data, $meta, $comments, $terms );
			return false;
		}

		// Ensure stickiness is handled correctly too
		if ( $data['is_sticky'] === '1' ) {
			stick_post( $post_id );
		}

		// map pre-import ID to local ID
		$this->mapping['post'][ $original_id ] = (int) $post_id;
		if ( $requires_remapping ) {
			$this->requires_remapping['post'][ $post_id ] = true;
		}
		$this->mark_post_exists( $data, $post_id );

		$this->logger->info( sprintf(
			__( 'Imported "%s" (%s)', 'wordpress-importer' ),
			$data['post_title'],
			$post_type_object->labels->singular_name
		) );
		$this->logger->debug( sprintf(
			__( 'Post %d remapped to %d', 'wordpress-importer' ),
			$original_id,
			$post_id
		) );

		// Handle the terms too
		$terms = apply_filters( 'wp_import_post_terms', $terms, $post_id, $data );

		if ( ! empty( $terms ) ) {
			$term_ids = array();
			foreach ( $terms as $term ) {
				$taxonomy = $term['taxonomy'];
				$key = sha1( $taxonomy . ':' . $term['slug'] );

				if ( isset( $this->mapping['term'][ $key ] ) ) {
					$term_ids[ $taxonomy ][] = (int) $this->mapping['term'][ $key ];
				} else {

					/**
					 * Fix for the post format "categories".
					 * The issue in this importer is, that these post formats are misused as categories in WP export
					 * (as the export data <category> item in the post export item), but they are not actually
					 * exported as wp:category items in the XML file, so they need to be inserted on the fly (here).
					 *
					 * Maybe something better can be done in the future?
					 *
					 * Original issue reported here: https://wordpress.org/support/topic/post-format-videoquotegallery-became-format-standard/#post-8447683
					 *
					 */
					if ( 'post_format' === $taxonomy ) {
						$term_exists = term_exists( $term['slug'], $taxonomy );
						$term_id = is_array( $term_exists ) ? $term_exists['term_id'] : $term_exists;

						if ( empty( $term_id ) ) {
							$t = wp_insert_term( $term['name'], $taxonomy, array( 'slug' => $term['slug'] ) );
							if ( ! is_wp_error( $t ) ) {
								$term_id = $t['term_id'];
								$this->mapping['term'][ $key ] = $term_id;
							} else {
								$this->logger->warning( sprintf(
									esc_html__( 'Failed to import term: %s - %s', 'wordpress-importer' ),
									esc_html( $taxonomy ),
									esc_html( $term['name'] )
								) );
								continue;
							}
						}

						if ( ! empty( $term_id ) ) {
							$term_ids[ $taxonomy ][] = intval( $term_id );
						}
					} // End of fix.
					else {
						$meta[] = array( 'key' => '_wxr_import_term', 'value' => $term );
						$requires_remapping = true;
					}
				}
			}

			foreach ( $term_ids as $tax => $ids ) {
				$tt_ids = wp_set_post_terms( $post_id, $ids, $tax );
				do_action( 'wp_import_set_post_terms', $tt_ids, $ids, $tax, $post_id, $data );
			}
		}

		$this->process_comments( $comments, $post_id, $data );
		$this->process_post_meta( $meta, $post_id, $data );

		if ( 'nav_menu_item' === $data['post_type'] ) {
			$this->process_menu_item_meta( $post_id, $data, $meta );
		}

		/**
		 * Post processing completed.
		 *
		 * @param int $post_id New post ID.
		 * @param array $data Raw data imported for the post.
		 * @param array $meta Raw meta data, already processed by {@see process_post_meta}.
		 * @param array $comments Raw comment data, already processed by {@see process_comments}.
		 * @param array $terms Raw term data, already processed.
		 */
		do_action( 'wxr_importer.processed.post', $post_id, $data, $meta, $comments, $terms );
	}

	/**
	 * Attempt to create a new menu item from import data
	 *
	 * Fails for draft, orphaned menu items and those without an associated nav_menu
	 * or an invalid nav_menu term. If the post type or term object which the menu item
	 * represents doesn't exist then the menu item will not be imported (waits until the
	 * end of the import to retry again before discarding).
	 *
	 * @param int $post_id Menu item post ID.
	 * @param array $data  Menu item details from WXR file.
	 * @param array $meta  Menu item meta details.
	 */
	protected function process_menu_item_meta( $post_id, $data, $meta ) {

		$item_type = get_post_meta( $post_id, '_menu_item_type', true );
		$original_object_id = get_post_meta( $post_id, '_menu_item_object_id', true );
		$object_id = null;

		$this->logger->debug( sprintf( 'Processing menu item %s', $item_type ) );

		$requires_remapping = false;
		switch ( $item_type ) {
			case 'taxonomy':
				if ( isset( $this->mapping['term_id'][ $original_object_id ] ) ) {
					$object_id = $this->mapping['term_id'][ $original_object_id ];
				} else {
					add_post_meta( $post_id, '_wxr_import_menu_item', wp_slash( $original_object_id ) );
					$requires_remapping = true;
				}
				break;

			case 'post_type':
				if ( isset( $this->mapping['post'][ $original_object_id ] ) ) {
					$object_id = $this->mapping['post'][ $original_object_id ];
				} else {
					add_post_meta( $post_id, '_wxr_import_menu_item', wp_slash( $original_object_id ) );
					$requires_remapping = true;
				}
				break;

			case 'custom':
				// Custom refers to itself, wonderfully easy.
				$object_id = $post_id;
				break;

			default:
				// associated object is missing or not imported yet, we'll retry later
				$this->missing_menu_items[] = $data;
				$this->logger->debug( 'Unknown menu item type' );
				break;
		}

		if ( $requires_remapping ) {
			$this->requires_remapping['post'][ $post_id ] = true;
		}

		if ( empty( $object_id ) ) {
			// Nothing needed here.
			return;
		}

		$this->logger->debug( sprintf( 'Menu item %d mapped to %d', $original_object_id, $object_id ) );
		update_post_meta( $post_id, '_menu_item_object_id', wp_slash( $object_id ) );
	}

	/**
	 * If fetching attachments is enabled then attempt to create a new attachment
	 *
	 * @param array  $post       Attachment post details from WXR.
	 * @param array  $meta       Attachment post meta details.
	 * @param string $remote_url URL to fetch attachment from.
	 *
	 * @return int|WP_Error Post ID on success, WP_Error otherwise
	 */
	protected function process_attachment( $post, $meta, $remote_url ) {
		// try to use _wp_attached file for upload folder placement to ensure the same location as the export site
		// e.g. location is 2003/05/image.jpg but the attachment post_date is 2010/09, see media_handle_upload()
		$post['upload_date'] = $post['post_date'];
		foreach ( $meta as $meta_item ) {
			if ( $meta_item['key'] !== '_wp_attached_file' ) {
				continue;
			}

			if ( preg_match( '%^[0-9]{4}/[0-9]{2}%', $meta_item['value'], $matches ) ) {
				$post['upload_date'] = $matches[0];
			}
			break;
		}

		// if the URL is absolute, but does not contain address, then upload it assuming base_site_url
		if ( preg_match( '|^/[\w\W]+$|', $remote_url ) ) {
			$remote_url = rtrim( $this->base_url, '/' ) . $remote_url;
		}

		$upload = $this->fetch_remote_file( $remote_url, $post );
		if ( is_wp_error( $upload ) ) {
			return $upload;
		}

		$info = wp_check_filetype( $upload['file'] );
		if ( ! $info ) {
			return new WP_Error( 'attachment_processing_error', __( 'Invalid file type', 'wordpress-importer' ) );
		}

		$post['post_mime_type'] = $info['type'];

		// WP really likes using the GUID for display. Allow updating it.
		// See https://core.trac.wordpress.org/ticket/33386
		if ( $this->options['update_attachment_guids'] ) {
			$post['guid'] = $upload['url'];
		}

		// as per wp-admin/includes/upload.php
		$post_id = wp_insert_attachment( $post, $upload['file'] );
		if ( is_wp_error( $post_id ) ) {
			return $post_id;
		}

		$attachment_metadata = wp_generate_attachment_metadata( $post_id, $upload['file'] );
		wp_update_attachment_metadata( $post_id, $attachment_metadata );

		// Map this image URL later if we need to
		$this->url_remap[ $remote_url ] = $upload['url'];

		// If we have a HTTPS URL, ensure the HTTP URL gets replaced too
		if ( substr( $remote_url, 0, 8 ) === 'https://' ) {
			$insecure_url = 'http' . substr( $remote_url, 5 );
			$this->url_remap[ $insecure_url ] = $upload['url'];
		}

		if ( $this->options['aggressive_url_search'] ) {
			// remap resized image URLs, works by stripping the extension and remapping the URL stub.
			/*if ( preg_match( '!^image/!', $info['type'] ) ) {
				$parts = pathinfo( $remote_url );
				$name = basename( $parts['basename'], ".{$parts['extension']}" ); // PATHINFO_FILENAME in PHP 5.2

				$parts_new = pathinfo( $upload['url'] );
				$name_new = basename( $parts_new['basename'], ".{$parts_new['extension']}" );

				$this->url_remap[$parts['dirname'] . '/' . $name] = $parts_new['dirname'] . '/' . $name_new;
			}*/
		}

		return $post_id;
	}

	/**
	 * Parse a meta node into meta data.
	 *
	 * @param \DOMNode $node Parent node of meta data (typically `wp:postmeta` or `wp:commentmeta`).
	 * @return array|null Meta data array on success, or null on error.
	 */
	protected function parse_meta_node( $node ) {
		foreach ( $node->childNodes as $child ) {
			// We only care about child elements
			if ( $child->nodeType !== XML_ELEMENT_NODE ) {
				continue;
			}

			switch ( $child->tagName ) {
				case 'wp:meta_key':
					$key = $child->textContent;
					break;

				case 'wp:meta_value':
					$value = $child->textContent;
					break;
			}
		}

		if ( empty( $key ) || ! isset( $value ) ) {
			return null;
		}

		return compact( 'key', 'value' );
	}

	/**
	 * Process and import post meta items.
	 *
	 * @param array $meta List of meta data arrays
	 * @param int $post_id Post to associate with
	 * @param array $post Post data
	 * @return int|WP_Error Number of meta items imported on success, error otherwise.
	 */
	protected function process_post_meta( $meta, $post_id, $post ) {
		if ( empty( $meta ) ) {
			return true;
		}

		foreach ( $meta as $meta_item ) {
			/**
			 * Pre-process post meta data.
			 *
			 * @param array $meta_item Meta data. (Return empty to skip.)
			 * @param int $post_id Post the meta is attached to.
			 */
			$meta_item = apply_filters( 'wxr_importer.pre_process.post_meta', $meta_item, $post_id );
			if ( empty( $meta_item ) ) {
				return false;
			}

			$key = apply_filters( 'import_post_meta_key', $meta_item['key'], $post_id, $post );
			$value = false;

			if ( '_edit_last' === $key ) {
				$value = intval( $meta_item['value'] );
				if ( ! isset( $this->mapping['user'][ $value ] ) ) {
					// Skip!
					continue;
				}

				$value = $this->mapping['user'][ $value ];
			}

			if ( $key ) {
				// export gets meta straight from the DB so could have a serialized string
				if ( ! $value ) {
					$value = maybe_unserialize( $meta_item['value'] );
				}

				// +EDIT: Bunyad WP version fix.
				$value_slashed = $value;
				if (function_exists('wp_slash_strings_only')) {
					$value_slashed = wp_slash_strings_only($value);
				}

				add_post_meta( $post_id, wp_slash( $key ), $value_slashed );
				do_action( 'import_post_meta', $post_id, $key, $value );

				// if the post has a featured image, take note of this in case of remap
				if ( '_thumbnail_id' === $key ) {
					$this->featured_images[ $post_id ] = (int) $value;
				}
			}
		}

		return true;
	}

	/**
	 * Parse a comment node into comment data.
	 *
	 * @param \DOMNode $node Parent node of comment data (typically `wp:comment`).
	 * @return array Comment data array.
	 */
	protected function parse_comment_node( $node ) {
		$data = array(
			'commentmeta' => array(),
		);

		foreach ( $node->childNodes as $child ) {
			// We only care about child elements
			if ( $child->nodeType !== XML_ELEMENT_NODE ) {
				continue;
			}

			switch ( $child->tagName ) {
				case 'wp:comment_id':
					$data['comment_id'] = $child->textContent;
					break;
				case 'wp:comment_author':
					$data['comment_author'] = $child->textContent;
					break;

				case 'wp:comment_author_email':
					$data['comment_author_email'] = $child->textContent;
					break;

				case 'wp:comment_author_IP':
					$data['comment_author_IP'] = $child->textContent;
					break;

				case 'wp:comment_author_url':
					$data['comment_author_url'] = $child->textContent;
					break;

				case 'wp:comment_user_id':
					$data['comment_user_id'] = $child->textContent;
					break;

				case 'wp:comment_date':
					$data['comment_date'] = $child->textContent;
					break;

				case 'wp:comment_date_gmt':
					$data['comment_date_gmt'] = $child->textContent;
					break;

				case 'wp:comment_content':
					$data['comment_content'] = $child->textContent;
					break;

				case 'wp:comment_approved':
					$data['comment_approved'] = $child->textContent;
					break;

				case 'wp:comment_type':
					$data['comment_type'] = $child->textContent;
					break;

				case 'wp:comment_parent':
					$data['comment_parent'] = $child->textContent;
					break;

				case 'wp:commentmeta':
					$meta_item = $this->parse_meta_node( $child );
					if ( ! empty( $meta_item ) ) {
						$data['commentmeta'][] = $meta_item;
					}
					break;
			}
		}

		return $data;
	}

	/**
	 * Process and import comment data.
	 *
	 * @param array   $comments    List of comment data arrays.
	 * @param int     $post_id     Post to associate with.
	 * @param array   $post        Post data.
	 * @param boolean $post_exists Boolean if the post already exists.
	 *
	 * @return int|WP_Error Number of comments imported on success, error otherwise.
	 */
	protected function process_comments( $comments, $post_id, $post, $post_exists = false ) {

		$comments = apply_filters( 'wp_import_post_comments', $comments, $post_id, $post );
		if ( empty( $comments ) ) {
			return 0;
		}

		$num_comments = 0;

		// Sort by ID to avoid excessive remapping later
		usort( $comments, array( $this, 'sort_comments_by_id' ) );

		foreach ( $comments as $key => $comment ) {
			/**
			 * Pre-process comment data
			 *
			 * @param array $comment Comment data. (Return empty to skip.)
			 * @param int $post_id Post the comment is attached to.
			 */
			$comment = apply_filters( 'wxr_importer.pre_process.comment', $comment, $post_id );
			if ( empty( $comment ) ) {
				return false;
			}

			$original_id = isset( $comment['comment_id'] )      ? (int) $comment['comment_id']      : 0;
			$parent_id   = isset( $comment['comment_parent'] )  ? (int) $comment['comment_parent']  : 0;
			$author_id   = isset( $comment['comment_user_id'] ) ? (int) $comment['comment_user_id'] : 0;

			// if this is a new post we can skip the comment_exists() check
			// TODO: Check comment_exists for performance
			if ( $post_exists ) {
				$existing = $this->comment_exists( $comment );
				if ( $existing ) {
					$this->mapping['comment'][ $original_id ] = $existing;
					continue;
				}
			}

			// Remove meta from the main array
			$meta = isset( $comment['commentmeta'] ) ? $comment['commentmeta'] : array();
			unset( $comment['commentmeta'] );

			// Map the parent comment, or mark it as one we need to fix
			$requires_remapping = false;
			if ( $parent_id ) {
				if ( isset( $this->mapping['comment'][ $parent_id ] ) ) {
					$comment['comment_parent'] = $this->mapping['comment'][ $parent_id ];
				} else {
					// Prepare for remapping later
					$meta[] = array( 'key' => '_wxr_import_parent', 'value' => $parent_id );
					$requires_remapping = true;

					// Wipe the parent for now
					$comment['comment_parent'] = 0;
				}
			}

			// Map the author, or mark it as one we need to fix
			if ( $author_id ) {
				if ( isset( $this->mapping['user'][ $author_id ] ) ) {
					$comment['user_id'] = $this->mapping['user'][ $author_id ];
				} else {
					// Prepare for remapping later
					$meta[] = array( 'key' => '_wxr_import_user', 'value' => $author_id );
					$requires_remapping = true;

					// Wipe the user for now
					$comment['user_id'] = 0;
				}
			}

			// Run standard core filters
			$comment['comment_post_ID'] = $post_id;
			$comment = wp_filter_comment( $comment );

			// wp_insert_comment expects slashed data
			$comment_id = wp_insert_comment( wp_slash( $comment ) );
			$this->mapping['comment'][ $original_id ] = $comment_id;
			if ( $requires_remapping ) {
				$this->requires_remapping['comment'][ $comment_id ] = true;
			}
			$this->mark_comment_exists( $comment, $comment_id );

			/**
			 * Comment has been imported.
			 *
			 * @param int $comment_id New comment ID
			 * @param array $comment Comment inserted (`comment_id` item refers to the original ID)
			 * @param int $post_id Post parent of the comment
			 * @param array $post Post data
			 */
			do_action( 'wp_import_insert_comment', $comment_id, $comment, $post_id, $post );

			// Process the meta items
			foreach ( $meta as $meta_item ) {
				$value = maybe_unserialize( $meta_item['value'] );
				add_comment_meta( $comment_id, wp_slash( $meta_item['key'] ), wp_slash( $value ) );
			}

			/**
			 * Post processing completed.
			 *
			 * @param int $post_id New post ID.
			 * @param array $comment Raw data imported for the comment.
			 * @param array $meta Raw meta data, already processed by {@see process_post_meta}.
			 * @param array $post_id Parent post ID.
			 */
			do_action( 'wxr_importer.processed.comment', $comment_id, $comment, $meta, $post_id );

			$num_comments++;
		}

		return $num_comments;
	}

	/**
	 * Parse the category node.
	 *
	 * @param \DOMNode $node The category node.
	 *
	 * @return array|null
	 */
	protected function parse_category_node( $node ) {
		$data = array(
			// Default taxonomy to "category", since this is a `<category>` tag
			'taxonomy' => 'category',
		);
		$meta = array();

		if ( $node->hasAttribute( 'domain' ) ) {
			$data['taxonomy'] = $node->getAttribute( 'domain' );
		}
		if ( $node->hasAttribute( 'nicename' ) ) {
			$data['slug'] = $node->getAttribute( 'nicename' );
		}

		$data['name'] = $node->textContent;

		if ( empty( $data['slug'] ) ) {
			return null;
		}

		// Just for extra compatibility
		if ( $data['taxonomy'] === 'tag' ) {
			$data['taxonomy'] = 'post_tag';
		}

		return $data;
	}

	/**
	 * Callback for `usort` to sort comments by ID
	 *
	 * @param array $a Comment data for the first comment
	 * @param array $b Comment data for the second comment
	 *
	 * @return int
	 */
	public static function sort_comments_by_id( $a, $b ) {
		if ( empty( $a['comment_id'] ) ) {
			return 1;
		}

		if ( empty( $b['comment_id'] ) ) {
			return -1;
		}

		return $a['comment_id'] - $b['comment_id'];
	}

	protected function parse_author_node( $node ) {
		$data = array();
		$meta = array();
		foreach ( $node->childNodes as $child ) {
			// We only care about child elements
			if ( $child->nodeType !== XML_ELEMENT_NODE ) {
				continue;
			}

			switch ( $child->tagName ) {
				case 'wp:author_login':
					$data['user_login'] = $child->textContent;
					break;

				case 'wp:author_id':
					$data['ID'] = $child->textContent;
					break;

				case 'wp:author_email':
					$data['user_email'] = $child->textContent;
					break;

				case 'wp:author_display_name':
					$data['display_name'] = $child->textContent;
					break;

				case 'wp:author_first_name':
					$data['first_name'] = $child->textContent;
					break;

				case 'wp:author_last_name':
					$data['last_name'] = $child->textContent;
					break;
			}
		}

		return compact( 'data', 'meta' );
	}

	/**
	 * Process author.
	 *
	 * @param array $data The author data from WXR file.
	 * @param array $meta The author meta data from WXR file.
	 */
	protected function process_author( $data, $meta ) {
		/**
		 * Pre-process user data.
		 *
		 * @param array $data User data. (Return empty to skip.)
		 * @param array $meta Meta data.
		 */
		$data = apply_filters( 'wxr_importer.pre_process.user', $data, $meta );
		if ( empty( $data ) ) {
			return false;
		}

		// Have we already handled this user?
		$original_id = isset( $data['ID'] ) ? $data['ID'] : 0;
		$original_slug = $data['user_login'];

		if ( isset( $this->mapping['user'][ $original_id ] ) ) {
			$existing = $this->mapping['user'][ $original_id ];

			// Note the slug mapping if we need to too
			if ( ! isset( $this->mapping['user_slug'][ $original_slug ] ) ) {
				$this->mapping['user_slug'][ $original_slug ] = $existing;
			}

			return false;
		}

		if ( isset( $this->mapping['user_slug'][ $original_slug ] ) ) {
			$existing = $this->mapping['user_slug'][ $original_slug ];

			// Ensure we note the mapping too
			$this->mapping['user'][ $original_id ] = $existing;

			return false;
		}

		// Allow overriding the user's slug
		$login = $original_slug;
		if ( isset( $this->user_slug_override[ $login ] ) ) {
			$login = $this->user_slug_override[ $login ];
		}

		$userdata = array(
			'user_login'   => sanitize_user( $login, true ),
			'user_pass'    => wp_generate_password(),
		);

		$allowed = array(
			'user_email'   => true,
			'display_name' => true,
			'first_name'   => true,
			'last_name'    => true,
		);
		foreach ( $data as $key => $value ) {
			if ( ! isset( $allowed[ $key ] ) ) {
				continue;
			}

			$userdata[ $key ] = $data[ $key ];
		}

		$user_id = wp_insert_user( wp_slash( $userdata ) );
		if ( is_wp_error( $user_id ) ) {
			$this->logger->error( sprintf(
				__( 'Failed to import user "%s"', 'wordpress-importer' ),
				$userdata['user_login']
			) );
			$this->logger->debug( $user_id->get_error_message() );

			/**
			 * User processing failed.
			 *
			 * @param WP_Error $user_id Error object.
			 * @param array $userdata Raw data imported for the user.
			 */
			do_action( 'wxr_importer.process_failed.user', $user_id, $userdata );
			return false;
		}

		if ( $original_id ) {
			$this->mapping['user'][ $original_id ] = $user_id;
		}
		$this->mapping['user_slug'][ $original_slug ] = $user_id;

		$this->logger->info( sprintf(
			__( 'Imported user "%s"', 'wordpress-importer' ),
			$userdata['user_login']
		) );
		$this->logger->debug( sprintf(
			__( 'User %d remapped to %d', 'wordpress-importer' ),
			$original_id,
			$user_id
		) );

		// TODO: Implement meta handling once WXR includes it
		/**
		 * User processing completed.
		 *
		 * @param int $user_id New user ID.
		 * @param array $userdata Raw data imported for the user.
		 */
		do_action( 'wxr_importer.processed.user', $user_id, $userdata );
	}


	/**
	 * Parse term node.
	 *
	 * @param \DOMNode $node The term node from WXR file.
	 * @param string   $type The type of the term node.
	 *
	 * @return array|null
	 */
	protected function parse_term_node( $node, $type = 'term' ) {
		$data = array();
		$meta = array();

		$tag_name = array(
			'id'          => 'wp:term_id',
			'taxonomy'    => 'wp:term_taxonomy',
			'slug'        => 'wp:term_slug',
			'parent'      => 'wp:term_parent',
			'name'        => 'wp:term_name',
			'description' => 'wp:term_description',
		);
		$taxonomy = null;

		// Special casing!
		switch ( $type ) {
			case 'category':
				$tag_name['slug']        = 'wp:category_nicename';
				$tag_name['parent']      = 'wp:category_parent';
				$tag_name['name']        = 'wp:cat_name';
				$tag_name['description'] = 'wp:category_description';
				$tag_name['taxonomy']    = null;

				$data['taxonomy'] = 'category';
				break;

			case 'tag':
				$tag_name['slug']        = 'wp:tag_slug';
				$tag_name['parent']      = null;
				$tag_name['name']        = 'wp:tag_name';
				$tag_name['description'] = 'wp:tag_description';
				$tag_name['taxonomy']    = null;

				$data['taxonomy'] = 'post_tag';
				break;
		}

		foreach ( $node->childNodes as $child ) {
			// We only care about child elements
			if ( $child->nodeType !== XML_ELEMENT_NODE ) {
				continue;
			}

			$key = array_search( $child->tagName, $tag_name );
			if ( $key ) {
				$data[ $key ] = $child->textContent;
			} else if ( $child->tagName == 'wp:termmeta' ) {
				$meta_item = $this->parse_meta_node( $child );
				if ( ! empty( $meta_item ) ) {
					$meta[] = $meta_item;
				}
			}
		}

		if ( empty( $data['taxonomy'] ) ) {
			return null;
		}

		// Compatibility with WXR 1.0
		if ( $data['taxonomy'] === 'tag' ) {
			$data['taxonomy'] = 'post_tag';
		}

		return compact( 'data', 'meta' );
	}

	/**
	 * Process term.
	 *
	 * @param array $data The term data from WXR file.
	 * @param array $meta The term meta data from WXR file.
	 */
	protected function process_term( $data, $meta ) {
		/**
		 * Pre-process term data.
		 *
		 * @param array $data Term data. (Return empty to skip.)
		 * @param array $meta Meta data.
		 */
		$data = apply_filters( 'wxr_importer.pre_process.term', $data, $meta );
		if ( empty( $data ) ) {
			return false;
		}

		$original_id = isset( $data['id'] ) ? (int) $data['id'] : 0;

		/* FIX for OCDI!
		 * As of WP 4.5, export.php returns the SLUG for the term's parent,
		 * rather than an integer ID (this differs from a post_parent)
		 * wp_insert_term and wp_update_term use the key: 'parent' and an integer value 'id'
		 */
		$term_slug   = isset( $data['slug'] ) ? $data['slug'] : '';
 		$parent_slug = isset( $data['parent'] ) ? $data['parent'] : '';

		$mapping_key = sha1( $data['taxonomy'] . ':' . $data['slug'] );
		$existing = $this->term_exists( $data );
		if ( $existing ) {
			$this->mapping['term'][ $mapping_key ] = $existing;
			$this->mapping['term_id'][ $original_id ] = $existing;
			$this->mapping['term_slug'][ $term_slug ] = $existing;
			return false;
		}

		// WP really likes to repeat itself in export files
		if ( isset( $this->mapping['term'][ $mapping_key ] ) ) {
			return false;
		}

		$termdata = array();
		$allowed = array(
			'slug' => true,
			'description' => true,
			'parent' => true, // The parent_id may have already been set, so pass this back to the newly inserted term.
		);

		// Map the parent comment, or mark it as one we need to fix
		$requires_remapping = false;
		if ( $parent_slug ) {
			if ( isset( $this->mapping['term_slug'][ $parent_slug ] ) ) {
				$data['parent'] = $this->mapping['term_slug'][ $parent_slug ];
			} else {
				// Prepare for remapping later
				$meta[] = array( 'key' => '_wxr_import_parent', 'value' => $parent_slug );
				$requires_remapping = true;

				// Wipe the parent id for now
				$data['parent'] = 0;
			}
		}

		foreach ( $data as $key => $value ) {
			if ( ! isset( $allowed[ $key ] ) ) {
				continue;
			}

			$termdata[ $key ] = $data[ $key ];
		}

		$result = wp_insert_term( $data['name'], $data['taxonomy'], $termdata );
		if ( is_wp_error( $result ) ) {
			$this->logger->warning( sprintf(
				__( 'Failed to import %s %s', 'wordpress-importer' ),
				$data['taxonomy'],
				$data['name']
			) );
			$this->logger->debug( $result->get_error_message() );
			do_action( 'wp_import_insert_term_failed', $result, $data );

			/**
			 * Term processing failed.
			 *
			 * @param WP_Error $result Error object.
			 * @param array $data Raw data imported for the term.
			 * @param array $meta Meta data supplied for the term.
			 */
			do_action( 'wxr_importer.process_failed.term', $result, $data, $meta );
			return false;
		}

		$term_id = $result['term_id'];

		// Now prepare to map this new term.
		$this->mapping['term'][ $mapping_key ] = $term_id;
		$this->mapping['term_id'][ $original_id ] = $term_id;
		$this->mapping['term_slug'][ $term_slug ] = $term_id;

		/*
		 * Fix for OCDI!
		 * The parent will be updated later in post_process_terms
		 * we will need both the term_id AND the term_taxonomy to retrieve existing
		 * term attributes. Those attributes will be returned with the corrected parent,
		 * using wp_update_term.
		 * Pass both the term_id along with the term_taxonomy as key=>value
		 * in the requires_remapping['term'] array.
		 */
		if ( $requires_remapping ) {
			$this->requires_remapping['term'][ $term_id ] = $data['taxonomy'];
		}

		$this->logger->info( sprintf(
			__( 'Imported "%s" (%s)', 'wordpress-importer' ),
			$data['name'],
			$data['taxonomy']
		) );
		$this->logger->debug( sprintf(
			__( 'Term %d remapped to %d', 'wordpress-importer' ),
			$original_id,
			$term_id
		) );

		// Actuall process of the term meta data.
		$this->process_term_meta( $meta, $term_id, $data );

		do_action( 'wp_import_insert_term', $term_id, $data );

		/**
		 * Term processing completed.
		 *
		 * @param int $term_id New term ID.
		 * @param array $data Raw data imported for the term.
		 */
		do_action( 'wxr_importer.processed.term', $term_id, $data );
	}

	/**
	 * Process and import term meta items.
	 *
	 * @param array $meta    List of meta data arrays.
	 * @param int   $term_id Term ID to associate with.
	 * @param array $term    Term data.
	 *
	 * @return int|bool Number of meta items imported on success, false otherwise.
	 */
	protected function process_term_meta( $meta, $term_id, $term ) {
		if ( empty( $meta ) ) {
			return true;
		}

		foreach ( $meta as $meta_item ) {
			/**
			 * Pre-process term meta data.
			 *
			 * @param array $meta_item Meta data. (Return empty to skip.)
			 * @param int $term_id Term the meta is attached to.
			 */
			$meta_item = apply_filters( 'wxr_importer.pre_process.term_meta', $meta_item, $term_id );

			if ( empty( $meta_item ) ) {
				continue;
			}

			$key = apply_filters( 'import_term_meta_key', $meta_item['key'], $term_id, $term );
			$value = false;

			if ( $key ) {
				// Export gets meta straight from the DB so could have a serialized string.
				if ( ! $value ) {
					$value = maybe_unserialize( $meta_item['value'] );
				}

				$result = add_term_meta( $term_id, $key, $value );

				if ( is_wp_error( $result ) ) {
					$this->logger->warning( sprintf(
						__( 'Failed to add metakey: %s, metavalue: %s to term_id: %d', 'wordpress-importer' ),
						$key,
						$value,
						$term_id
					) );
					do_action( 'wxr_importer.process_failed.termmeta', $result, $meta_item, $term_id, $term );
				}
				else {
					$this->logger->debug( sprintf(
						__( 'Meta for term_id %d : %s => %s ; successfully added!', 'wordpress-importer' ),
						$term_id,
						$key,
						$value
					) );
				}

				do_action( 'import_term_meta', $term_id, $key, $value );
			}
		}

		return true;
	}

	/**
	 * Attempt to download a remote file attachment.
	 *
	 * @param string $url  URL of item to fetch.
	 * @param array  $post Attachment details.
	 *
	 * @return array|WP_Error Local file location details on success, WP_Error otherwise
	 */
	protected function fetch_remote_file( $url, $post ) {
		// extract the file name and extension from the url
		$file_name = basename( $url );

		// get placeholder file in the upload dir with a unique, sanitized filename
		$upload = wp_upload_bits( $file_name, 0, '', $post['upload_date'] );
		if ( $upload['error'] ) {
			return new WP_Error( 'upload_dir_error', $upload['error'] );
		}

		// fetch the remote url and write it to the placeholder file
		$response = wp_remote_get( $url, array(
			'stream' => true,
			'filename' => $upload['file'],
		) );

		// request failed
		if ( is_wp_error( $response ) ) {
			unlink( $upload['file'] );
			return $response;
		}

		$code = (int) wp_remote_retrieve_response_code( $response );

		// make sure the fetch was successful
		if ( $code !== 200 ) {
			unlink( $upload['file'] );
			return new WP_Error(
				'import_file_error',
				sprintf(
					__( 'Remote server returned %1$d %2$s for %3$s', 'wordpress-importer' ),
					$code,
					get_status_header_desc( $code ),
					$url
				)
			);
		}

		$filesize = filesize( $upload['file'] );
		$headers = wp_remote_retrieve_headers( $response );

		// OCDI fix!
		// Smaller images with server compression do not pass this rule.
		// More info here: https://github.com/proteusthemes/WordPress-Importer/pull/2
		//
		// if ( isset( $headers['content-length'] ) && $filesize !== (int) $headers['content-length'] ) {
		// 	unlink( $upload['file'] );
		// 	return new WP_Error( 'import_file_error', __( 'Remote file is incorrect size', 'wordpress-importer' ) );
		// }

		if ( 0 === $filesize ) {
			unlink( $upload['file'] );
			return new WP_Error( 'import_file_error', __( 'Zero size file downloaded', 'wordpress-importer' ) );
		}

		$max_size = (int) $this->max_attachment_size();
		if ( ! empty( $max_size ) && $filesize > $max_size ) {
			unlink( $upload['file'] );
			$message = sprintf( __( 'Remote file is too large, limit is %s', 'wordpress-importer' ), size_format( $max_size ) );
			return new WP_Error( 'import_file_error', $message );
		}

		return $upload;
	}

	protected function post_process() {
		// Time to tackle any left-over bits
		if ( ! empty( $this->requires_remapping['post'] ) ) {
			$this->post_process_posts( $this->requires_remapping['post'] );
		}
		if ( ! empty( $this->requires_remapping['comment'] ) ) {
			$this->post_process_comments( $this->requires_remapping['comment'] );
		}
		if ( ! empty( $this->requires_remapping['term'] ) ) {
			$this->post_process_terms( $this->requires_remapping['term'] );
		}
	}

	protected function post_process_posts( $todo ) {
		foreach ( $todo as $post_id => $_ ) {
			$this->logger->debug( sprintf(
				// Note: title intentionally not used to skip extra processing
				// for when debug logging is off
				__( 'Running post-processing for post %d', 'wordpress-importer' ),
				$post_id
			) );

			$data = array();

			$parent_id = get_post_meta( $post_id, '_wxr_import_parent', true );
			if ( ! empty( $parent_id ) ) {
				// Have we imported the parent now?
				if ( isset( $this->mapping['post'][ $parent_id ] ) ) {
					$data['post_parent'] = $this->mapping['post'][ $parent_id ];
				} else {
					$this->logger->warning( sprintf(
						__( 'Could not find the post parent for "%s" (post #%d)', 'wordpress-importer' ),
						get_the_title( $post_id ),
						$post_id
					) );
					$this->logger->debug( sprintf(
						__( 'Post %d was imported with parent %d, but could not be found', 'wordpress-importer' ),
						$post_id,
						$parent_id
					) );
				}
			}

			$author_slug = get_post_meta( $post_id, '_wxr_import_user_slug', true );
			if ( ! empty( $author_slug ) ) {
				// Have we imported the user now?
				if ( isset( $this->mapping['user_slug'][ $author_slug ] ) ) {
					$data['post_author'] = $this->mapping['user_slug'][ $author_slug ];
				} else {
					$this->logger->warning( sprintf(
						__( 'Could not find the author for "%s" (post #%d)', 'wordpress-importer' ),
						get_the_title( $post_id ),
						$post_id
					) );
					$this->logger->debug( sprintf(
						__( 'Post %d was imported with author "%s", but could not be found', 'wordpress-importer' ),
						$post_id,
						$author_slug
					) );
				}
			}

			$has_attachments = get_post_meta( $post_id, '_wxr_import_has_attachment_refs', true );
			if ( ! empty( $has_attachments ) ) {
				$post = get_post( $post_id );
				$content = $post->post_content;

				// Replace all the URLs we've got
				$new_content = str_replace( array_keys( $this->url_remap ), $this->url_remap, $content );
				if ( $new_content !== $content ) {
					$data['post_content'] = $new_content;
				}
			}

			if ( get_post_type( $post_id ) === 'nav_menu_item' ) {
				$this->post_process_menu_item( $post_id );
			}

			// Do we have updates to make?
			if ( empty( $data ) ) {
				$this->logger->debug( sprintf(
					__( 'Post %d was marked for post-processing, but none was required.', 'wordpress-importer' ),
					$post_id
				) );
				continue;
			}

			// Run the update
			$data['ID'] = $post_id;
			$result = wp_update_post( $data, true );
			if ( is_wp_error( $result ) ) {
				$this->logger->warning( sprintf(
					__( 'Could not update "%s" (post #%d) with mapped data', 'wordpress-importer' ),
					get_the_title( $post_id ),
					$post_id
				) );
				$this->logger->debug( $result->get_error_message() );
				continue;
			}

			// Clear out our temporary meta keys
			delete_post_meta( $post_id, '_wxr_import_parent' );
			delete_post_meta( $post_id, '_wxr_import_user_slug' );
			delete_post_meta( $post_id, '_wxr_import_has_attachment_refs' );
		}
	}

	protected function post_process_menu_item( $post_id ) {
		$menu_object_id = get_post_meta( $post_id, '_wxr_import_menu_item', true );
		if ( empty( $menu_object_id ) ) {
			// No processing needed!
			return;
		}

		$menu_item_type = get_post_meta( $post_id, '_menu_item_type', true );
		switch ( $menu_item_type ) {
			case 'taxonomy':
				if ( isset( $this->mapping['term_id'][ $menu_object_id ] ) ) {
					$menu_object = $this->mapping['term_id'][ $menu_object_id ];
				}
				break;

			case 'post_type':
				if ( isset( $this->mapping['post'][ $menu_object_id ] ) ) {
					$menu_object = $this->mapping['post'][ $menu_object_id ];
				}
				break;

			default:
				// Cannot handle this.
				return;
		}

		if ( ! empty( $menu_object ) ) {
			update_post_meta( $post_id, '_menu_item_object_id', wp_slash( $menu_object ) );
		} else {
			$this->logger->warning( sprintf(
				__( 'Could not find the menu object for "%s" (post #%d)', 'wordpress-importer' ),
				get_the_title( $post_id ),
				$post_id
			) );
			$this->logger->debug( sprintf(
				__( 'Post %d was imported with object "%d" of type "%s", but could not be found', 'wordpress-importer' ),
				$post_id,
				$menu_object_id,
				$menu_item_type
			) );
		}

		delete_post_meta( $post_id, '_wxr_import_menu_item' );
	}


	protected function post_process_comments( $todo ) {
		foreach ( $todo as $comment_id => $_ ) {
			$data = array();

			$parent_id = get_comment_meta( $comment_id, '_wxr_import_parent', true );
			if ( ! empty( $parent_id ) ) {
				// Have we imported the parent now?
				if ( isset( $this->mapping['comment'][ $parent_id ] ) ) {
					$data['comment_parent'] = $this->mapping['comment'][ $parent_id ];
				} else {
					$this->logger->warning( sprintf(
						__( 'Could not find the comment parent for comment #%d', 'wordpress-importer' ),
						$comment_id
					) );
					$this->logger->debug( sprintf(
						__( 'Comment %d was imported with parent %d, but could not be found', 'wordpress-importer' ),
						$comment_id,
						$parent_id
					) );
				}
			}

			$author_id = get_comment_meta( $comment_id, '_wxr_import_user', true );
			if ( ! empty( $author_id ) ) {
				// Have we imported the user now?
				if ( isset( $this->mapping['user'][ $author_id ] ) ) {
					$data['user_id'] = $this->mapping['user'][ $author_id ];
				} else {
					$this->logger->warning( sprintf(
						__( 'Could not find the author for comment #%d', 'wordpress-importer' ),
						$comment_id
					) );
					$this->logger->debug( sprintf(
						__( 'Comment %d was imported with author %d, but could not be found', 'wordpress-importer' ),
						$comment_id,
						$author_id
					) );
				}
			}

			// Do we have updates to make?
			if ( empty( $data ) ) {
				continue;
			}

			// Run the update
			$data['comment_ID'] = $comment_id;
			$result = wp_update_comment( wp_slash( $data ) );
			if ( empty( $result ) ) {
				$this->logger->warning( sprintf(
					__( 'Could not update comment #%d with mapped data', 'wordpress-importer' ),
					$comment_id
				) );
				continue;
			}

			// Clear out our temporary meta keys
			delete_comment_meta( $comment_id, '_wxr_import_parent' );
			delete_comment_meta( $comment_id, '_wxr_import_user' );
		}
	}


	/**
	 * There is no explicit 'top' or 'root' for a hierarchy of WordPress terms
	 * Terms without a parent, or parent=0 are either unconnected (orphans)
	 * or top-level siblings without an explicit root parent
	 * An unconnected term (orphan) should have a null parent_slug
	 * Top-level siblings without an explicit root parent, shall be identified
	 * with the parent_slug: top
	 * [we'll map parent_slug: top into parent 0]
	 *
	 * @param array $terms_to_be_remapped The terms to be remapped.
	 */
	protected function post_process_terms( $terms_to_be_remapped ) {
		$this->mapping['term_slug']['top'] = 0;
		// The term_id and term_taxonomy are passed-in with $this->requires_remapping['term'].
		foreach ( $terms_to_be_remapped as $termid => $term_taxonomy ) {
			// Basic check.
			if( empty( $termid ) || ! is_numeric( $termid ) ) {
				$this->logger->warning( sprintf(
					__( 'Faulty term_id provided in terms-to-be-remapped array %s', 'wordpress-importer' ),
					$termid
					) );
				continue;
			}
			// This cast to integer may be unnecessary.
			$term_id = (int) $termid;

			if( empty( $term_taxonomy ) ){
				$this->logger->warning( sprintf(
					__( 'No taxonomy provided in terms-to-be-remapped array for term #%d', 'wordpress-importer' ),
					$term_id
					) );
				continue;
			}

			$parent_slug = get_term_meta( $term_id, '_wxr_import_parent', true );

			if ( empty( $parent_slug ) ) {
				$this->logger->warning( sprintf(
					__( 'No parent_slug identified in remapping-array for term: %d', 'wordpress-importer' ),
					$term_id
					) );
				continue;
			}

			if ( ! isset( $this->mapping['term_slug'][ $parent_slug ] ) || ! is_numeric( $this->mapping['term_slug'][ $parent_slug ] ) ) {
				$this->logger->warning( sprintf(
					__( 'The term(%d)"s parent_slug (%s) is not found in the remapping-array.', 'wordpress-importer' ),
					$term_id,
					$parent_slug
					) );
				continue;
			}

			$mapped_parent = (int) $this->mapping['term_slug'][ $parent_slug ];

			$termattributes = get_term_by( 'id', $term_id, $term_taxonomy, ARRAY_A );
			// Note: the default OBJECT return results in a reserved-word clash with 'parent' [$termattributes->parent], so instead return an associative array.

			if ( empty( $termattributes ) ) {
				$this->logger->warning( sprintf(
					__( 'No data returned by get_term_by for term_id #%d', 'wordpress-importer' ),
					$term_id
					) );
				continue;
			}
			// Check if the correct parent id is already correctly mapped.
			if ( isset( $termattributes['parent'] ) &&  $termattributes['parent'] == $mapped_parent ) {
				// Clear out our temporary meta key.
				delete_term_meta( $term_id, '_wxr_import_parent' );
				continue;
			}

			// Otherwise set the mapped parent and update the term.
			$termattributes['parent'] = $mapped_parent;

			$result = wp_update_term( $term_id, $termattributes['taxonomy'], $termattributes );

			if ( is_wp_error( $result ) ) {
			$this->logger->warning( sprintf(
					__( 'Could not update "%s" (term #%d) with mapped data', 'wordpress-importer' ),
					$termattributes['name'],
					$term_id
				) );
				$this->logger->debug( $result->get_error_message() );
				continue;
			}
			// Clear out our temporary meta key.
			delete_term_meta( $term_id, '_wxr_import_parent' );
			$this->logger->debug( sprintf(
				__( 'Term %d was successfully updated with parent %d', 'wordpress-importer' ),
				$term_id,
				$mapped_parent
			) );
		}
	}


	/**
	 * Use stored mapping information to update old attachment URLs
	 */
	protected function replace_attachment_urls_in_content() {
		global $wpdb;
		// make sure we do the longest urls first, in case one is a substring of another
		uksort( $this->url_remap, array( $this, 'cmpr_strlen' ) );

		foreach ( $this->url_remap as $from_url => $to_url ) {
			// remap urls in post_content
			$query = $wpdb->prepare( "UPDATE {$wpdb->posts} SET post_content = REPLACE(post_content, %s, %s)", $from_url, $to_url );
			$wpdb->query( $query );

			// remap enclosure urls
			$query = $wpdb->prepare( "UPDATE {$wpdb->postmeta} SET meta_value = REPLACE(meta_value, %s, %s) WHERE meta_key='enclosure'", $from_url, $to_url );
			$wpdb->query( $query );
		}
	}

	/**
	 * Update _thumbnail_id meta to new, imported attachment IDs
	 */
	function remap_featured_images() {
		if ( empty( $this->featured_images ) ) {
			return;
		}

		$this->logger->info( esc_html__( 'Starting remapping of featured images', 'wordpress-importer' ) );

		// Cycle through posts that have a featured image.
		foreach ( $this->featured_images as $post_id => $value ) {
			if ( isset( $this->mapping['post'][ $value ] ) ) {
				$new_id = $this->mapping['post'][ $value ];

				// Only update if there's a difference.
				if ( $new_id !== $value ) {
					$this->logger->info( sprintf( esc_html__( 'Remapping featured image ID %d to new ID %d for post ID %d', 'wordpress-importer' ), $value, $new_id, $post_id ) );

					update_post_meta( $post_id, '_thumbnail_id', $new_id );
				}
			}
		}
	}

	/**
	 * Decide if the given meta key maps to information we will want to import
	 *
	 * @param string $key The meta key to check
	 * @return string|bool The key if we do want to import, false if not
	 */
	public function is_valid_meta_key( $key ) {
		// skip attachment metadata since we'll regenerate it from scratch
		// skip _edit_lock as not relevant for import
		if ( in_array( $key, array( '_wp_attached_file', '_wp_attachment_metadata', '_edit_lock' ) ) ) {
			return false;
		}

		return $key;
	}

	/**
	 * Decide what the maximum file size for downloaded attachments is.
	 * Default is 0 (unlimited), can be filtered via import_attachment_size_limit
	 *
	 * @return int Maximum attachment file size to import
	 */
	protected function max_attachment_size() {
		return apply_filters( 'import_attachment_size_limit', 0 );
	}

	/**
	 * Added to http_request_timeout filter to force timeout at 60 seconds during import
	 *
	 * @param int $val Time in seconds.
	 * @access protected
	 * @return int 60
	 */
	function bump_request_timeout($val) {
		return 60;
	}

	// return the difference in length between two strings
	function cmpr_strlen( $a, $b ) {
		return strlen( $b ) - strlen( $a );
	}

	/**
	 * Prefill existing post data.
	 *
	 * This preloads all GUIDs into memory, allowing us to avoid hitting the
	 * database when we need to check for existence. With larger imports, this
	 * becomes prohibitively slow to perform SELECT queries on each.
	 *
	 * By preloading all this data into memory, it's a constant-time lookup in
	 * PHP instead. However, this does use a lot more memory, so for sites doing
	 * small imports onto a large site, it may be a better tradeoff to use
	 * on-the-fly checking instead.
	 */
	protected function prefill_existing_posts() {
		global $wpdb;
		$posts = $wpdb->get_results( "SELECT ID, guid FROM {$wpdb->posts}" );

		foreach ( $posts as $item ) {
			$this->exists['post'][ $item->guid ] = $item->ID;
		}
	}

	/**
	 * Does the post exist?
	 *
	 * @param array $data Post data to check against.
	 * @return int|bool Existing post ID if it exists, false otherwise.
	 */
	protected function post_exists( $data ) {
		// Constant-time lookup if we prefilled
		$exists_key = $data['guid'];

		if ( $this->options['prefill_existing_posts'] ) {
			// OCDI: fix for custom post types. The guids in the prefilled section are escaped, so these ones should be as well.
			$exists_key = htmlentities( $exists_key );
			return isset( $this->exists['post'][ $exists_key ] ) ? $this->exists['post'][ $exists_key ] : false;
		}

		// No prefilling, but might have already handled it
		if ( isset( $this->exists['post'][ $exists_key ] ) ) {
			return $this->exists['post'][ $exists_key ];
		}

		// Still nothing, try post_exists, and cache it
		$exists = post_exists( $data['post_title'], $data['post_content'], $data['post_date'] );
		$this->exists['post'][ $exists_key ] = $exists;

		return $exists;
	}

	/**
	 * Mark the post as existing.
	 *
	 * @param array $data Post data to mark as existing.
	 * @param int $post_id Post ID.
	 */
	protected function mark_post_exists( $data, $post_id ) {
		$exists_key = $data['guid'];
		$this->exists['post'][ $exists_key ] = $post_id;
	}

	/**
	 * Prefill existing comment data.
	 *
	 * @see self::prefill_existing_posts() for justification of why this exists.
	 */
	protected function prefill_existing_comments() {
		global $wpdb;
		$posts = $wpdb->get_results( "SELECT comment_ID, comment_author, comment_date FROM {$wpdb->comments}" );

		foreach ( $posts as $item ) {
			$exists_key = sha1( $item->comment_author . ':' . $item->comment_date );
			$this->exists['comment'][ $exists_key ] = $item->comment_ID;
		}
	}

	/**
	 * Does the comment exist?
	 *
	 * @param array $data Comment data to check against.
	 * @return int|bool Existing comment ID if it exists, false otherwise.
	 */
	protected function comment_exists( $data ) {
		$exists_key = sha1( $data['comment_author'] . ':' . $data['comment_date'] );

		// Constant-time lookup if we prefilled
		if ( $this->options['prefill_existing_comments'] ) {
			return isset( $this->exists['comment'][ $exists_key ] ) ? $this->exists['comment'][ $exists_key ] : false;
		}

		// No prefilling, but might have already handled it
		if ( isset( $this->exists['comment'][ $exists_key ] ) ) {
			return $this->exists['comment'][ $exists_key ];
		}

		// Still nothing, try comment_exists, and cache it
		$exists = comment_exists( $data['comment_author'], $data['comment_date'] );
		$this->exists['comment'][ $exists_key ] = $exists;

		return $exists;
	}

	/**
	 * Mark the comment as existing.
	 *
	 * @param array $data Comment data to mark as existing.
	 * @param int $comment_id Comment ID.
	 */
	protected function mark_comment_exists( $data, $comment_id ) {
		$exists_key = sha1( $data['comment_author'] . ':' . $data['comment_date'] );
		$this->exists['comment'][ $exists_key ] = $comment_id;
	}

	/**
	 * Prefill existing term data.
	 *
	 * @see self::prefill_existing_posts() for justification of why this exists.
	 */
	protected function prefill_existing_terms() {
		global $wpdb;
		$query = "SELECT t.term_id, tt.taxonomy, t.slug FROM {$wpdb->terms} AS t";
		$query .= " JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id";
		$terms = $wpdb->get_results( $query );

		foreach ( $terms as $item ) {
			$exists_key = sha1( $item->taxonomy . ':' . $item->slug );
			$this->exists['term'][ $exists_key ] = $item->term_id;
		}
	}

	/**
	 * Does the term exist?
	 *
	 * @param array $data Term data to check against.
	 * @return int|bool Existing term ID if it exists, false otherwise.
	 */
	protected function term_exists( $data ) {
		$exists_key = sha1( $data['taxonomy'] . ':' . $data['slug'] );

		// Constant-time lookup if we prefilled
		if ( $this->options['prefill_existing_terms'] ) {
			return isset( $this->exists['term'][ $exists_key ] ) ? $this->exists['term'][ $exists_key ] : false;
		}

		// No prefilling, but might have already handled it
		if ( isset( $this->exists['term'][ $exists_key ] ) ) {
			return $this->exists['term'][ $exists_key ];
		}

		// Still nothing, try comment_exists, and cache it
		$exists = term_exists( $data['slug'], $data['taxonomy'] );
		if ( is_array( $exists ) ) {
			$exists = $exists['term_id'];
		}

		$this->exists['term'][ $exists_key ] = $exists;

		return $exists;
	}

	/**
	 * Mark the term as existing.
	 *
	 * @param array $data Term data to mark as existing.
	 * @param int $term_id Term ID.
	 */
	protected function mark_term_exists( $data, $term_id ) {
		$exists_key = sha1( $data['taxonomy'] . ':' . $data['slug'] );
		$this->exists['term'][ $exists_key ] = $term_id;
	}
}
PK/3Y�p��**Tbunyad-demo-import/vendor/awesomemotive/wp-content-importer-v2/src/WXRImportInfo.php<?php

namespace AwesomeMotive\WPContentImporter2;

class WXRImportInfo {
	public $home;
	public $siteurl;
	public $title;
	public $users = array();
	public $post_count = 0;
	public $media_count = 0;
	public $comment_count = 0;
	public $term_count = 0;
	public $generator = '';
	public $version;
}
PK/3Y��b��8bunyad-demo-import/vendor/composer/autoload_classmap.php<?php

// autoload_classmap.php @generated by Composer

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
);
PK/3Yt�!ו�:bunyad-demo-import/vendor/composer/autoload_namespaces.php<?php

// autoload_namespaces.php @generated by Composer

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
);
PK/3YS�=''4bunyad-demo-import/vendor/composer/autoload_psr4.php<?php

// autoload_psr4.php @generated by Composer

$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);

return array(
    'OCDI\\' => array($baseDir . '/inc'),
    'AwesomeMotive\\WPContentImporter2\\' => array($vendorDir . '/awesomemotive/wp-content-importer-v2/src'),
);
PK/3Y�?BE  4bunyad-demo-import/vendor/composer/autoload_real.php<?php

// autoload_real.php @generated by Composer

class ComposerAutoloaderInitef3a658a88d521398d72929dc54fa111
{
    private static $loader;

    public static function loadClassLoader($class)
    {
        if ('Composer\Autoload\ClassLoader' === $class) {
            require __DIR__ . '/ClassLoader.php';
        }
    }

    /**
     * @return \Composer\Autoload\ClassLoader
     */
    public static function getLoader()
    {
        if (null !== self::$loader) {
            return self::$loader;
        }

        spl_autoload_register(array('ComposerAutoloaderInitef3a658a88d521398d72929dc54fa111', 'loadClassLoader'), true, true);
        self::$loader = $loader = new \Composer\Autoload\ClassLoader();
        spl_autoload_unregister(array('ComposerAutoloaderInitef3a658a88d521398d72929dc54fa111', 'loadClassLoader'));

        $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
        if ($useStaticLoader) {
            require_once __DIR__ . '/autoload_static.php';

            call_user_func(\Composer\Autoload\ComposerStaticInitef3a658a88d521398d72929dc54fa111::getInitializer($loader));
        } else {
            $map = require __DIR__ . '/autoload_namespaces.php';
            foreach ($map as $namespace => $path) {
                $loader->set($namespace, $path);
            }

            $map = require __DIR__ . '/autoload_psr4.php';
            foreach ($map as $namespace => $path) {
                $loader->setPsr4($namespace, $path);
            }

            $classMap = require __DIR__ . '/autoload_classmap.php';
            if ($classMap) {
                $loader->addClassMap($classMap);
            }
        }

        $loader->register(true);

        return $loader;
    }
}
PK/3Y�"�))6bunyad-demo-import/vendor/composer/autoload_static.php<?php

// autoload_static.php @generated by Composer

namespace Composer\Autoload;

class ComposerStaticInitef3a658a88d521398d72929dc54fa111
{
    public static $prefixLengthsPsr4 = array (
        'O' => 
        array (
            'OCDI\\' => 5,
        ),
        'A' => 
        array (
            'AwesomeMotive\\WPContentImporter2\\' => 33,
        ),
    );

    public static $prefixDirsPsr4 = array (
        'OCDI\\' => 
        array (
            0 => __DIR__ . '/../..' . '/inc',
        ),
        'AwesomeMotive\\WPContentImporter2\\' => 
        array (
            0 => __DIR__ . '/..' . '/awesomemotive/wp-content-importer-v2/src',
        ),
    );

    public static function getInitializer(ClassLoader $loader)
    {
        return \Closure::bind(function () use ($loader) {
            $loader->prefixLengthsPsr4 = ComposerStaticInitef3a658a88d521398d72929dc54fa111::$prefixLengthsPsr4;
            $loader->prefixDirsPsr4 = ComposerStaticInitef3a658a88d521398d72929dc54fa111::$prefixDirsPsr4;

        }, null, ClassLoader::class);
    }
}
PK/3Y�z���4�42bunyad-demo-import/vendor/composer/ClassLoader.php<?php

/*
 * This file is part of Composer.
 *
 * (c) Nils Adermann <[email protected]>
 *     Jordi Boggiano <[email protected]>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Composer\Autoload;

/**
 * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
 *
 *     $loader = new \Composer\Autoload\ClassLoader();
 *
 *     // register classes with namespaces
 *     $loader->add('Symfony\Component', __DIR__.'/component');
 *     $loader->add('Symfony',           __DIR__.'/framework');
 *
 *     // activate the autoloader
 *     $loader->register();
 *
 *     // to enable searching the include path (eg. for PEAR packages)
 *     $loader->setUseIncludePath(true);
 *
 * In this example, if you try to use a class in the Symfony\Component
 * namespace or one of its children (Symfony\Component\Console for instance),
 * the autoloader will first look for the class under the component/
 * directory, and it will then fallback to the framework/ directory if not
 * found before giving up.
 *
 * This class is loosely based on the Symfony UniversalClassLoader.
 *
 * @author Fabien Potencier <[email protected]>
 * @author Jordi Boggiano <[email protected]>
 * @see    http://www.php-fig.org/psr/psr-0/
 * @see    http://www.php-fig.org/psr/psr-4/
 */
class ClassLoader
{
    // PSR-4
    private $prefixLengthsPsr4 = array();
    private $prefixDirsPsr4 = array();
    private $fallbackDirsPsr4 = array();

    // PSR-0
    private $prefixesPsr0 = array();
    private $fallbackDirsPsr0 = array();

    private $useIncludePath = false;
    private $classMap = array();
    private $classMapAuthoritative = false;
    private $missingClasses = array();
    private $apcuPrefix;

    public function getPrefixes()
    {
        if (!empty($this->prefixesPsr0)) {
            return call_user_func_array('array_merge', $this->prefixesPsr0);
        }

        return array();
    }

    public function getPrefixesPsr4()
    {
        return $this->prefixDirsPsr4;
    }

    public function getFallbackDirs()
    {
        return $this->fallbackDirsPsr0;
    }

    public function getFallbackDirsPsr4()
    {
        return $this->fallbackDirsPsr4;
    }

    public function getClassMap()
    {
        return $this->classMap;
    }

    /**
     * @param array $classMap Class to filename map
     */
    public function addClassMap(array $classMap)
    {
        if ($this->classMap) {
            $this->classMap = array_merge($this->classMap, $classMap);
        } else {
            $this->classMap = $classMap;
        }
    }

    /**
     * Registers a set of PSR-0 directories for a given prefix, either
     * appending or prepending to the ones previously set for this prefix.
     *
     * @param string       $prefix  The prefix
     * @param array|string $paths   The PSR-0 root directories
     * @param bool         $prepend Whether to prepend the directories
     */
    public function add($prefix, $paths, $prepend = false)
    {
        if (!$prefix) {
            if ($prepend) {
                $this->fallbackDirsPsr0 = array_merge(
                    (array) $paths,
                    $this->fallbackDirsPsr0
                );
            } else {
                $this->fallbackDirsPsr0 = array_merge(
                    $this->fallbackDirsPsr0,
                    (array) $paths
                );
            }

            return;
        }

        $first = $prefix[0];
        if (!isset($this->prefixesPsr0[$first][$prefix])) {
            $this->prefixesPsr0[$first][$prefix] = (array) $paths;

            return;
        }
        if ($prepend) {
            $this->prefixesPsr0[$first][$prefix] = array_merge(
                (array) $paths,
                $this->prefixesPsr0[$first][$prefix]
            );
        } else {
            $this->prefixesPsr0[$first][$prefix] = array_merge(
                $this->prefixesPsr0[$first][$prefix],
                (array) $paths
            );
        }
    }

    /**
     * Registers a set of PSR-4 directories for a given namespace, either
     * appending or prepending to the ones previously set for this namespace.
     *
     * @param string       $prefix  The prefix/namespace, with trailing '\\'
     * @param array|string $paths   The PSR-4 base directories
     * @param bool         $prepend Whether to prepend the directories
     *
     * @throws \InvalidArgumentException
     */
    public function addPsr4($prefix, $paths, $prepend = false)
    {
        if (!$prefix) {
            // Register directories for the root namespace.
            if ($prepend) {
                $this->fallbackDirsPsr4 = array_merge(
                    (array) $paths,
                    $this->fallbackDirsPsr4
                );
            } else {
                $this->fallbackDirsPsr4 = array_merge(
                    $this->fallbackDirsPsr4,
                    (array) $paths
                );
            }
        } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
            // Register directories for a new namespace.
            $length = strlen($prefix);
            if ('\\' !== $prefix[$length - 1]) {
                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
            }
            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
            $this->prefixDirsPsr4[$prefix] = (array) $paths;
        } elseif ($prepend) {
            // Prepend directories for an already registered namespace.
            $this->prefixDirsPsr4[$prefix] = array_merge(
                (array) $paths,
                $this->prefixDirsPsr4[$prefix]
            );
        } else {
            // Append directories for an already registered namespace.
            $this->prefixDirsPsr4[$prefix] = array_merge(
                $this->prefixDirsPsr4[$prefix],
                (array) $paths
            );
        }
    }

    /**
     * Registers a set of PSR-0 directories for a given prefix,
     * replacing any others previously set for this prefix.
     *
     * @param string       $prefix The prefix
     * @param array|string $paths  The PSR-0 base directories
     */
    public function set($prefix, $paths)
    {
        if (!$prefix) {
            $this->fallbackDirsPsr0 = (array) $paths;
        } else {
            $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
        }
    }

    /**
     * Registers a set of PSR-4 directories for a given namespace,
     * replacing any others previously set for this namespace.
     *
     * @param string       $prefix The prefix/namespace, with trailing '\\'
     * @param array|string $paths  The PSR-4 base directories
     *
     * @throws \InvalidArgumentException
     */
    public function setPsr4($prefix, $paths)
    {
        if (!$prefix) {
            $this->fallbackDirsPsr4 = (array) $paths;
        } else {
            $length = strlen($prefix);
            if ('\\' !== $prefix[$length - 1]) {
                throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
            }
            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
            $this->prefixDirsPsr4[$prefix] = (array) $paths;
        }
    }

    /**
     * Turns on searching the include path for class files.
     *
     * @param bool $useIncludePath
     */
    public function setUseIncludePath($useIncludePath)
    {
        $this->useIncludePath = $useIncludePath;
    }

    /**
     * Can be used to check if the autoloader uses the include path to check
     * for classes.
     *
     * @return bool
     */
    public function getUseIncludePath()
    {
        return $this->useIncludePath;
    }

    /**
     * Turns off searching the prefix and fallback directories for classes
     * that have not been registered with the class map.
     *
     * @param bool $classMapAuthoritative
     */
    public function setClassMapAuthoritative($classMapAuthoritative)
    {
        $this->classMapAuthoritative = $classMapAuthoritative;
    }

    /**
     * Should class lookup fail if not found in the current class map?
     *
     * @return bool
     */
    public function isClassMapAuthoritative()
    {
        return $this->classMapAuthoritative;
    }

    /**
     * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
     *
     * @param string|null $apcuPrefix
     */
    public function setApcuPrefix($apcuPrefix)
    {
        $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
    }

    /**
     * The APCu prefix in use, or null if APCu caching is not enabled.
     *
     * @return string|null
     */
    public function getApcuPrefix()
    {
        return $this->apcuPrefix;
    }

    /**
     * Registers this instance as an autoloader.
     *
     * @param bool $prepend Whether to prepend the autoloader or not
     */
    public function register($prepend = false)
    {
        spl_autoload_register(array($this, 'loadClass'), true, $prepend);
    }

    /**
     * Unregisters this instance as an autoloader.
     */
    public function unregister()
    {
        spl_autoload_unregister(array($this, 'loadClass'));
    }

    /**
     * Loads the given class or interface.
     *
     * @param  string    $class The name of the class
     * @return bool|null True if loaded, null otherwise
     */
    public function loadClass($class)
    {
        if ($file = $this->findFile($class)) {
            includeFile($file);

            return true;
        }
    }

    /**
     * Finds the path to the file where the class is defined.
     *
     * @param string $class The name of the class
     *
     * @return string|false The path if found, false otherwise
     */
    public function findFile($class)
    {
        // class map lookup
        if (isset($this->classMap[$class])) {
            return $this->classMap[$class];
        }
        if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
            return false;
        }
        if (null !== $this->apcuPrefix) {
            $file = apcu_fetch($this->apcuPrefix.$class, $hit);
            if ($hit) {
                return $file;
            }
        }

        $file = $this->findFileWithExtension($class, '.php');

        // Search for Hack files if we are running on HHVM
        if (false === $file && defined('HHVM_VERSION')) {
            $file = $this->findFileWithExtension($class, '.hh');
        }

        if (null !== $this->apcuPrefix) {
            apcu_add($this->apcuPrefix.$class, $file);
        }

        if (false === $file) {
            // Remember that this class does not exist.
            $this->missingClasses[$class] = true;
        }

        return $file;
    }

    private function findFileWithExtension($class, $ext)
    {
        // PSR-4 lookup
        $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;

        $first = $class[0];
        if (isset($this->prefixLengthsPsr4[$first])) {
            $subPath = $class;
            while (false !== $lastPos = strrpos($subPath, '\\')) {
                $subPath = substr($subPath, 0, $lastPos);
                $search = $subPath . '\\';
                if (isset($this->prefixDirsPsr4[$search])) {
                    $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
                    foreach ($this->prefixDirsPsr4[$search] as $dir) {
                        if (file_exists($file = $dir . $pathEnd)) {
                            return $file;
                        }
                    }
                }
            }
        }

        // PSR-4 fallback dirs
        foreach ($this->fallbackDirsPsr4 as $dir) {
            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
                return $file;
            }
        }

        // PSR-0 lookup
        if (false !== $pos = strrpos($class, '\\')) {
            // namespaced class name
            $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
                . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
        } else {
            // PEAR-like class name
            $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
        }

        if (isset($this->prefixesPsr0[$first])) {
            foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
                if (0 === strpos($class, $prefix)) {
                    foreach ($dirs as $dir) {
                        if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
                            return $file;
                        }
                    }
                }
            }
        }

        // PSR-0 fallback dirs
        foreach ($this->fallbackDirsPsr0 as $dir) {
            if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
                return $file;
            }
        }

        // PSR-0 include paths.
        if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
            return $file;
        }

        return false;
    }
}

/**
 * Scope isolated include.
 *
 * Prevents access to $this/self from included files.
 */
function includeFile($file)
{
    include $file;
}
PK/3YI�=���1bunyad-demo-import/vendor/composer/installed.json[
    {
        "name": "awesomemotive/wp-content-importer-v2",
        "version": "v3.0.3",
        "version_normalized": "3.0.3.0",
        "source": {
            "type": "git",
            "url": "https://github.com/awesomemotive/WordPress-Importer.git",
            "reference": "318c7657f4a4a84cf9e5a0d7f8d6ee2b2d0d0e9e"
        },
        "dist": {
            "type": "zip",
            "url": "https://api.github.com/repos/awesomemotive/WordPress-Importer/zipball/318c7657f4a4a84cf9e5a0d7f8d6ee2b2d0d0e9e",
            "reference": "318c7657f4a4a84cf9e5a0d7f8d6ee2b2d0d0e9e",
            "shasum": ""
        },
        "time": "2020-07-21T15:06:58+00:00",
        "type": "library",
        "installation-source": "dist",
        "autoload": {
            "psr-4": {
                "AwesomeMotive\\WPContentImporter2\\": "src/"
            }
        },
        "license": [
            "GPL-2.0+"
        ],
        "authors": [
            {
                "name": "Gregor Capuder",
                "email": "[email protected]"
            },
            {
                "name": "Primoz Cigler",
                "email": "[email protected]"
            },
            {
                "name": "Humanmade contributors",
                "homepage": "https://github.com/humanmade/WordPress-Importer/graphs/contributors"
            }
        ],
        "description": "Improved WP content importer used in OCDI plugin.",
        "keywords": [
            "awesomemotive",
            "content",
            "import",
            "theme",
            "wordpress",
            "wp"
        ],
        "support": {
            "source": "https://github.com/awesomemotive/WordPress-Importer/tree/v3.0.3"
        }
    }
]
PK/3Y �..*bunyad-demo-import/vendor/composer/LICENSE
Copyright (c) Nils Adermann, Jordi Boggiano

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

PK/3Y�f+�\\(bunyad-demo-import/views/plugin-page.php<?php
/**
 * Plugin page view.
 */
?>
<!-- The modal / dialog box, hidden somewhere near the footer -->
<div id="bunyad-missing-plugins" class="bunyad-depends-modal hidden" style="max-width:800px">

<p>The following required plugins should be installed and activated for this demo import.</p>
<ul class="plugin-names"></ul>

<form method="post" action="<?php echo esc_url(admin_url('admin.php?page=tgmpa-install-plugins')); ?>" target="_install_iframe">
	<input type="hidden" name="tgmpa-page" value="tgmpa-install-plugins" />
	<input type="hidden" name="plugin_status" value="all" />
	<!-- <input type="hidden" name="plugin[]" value="regenerate-thumbnails" /> -->
	<input type="hidden" name="action" value="tgmpa-bulk-install" />
	<?php wp_nonce_field('bulk-plugins'); ?>
	<div class="form-buttons ui-dialog-buttonpane">
		<input type="submit" class="button button-primary" value="<?php echo esc_attr__('Install/Activate Plugins'); ?>" />
		<!-- <a href="#" class="cancel button button-secondary">Cancel</a> -->
	</div>
</form>

<iframe name="_install_iframe" class="hidden"></iframe>
</div>


<div class="wrap bunyad-import">
<h1><?php echo esc_html_x('Import Theme Demos', 'Admin', 'pt-ocdi'); ?></h1>

<div class="notice notice-large intro-text">
	<h3>Using Importer:</h3>
	<p>We has several demos that can let you get quickly started with your setup. There are two type of imports available.</p>
	
	<ol>
		<li><p><strong>Settings Only</strong>: This will only import customizer settings but it will not import posts, menus, pages etc.</p></li>
		<li><p><strong>Full Content</strong>: Will import posts, menus, pages, images but it should only be used on fresh or test installs. It requires about 1-5 minutes to complete.</p></li>
	</ol>
	<p>
		<strong><?php echo esc_html_x('NOTE:', 'Admin', 'pt-ocdi'); ?></strong>
		DO NOT use "Full Content" option if your already have existing posts on your site. You cannot undo an import - create a backup if you really wish to use it on an existing site.
	</p> 

	<hr />
	<p>If it fails, you will have to request your webhost to increase your PHP <code>max_execution_time</code> (and other server timeouts) to at least 120 secs, and <code>memory_limit</code> to at least 196M, temporarily. If you tried it on a fresh WordPress install, you can go back to fresh install by using the "WordPress Reset" plugin. On localhost, a good internet connection is required.</p>

</div>

<div class="ajax-response"></div>

<div class="theme-browser">
<?php 

	// For is_plugin_active function.
	include_once  ABSPATH . 'wp-admin/includes/plugin.php';

	foreach ($this->import_files as $id => $demo): 
		$missing = [];

		// Required plugins check.
		if (!empty($demo['depends'])) {
			foreach ((array) $demo['depends'] as $slug => $name) {
				if (!is_plugin_active("{$slug}/{$slug}.php")) {
					$missing[$slug] = $name;
				}
			}
		}
		
		$missing = json_encode($missing);
?>

	<div class="theme">
		<a class="theme-screenshot" href="<?php echo esc_url($demo['demo_url']); ?>" target="_blank">
			<img src="<?php echo esc_url($demo['demo_image']); ?>" />
		</a>
		
		<div class="theme-id-container">
			<h3 class="theme-name"><?php echo esc_html($demo['demo_name']); ?></h3>
			<div class="theme-actions">
				<select name="import_type">
					<option value="settings"><?php echo esc_html_x('Settings Only', 'Admin', 'pt-ocdi'); ?></option>
					<option value="full"><?php echo esc_html_x('Full Content', 'Admin', 'pt-ocdi'); ?></option>
				</select>
				<a class="button import" data-id="<?php echo esc_attr($id); ?>" data-depends="<?php echo esc_attr($missing); ?>">Import</a>
			</div>
		</div>
	</div>

<?php endforeach; ?>
</div>
</div>PK/3Y�6#�)��bunyad-demo-import/bunyad-demo-import.phpPK/3Y��ee��Wbunyad-demo-import/readme.txtPK/3Y/�<��&���ubunyad-demo-import/assets/css/main.cssPK/3YEN�PP$���ybunyad-demo-import/assets/js/main.jsPK/3Y�Rww-��0�bunyad-demo-import/inc/CustomizerImporter.phpPK/3Y4C���+���bunyad-demo-import/inc/CustomizerOption.phpPK/3YB�hG��%��$�bunyad-demo-import/inc/Downloader.phpPK/3YԠH:�V�V"��<�bunyad-demo-import/inc/Helpers.phpPK/3Y� ���(��&bunyad-demo-import/inc/ImportActions.phpPK/3Y[��C��#��_'bunyad-demo-import/inc/Importer.phpPK/3YC��r��!��e@bunyad-demo-import/inc/Logger.phpPK/3YTLR�� ��)Fbunyad-demo-import/inc/menus.phpPK/3Y�
r:r:-��(bbunyad-demo-import/inc/OneClickDemoImport.phpPK/3Y�$�
	
	(���bunyad-demo-import/inc/ReduxImporter.phpPK/3Y��l�2�2)��8�bunyad-demo-import/inc/WidgetImporter.phpPK/3Y[@�*%*%(��[�bunyad-demo-import/inc/WPCLICommands.phpPK/3Y���2��&���bunyad-demo-import/inc/WXRImporter.phpPK/3Y9��(2(2(��bunyad-demo-import/languages/pt-ocdi.potPK/3Y�wb_��&��sDbunyad-demo-import/vendor/autoload.phpPK/3Y4��+��L��iEbunyad-demo-import/vendor/awesomemotive/wp-content-importer-v2/composer.jsonPK/3Yp�����H��cHbunyad-demo-import/vendor/awesomemotive/wp-content-importer-v2/README.mdPK/3Y
��L3@3@O���Mbunyad-demo-import/vendor/awesomemotive/wp-content-importer-v2/src/Importer.phpPK/3Y�h”R
R
W��+�bunyad-demo-import/vendor/awesomemotive/wp-content-importer-v2/src/WPImporterLogger.phpPK/3Y��ǼffZ���bunyad-demo-import/vendor/awesomemotive/wp-content-importer-v2/src/WPImporterLoggerCLI.phpPK/3Yv��'�'R��Пbunyad-demo-import/vendor/awesomemotive/wp-content-importer-v2/src/WXRImporter.phpPK/3Y�p��**T��6�bunyad-demo-import/vendor/awesomemotive/wp-content-importer-v2/src/WXRImportInfo.phpPK/3Y��b��8����bunyad-demo-import/vendor/composer/autoload_classmap.phpPK/3Yt�!ו�:����bunyad-demo-import/vendor/composer/autoload_namespaces.phpPK/3YS�=''4����bunyad-demo-import/vendor/composer/autoload_psr4.phpPK/3Y�?BE  4��!�bunyad-demo-import/vendor/composer/autoload_real.phpPK/3Y�"�))6����bunyad-demo-import/vendor/composer/autoload_static.phpPK/3Y�z���4�42���bunyad-demo-import/vendor/composer/ClassLoader.phpPK/3YI�=���1���
bunyad-demo-import/vendor/composer/installed.jsonPK/3Y �..*��
bunyad-demo-import/vendor/composer/LICENSEPK/3Y�f+�\\(���bunyad-demo-import/views/plugin-page.phpPK##
"(Downloaded From GPLAstra.com

Youez - 2016 - github.com/yon3zu
LinuXploit