Acme Demo Setup - Version 1.0.3

Version Description

Download this release

Release Info

Developer acmethemes
Plugin Icon 128x128 Acme Demo Setup
Version 1.0.3
Comparing to
See all releases

Version 1.0.3

acme-demo-setup.php ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: Acme Demo Setup
4
+ Plugin URI:
5
+ Description: One click demo import
6
+ Version: 1.0.3
7
+ Author: Acme Themes
8
+ Author URI: https://www.acmethemes.com/
9
+ License: GPLv2 or later
10
+ */
11
+
12
+ /*Make sure we don't expose any info if called directly*/
13
+ if ( !function_exists( 'add_action' ) ) {
14
+ echo 'Hi there! I\'m just a plugin, not much I can do when called directly.';
15
+ exit;
16
+ }
17
+ /*Define Constants for this plugin*/
18
+ define( 'ACME_DEMO_SETUP_VERSION', '1.0' );
19
+ define( 'ACME_DEMO_SETUP_PATH', plugin_dir_path( __FILE__ ) );
20
+ define( 'ACME_DEMO_SETUP_URL', plugin_dir_url( __FILE__ ) );
21
+
22
+ /*Now lets init the functionality of this plugin*/
23
+ require_once( ACME_DEMO_SETUP_PATH . '/inc/init.php' );
24
+
25
+ /**
26
+ * Load plugin textdomain.
27
+ * see here https://ulrich.pogson.ch/load-theme-plugin-translations
28
+ */
29
+ if ( ! function_exists( 'acme_demo_setup_load_textdomain' ) ) :
30
+ function acme_demo_setup_load_textdomain() {
31
+
32
+ $domain = 'acme-demo-setup';
33
+ $locale = apply_filters( 'plugin_locale', get_locale(), $domain );
34
+
35
+ // wp-content/languages/plugin-name/plugin-name-de_DE.mo
36
+ load_textdomain( 'acme-demo-setup', trailingslashit( WP_LANG_DIR ) . $domain . '/' . $domain . '-' . $locale . '.mo' );
37
+
38
+ // wp-content/plugins/plugin-name/languages/plugin-name-de_DE.mo
39
+ load_plugin_textdomain( 'acme-demo-setup', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
40
+ }
41
+ endif;
42
+ add_action( 'plugins_loaded', 'acme_demo_setup_load_textdomain' );
43
+
44
+
inc/admin/upload.php ADDED
@@ -0,0 +1,217 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Acme Demo Setup
4
+ *
5
+ * @package Acme Themes
6
+ * @subpackage Acme Demo Setup
7
+ */
8
+ if( !class_exists( 'Acme_Demo_Setup') ):
9
+ class Acme_Demo_Setup {
10
+ /**
11
+ * @return void
12
+ */
13
+ function __construct( ) {
14
+ add_action( 'mime_types', array( $this, 'mime_types' ) );
15
+ add_action( 'admin_menu', array( $this, 'menu' ) );
16
+ /* enqueue script and style for about page */
17
+ add_action( 'admin_enqueue_scripts', array( $this, 'style_and_scripts' ) );
18
+ /*ajax callback for demo content installation*/
19
+ add_action( 'wp_ajax_acme_demo_setup_ajax_setup', array( $this, 'handler' ) );
20
+
21
+ }
22
+ /**
23
+ * Load css and scripts for the about page
24
+ */
25
+ public function style_and_scripts( $hook_suffix ) {
26
+ if ( 'appearance_page_acme-demo-setup' == $hook_suffix ) {
27
+ wp_enqueue_script( 'acme-demo-setup', ACME_DEMO_SETUP_URL.'inc/assets/js/acme-demo-setup.js', array( 'jquery' ) );
28
+ wp_localize_script( 'acme-demo-setup', 'acme_demo_setup_object', array(
29
+ 'ajaxurl' => admin_url( 'admin-ajax.php' ),
30
+ 'importing' => esc_html__('Importing','education-base'),
31
+ 'imported' => esc_html__('Task Completed, view the log below','education-base')
32
+ ) );
33
+ }
34
+ }
35
+ /**
36
+ * @return array
37
+ */
38
+ function mime_types( $mimes ) {
39
+ $add_mimes = array(
40
+ 'dat' => 'text/plain',
41
+ 'xml' => 'application/xml',
42
+ 'wie' => 'text/html'
43
+ );
44
+
45
+ return array_merge( $mimes, $add_mimes );
46
+ }
47
+
48
+ /**
49
+ * Create admin pages in menu
50
+ *
51
+ * @return void
52
+ */
53
+ function menu() {
54
+ add_theme_page( __( 'Acme Demo Setup', 'acme-demo-setup' ), __( 'Acme Demo Setup', 'acme-demo-setup' ), 'upload_files', 'acme-demo-setup', array( $this, 'screen' ) );
55
+ }
56
+
57
+ /**
58
+ * The Admin Screen
59
+ */
60
+ function screen() {
61
+ echo '<div class="wrap">';
62
+ echo '<h2>' . __( 'Acme Demo Setup', 'acme-demo-setup' ) . '</h2>';
63
+ $this->handler();
64
+ $this->import_form();
65
+ echo '</div>';
66
+ }
67
+
68
+ /**
69
+ * Handle the demo content upload and called to process
70
+ *
71
+ * @return string HTML Results or Error message
72
+ */
73
+ function handler() {
74
+ $error = '';
75
+ $required_files = array();
76
+ if ( isset( $_FILES[ 'upload-zip-archive' ][ 'name' ] ) && ! empty( $_FILES[ 'upload-zip-archive' ][ 'name' ] ) ) {
77
+
78
+ /*check for security*/
79
+ if ( ! current_user_can( 'upload_files' ) ) {
80
+ wp_die( __( 'Sorry, you are not allowed to install demo on this site.', 'acme-demo-setup' ) );
81
+ }
82
+ check_admin_referer( 'acme-demo-setup' );
83
+
84
+ /*file process*/
85
+ esc_html_e('Uploading Zip...','acme-demo-import');
86
+ echo "<br />";
87
+ $upload_zip_archive = $_FILES[ 'upload-zip-archive' ];
88
+ WP_Filesystem();
89
+ global $wp_filesystem;
90
+ $upload_dir = wp_upload_dir();
91
+ $destination = $upload_dir['basedir'] . '/acme-demo-importer/';
92
+
93
+ /*the zip file shouldn't content greater than 3 files*/
94
+ $za = new ZipArchive();
95
+ $za->open( $upload_zip_archive['tmp_name'] );
96
+ $file_on_zip = $za->numFiles;
97
+ if( $file_on_zip > 3 ){
98
+ $error[] = __( "Invalid ZIP greater than 3 files" ,'acme-demo-importer');
99
+ }
100
+
101
+ /*unzip file*/
102
+ esc_html_e('Unzipping File...','acme-demo-import');
103
+ echo "<br />";
104
+ $unzipfile = unzip_file( $upload_zip_archive['tmp_name'], $destination);
105
+ if ( !$unzipfile ) {
106
+ $error[] = __( "Error on unzipping, Please try again" ,'acme-demo-importer');
107
+ }
108
+
109
+ /*get required file*/
110
+ $dirlist = $wp_filesystem->dirlist($destination);
111
+ foreach ( (array) $dirlist as $filename => $fileinfo ) {
112
+ $filetype = wp_check_filetype($filename);
113
+ if( 'xml' == $filetype['ext'] ){
114
+ $required_files['xml'] = $destination.$filename;
115
+ }
116
+ elseif ('wie' == $filetype['ext'] ){
117
+ $required_files['wie'] = $destination.$filename;
118
+ }
119
+ elseif ( 'dat' == $filetype['ext'] ){
120
+ $required_files['dat'] = $destination.$filename;
121
+ }
122
+ else{
123
+ $wp_filesystem->rmdir($destination, true );
124
+ $error[] = __( "Invalid ZIP destination file" ,'acme-demo-importer');
125
+ }
126
+ }
127
+
128
+ /*prepare array of files to import*/
129
+ if( !isset( $required_files['xml'] ) || empty( $required_files['xml'] )){
130
+ $error[] = __( "xml file not included" ,'acme-demo-importer');
131
+
132
+ }
133
+ if( !isset( $required_files['wie'] ) && empty( $required_files['wie'] )){
134
+ $error[] = __( "wie file not included" ,'acme-demo-importer');
135
+
136
+ }
137
+ if( !isset( $required_files['dat'] ) && empty( $required_files['dat'] )){
138
+ $error[] = __( "dat file not included" ,'acme-demo-importer');
139
+ }
140
+ if( is_array( $error ) && !empty( $error ) ){
141
+ foreach ( $error as $e ){
142
+ echo $e;
143
+ echo "<br />";
144
+ }
145
+ }
146
+
147
+ /*process import*/
148
+ $this->import( $required_files );
149
+ }
150
+ }
151
+
152
+ /*import */
153
+ function import( $required_files ){
154
+ /*before import*/
155
+ do_action( 'acme_demo_setup_before_import',$required_files );
156
+
157
+ /*xml demo import*/
158
+ if( isset( $required_files['xml'] ) && !empty( $required_files['xml'] ) ){
159
+ esc_html_e('Importing Demo Content...','acme-demo-import');
160
+ echo "<br /><br />";
161
+
162
+ // Try to update PHP memory limit (so that it does not run out of it).
163
+ ini_set( 'memory_limit', apply_filters( 'acme_demo_setup_memory_limit', '50M' ) );
164
+
165
+ $xml_import = new Acme_Demo_Setup_Wp_Import();
166
+ $xml_import->fetch_attachments = true;
167
+ set_time_limit(0);
168
+ $xml_import -> import( $required_files['xml'] );
169
+ }
170
+
171
+ /*customizer import*/
172
+ if( isset( $required_files['dat'] ) && !empty( $required_files['dat'] ) ){
173
+ esc_html_e('Importing Customizer Data...','acme-demo-import');
174
+ echo "<br /><br />";
175
+
176
+ $wie_import = new Acme_Demo_Setup_CEI_Core();
177
+ $wie_import -> _import( $required_files['dat'] );
178
+ }
179
+
180
+ /*widget import*/
181
+ if( isset( $required_files['dat'] ) && !empty( $required_files['dat'] ) ){
182
+ esc_html_e('Importing Widget Data...','acme-demo-import');
183
+ echo "<br /><br />";
184
+
185
+ acme_demo_setup_wie_process_import_file( $required_files['wie'] );
186
+ }
187
+
188
+ do_action( 'acme_demo_setup_after_import',$required_files );
189
+
190
+ printf( esc_html__('All Done Visit your %s site %s','acme-demo-import'),'<a href='.esc_url( get_home_url()).' target="_blank">','</a>' );
191
+ echo "<br /><br />";
192
+
193
+ exit;
194
+ }
195
+
196
+ /**
197
+ * The upload form
198
+ *
199
+ * @param null
200
+ */
201
+ function import_form( ) {
202
+ echo '<form action="" method="post" enctype="multipart/form-data" id="acme-demo-setup-upload-zip-form">';
203
+ echo '<h3 class="media-title">'. __( 'Upload a zip file containing demo content', 'acme-demo-setup' ) .'</h3>';
204
+ echo '<p><input type="file" name="upload-zip-archive" id="upload-zip-archive" size="50" /></p>';
205
+ echo '<p>'. sprintf( __( 'Maximum upload file size: %s','acme-demo-setup' ), size_format( wp_max_upload_size() ) ) .'</p>';
206
+ wp_nonce_field( 'acme-demo-setup' );
207
+ submit_button( __( 'Upload and Import', 'acme-demo-setup' ) );
208
+ echo "<div id='at-demo-ajax-install-error' style='display: none;color: #d54e21'>".esc_html__('Select File and Try Again!','education-base')."</div>";
209
+ echo '</form>';
210
+ echo "<span id='at-demo-ajax-install-result-loading' class='button button-primary' style='display: none'>".esc_html__('Importing...','education-base')."</span>";
211
+ echo "<h4 id='at-demo-ajax-install-result-title' style='display: none'>".esc_html__('Task Completed, view the log below','education-base')."</h4>";
212
+ echo "<div id='at-demo-ajax-install-result'></div>";
213
+ }
214
+
215
+ }//end class
216
+ endif;
217
+ $Acme_Demo_Setup = new Acme_Demo_Setup();
inc/assets/js/acme-demo-setup.js ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(document).ready(function ($) {
2
+ $('#acme-demo-setup-upload-zip-form').submit(function (e) {
3
+ if( window.FormData === undefined ){
4
+ return true;
5
+ }
6
+ e.preventDefault();
7
+ var fd = new FormData();
8
+ var file = $(this).find('#upload-zip-archive');
9
+ if(!file.val()){
10
+ jQuery('#at-demo-ajax-install-error').show();
11
+ return false;
12
+ }
13
+ else{
14
+ jQuery('#at-demo-ajax-install-error').hide();
15
+ }
16
+ var _wpnonce = $(this).find('input[name=_wpnonce]');
17
+ var _wp_http_referer = $(this).find('input[name=_wp_http_referer]');
18
+
19
+ var individual_file = file[0].files[0];
20
+
21
+ fd.append("upload-zip-archive", individual_file);
22
+ fd.append('action', 'acme_demo_setup_ajax_setup');
23
+ fd.append('_wpnonce', _wpnonce.val());
24
+ fd.append('_wp_http_referer', _wp_http_referer.val());
25
+
26
+ jQuery.ajax({
27
+ type: 'POST',
28
+ url: acme_demo_setup_object.ajaxurl,
29
+ data: fd,
30
+ contentType: false,
31
+ processData: false,
32
+ beforeSend: function (data, settings) {
33
+ jQuery('#acme-demo-setup-upload-zip-form').remove();
34
+ jQuery('#at-demo-ajax-install-result-loading').show();
35
+ jQuery('#at-demo-ajax-install').html(acme_demo_setup_object.importing);
36
+ },
37
+ success : function (data) {
38
+ jQuery('#at-demo-ajax-install-result-loading').hide();
39
+ jQuery('#at-demo-ajax-install-result-title').show();
40
+ jQuery('#at-demo-ajax-install-result').html(data);
41
+ },
42
+ error : function (jqXHR, textStatus, errorThrown) {
43
+ console.log(jqXHR + " :: " + textStatus + " :: " + errorThrown);
44
+ }
45
+ });
46
+ return false;
47
+ });
48
+
49
+ });
inc/frameworks/customizer-export-import/class-cei-core.php ADDED
@@ -0,0 +1,199 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * The main export/import class from customizer-export-import.
4
+ * Renaming CEI_Core to Acme_Demo_Setup_CEI_Core
5
+ * @since 1.0.0
6
+ */
7
+ final class Acme_Demo_Setup_CEI_Core {
8
+
9
+ /**
10
+ * An array of core options that shouldn't be imported.
11
+ *
12
+ * @since 1.0.0
13
+ * @access private
14
+ * @var array $core_options
15
+ */
16
+ static private $core_options = array(
17
+ 'blogname',
18
+ 'blogdescription',
19
+ 'show_on_front',
20
+ 'page_on_front',
21
+ 'page_for_posts',
22
+ );
23
+
24
+ /**
25
+ * Acme Customized Version
26
+ * Imports uploaded mods and calls WordPress core customize_save actions so
27
+ * themes that hook into them can act before mods are saved to the database.
28
+ *
29
+ * @since 1.0
30
+ * @access public
31
+ * @param object $wp_customize An instance of WP_Customize_Manager.
32
+ */
33
+ function _import( $file_url ) {
34
+ $template = get_template();
35
+
36
+ WP_Filesystem();
37
+
38
+ // Setup global vars.
39
+ global $wp_filesystem;
40
+ global $wp_customize;
41
+
42
+
43
+ $raw = $wp_filesystem->get_contents( $file_url );
44
+ if ( $error = is_wp_error( $raw ) ) {
45
+ return $error;
46
+ }
47
+
48
+ $data = @unserialize( $raw );
49
+
50
+ // Data checks.
51
+ if ( 'array' != gettype( $data ) ) {
52
+ esc_html_e( 'Error importing settings! Please check that you uploaded a customizer export file.', 'acme-demo-setup' );
53
+ return;
54
+ }
55
+ if ( ! isset( $data['template'] ) || ! isset( $data['mods'] ) ) {
56
+ esc_html_e( 'Error importing settings! Please check that you uploaded a customizer export file.', 'acme-demo-setup' );
57
+ return;
58
+ }
59
+ if ( $data['template'] != $template ) {
60
+ esc_html_e( 'Error importing settings! The settings you uploaded are not for the current theme.', 'acme-demo-setup' );
61
+ return;
62
+ }
63
+
64
+ // Import images.
65
+ $data['mods'] = self::_import_images( $data['mods'] );
66
+
67
+ // Import custom options.
68
+ if ( isset( $data['options'] ) ) {
69
+
70
+ foreach ( $data['options'] as $option_key => $option_value ) {
71
+
72
+ $option = new Acme_Demo_Setup_CEI_Option( $wp_customize, $option_key, array(
73
+ 'default' => '',
74
+ 'type' => 'option',
75
+ 'capability' => 'edit_theme_options'
76
+ ) );
77
+
78
+ $option->import( $option_value );
79
+ }
80
+ }
81
+
82
+ // Call the customize_save action.
83
+ do_action( 'customize_save', $wp_customize );
84
+
85
+ // Loop through the mods.
86
+ foreach ( $data['mods'] as $key => $val ) {
87
+
88
+ // Call the customize_save_ dynamic action.
89
+ do_action( 'customize_save_' . $key, $wp_customize );
90
+
91
+ // Save the mod.
92
+ set_theme_mod( $key, $val );
93
+ }
94
+
95
+ }
96
+
97
+ /**
98
+ * Imports images for settings saved as mods.
99
+ *
100
+ * @since 0.1
101
+ * @access private
102
+ * @param array $mods An array of customizer mods.
103
+ * @return array The mods array with any new import data.
104
+ */
105
+ static private function _import_images( $mods )
106
+ {
107
+ foreach ( $mods as $key => $val ) {
108
+
109
+ if ( self::_is_image_url( $val ) ) {
110
+
111
+ $data = self::_sideload_image( $val );
112
+
113
+ if ( ! is_wp_error( $data ) ) {
114
+
115
+ $mods[ $key ] = $data->url;
116
+
117
+ // Handle header image controls.
118
+ if ( isset( $mods[ $key . '_data' ] ) ) {
119
+ $mods[ $key . '_data' ] = $data;
120
+ update_post_meta( $data->attachment_id, '_wp_attachment_is_custom_header', get_stylesheet() );
121
+ }
122
+ }
123
+ }
124
+ }
125
+
126
+ return $mods;
127
+ }
128
+
129
+ /**
130
+ * Taken from the core media_sideload_image function and
131
+ * modified to return an array of data instead of html.
132
+ *
133
+ * @since 0.1
134
+ * @access private
135
+ * @param string $file The image file path.
136
+ * @return stdClass An array of image data.
137
+ */
138
+ static private function _sideload_image( $file )
139
+ {
140
+ $data = new stdClass();
141
+
142
+ if ( ! function_exists( 'media_handle_sideload' ) ) {
143
+ require_once( ABSPATH . 'wp-admin/includes/media.php' );
144
+ require_once( ABSPATH . 'wp-admin/includes/file.php' );
145
+ require_once( ABSPATH . 'wp-admin/includes/image.php' );
146
+ }
147
+ if ( ! empty( $file ) ) {
148
+
149
+ // Set variables for storage, fix file filename for query strings.
150
+ preg_match( '/[^\?]+\.(jpe?g|jpe|gif|png)\b/i', $file, $matches );
151
+ $file_array = array();
152
+ $file_array['name'] = basename( $matches[0] );
153
+
154
+ // Download file to temp location.
155
+ $file_array['tmp_name'] = download_url( $file );
156
+
157
+ // If error storing temporarily, return the error.
158
+ if ( is_wp_error( $file_array['tmp_name'] ) ) {
159
+ return $file_array['tmp_name'];
160
+ }
161
+
162
+ // Do the validation and storage stuff.
163
+ $id = media_handle_sideload( $file_array, 0 );
164
+
165
+ // If error storing permanently, unlink.
166
+ if ( is_wp_error( $id ) ) {
167
+ @unlink( $file_array['tmp_name'] );
168
+ return $id;
169
+ }
170
+
171
+ // Build the object to return.
172
+ $meta = wp_get_attachment_metadata( $id );
173
+ $data->attachment_id = $id;
174
+ $data->url = wp_get_attachment_url( $id );
175
+ $data->thumbnail_url = wp_get_attachment_thumb_url( $id );
176
+ $data->height = $meta['height'];
177
+ $data->width = $meta['width'];
178
+ }
179
+
180
+ return $data;
181
+ }
182
+
183
+ /**
184
+ * Checks to see whether a string is an image url or not.
185
+ *
186
+ * @since 0.1
187
+ * @access private
188
+ * @param string $string The string to check.
189
+ * @return bool Whether the string is an image url or not.
190
+ */
191
+ static private function _is_image_url( $string = '' ){
192
+ if ( is_string( $string ) ) {
193
+ if ( preg_match( '/\.(jpg|jpeg|png|gif)/i', $string ) ) {
194
+ return true;
195
+ }
196
+ }
197
+ return false;
198
+ }
199
+ }
inc/frameworks/customizer-export-import/class-cei-option.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * A class that extends WP_Customize_Setting so we can access
4
+ * the protected updated method when importing options.
5
+ *
6
+ * @since 1.0.0
7
+ *
8
+ * Renaming CEI_Option to Acme_Demo_Setup_CEI_Option
9
+ */
10
+ // Load WordPress Customize Setting Class.
11
+ if ( ! class_exists( 'WP_Customize_Setting' ) ) {
12
+ require_once( ABSPATH . WPINC . '/class-wp-customize-setting.php' );
13
+ }
14
+
15
+ final class Acme_Demo_Setup_CEI_Option extends WP_Customize_Setting {
16
+
17
+ /**
18
+ * Import an option value for this setting.
19
+ *
20
+ * @since 1.0.0
21
+ * @param mixed $value The option value.
22
+ * @return void
23
+ */
24
+ public function import( $value )
25
+ {
26
+ $this->update( $value );
27
+ }
28
+ }
inc/frameworks/widget-importer-exporter/import.php ADDED
@@ -0,0 +1,244 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Process import file
4
+ *
5
+ * This parses a file and triggers importation of its widgets.
6
+ *
7
+ * @since 1.0.0
8
+ * @param string $file Path to .wie file uploaded
9
+ * @global string $wie_import_results
10
+ *
11
+ * Renaming wie_process_import_file to acme_demo_setup_wie_process_import_file
12
+ */
13
+ function acme_demo_setup_wie_process_import_file( $file ) {
14
+
15
+ global $wie_import_results;
16
+
17
+ // File exists?
18
+ if ( ! file_exists( $file ) ) {
19
+ wp_die(
20
+ esc_html__( 'Import file could not be found. Please try again.', 'acme-demo-setup' ),
21
+ '',
22
+ array( 'back_link' => true )
23
+ );
24
+ }
25
+
26
+ // Get file contents and decode
27
+ $data = file_get_contents( $file );
28
+ $data = json_decode( $data );
29
+
30
+ // Import the widget data
31
+ // Make results available for display on import/export page
32
+ $wie_import_results = acme_demo_setup_wie_import_data( $data );
33
+ }
34
+
35
+ /**
36
+ * Import widget JSON data
37
+ *
38
+ * @since 1.0.0
39
+ * @global array $wp_registered_sidebars
40
+ * @param object $data JSON widget data from .wie file
41
+ * @return array Results array
42
+ */
43
+ function acme_demo_setup_wie_import_data( $data ) {
44
+
45
+ global $wp_registered_sidebars;
46
+
47
+ // Have valid data?
48
+ // If no data or could not decode
49
+ if ( empty( $data ) || ! is_object( $data ) ) {
50
+ wp_die(
51
+ esc_html__( 'Import data could not be read. Please try a different file.', 'acme-demo-setup' ),
52
+ '',
53
+ array( 'back_link' => true )
54
+ );
55
+ }
56
+
57
+ // Hook before import
58
+ do_action( 'wie_before_import' );
59
+ $data = apply_filters( 'wie_import_data', $data );
60
+
61
+ // Get all available widgets site supports
62
+ $available_widgets = acme_demo_setup_wie_available_widgets();
63
+
64
+ // Get all existing widget instances
65
+ $widget_instances = array();
66
+ foreach ( $available_widgets as $widget_data ) {
67
+ $widget_instances[$widget_data['id_base']] = get_option( 'widget_' . $widget_data['id_base'] );
68
+ }
69
+
70
+ // Begin results
71
+ $results = array();
72
+
73
+ // Loop import data's sidebars
74
+ foreach ( $data as $sidebar_id => $widgets ) {
75
+
76
+ // Skip inactive widgets
77
+ // (should not be in export file)
78
+ if ( 'wp_inactive_widgets' == $sidebar_id ) {
79
+ continue;
80
+ }
81
+
82
+ // Check if sidebar is available on this site
83
+ // Otherwise add widgets to inactive, and say so
84
+ if ( isset( $wp_registered_sidebars[$sidebar_id] ) ) {
85
+ $sidebar_available = true;
86
+ $use_sidebar_id = $sidebar_id;
87
+ $sidebar_message_type = 'success';
88
+ $sidebar_message = '';
89
+ } else {
90
+ $sidebar_available = false;
91
+ $use_sidebar_id = 'wp_inactive_widgets'; // add to inactive if sidebar does not exist in theme
92
+ $sidebar_message_type = 'error';
93
+ $sidebar_message = esc_html__( 'Widget area does not exist in theme (using Inactive)', 'acme-demo-setup' );
94
+ }
95
+
96
+ // Result for sidebar
97
+ $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
98
+ $results[$sidebar_id]['message_type'] = $sidebar_message_type;
99
+ $results[$sidebar_id]['message'] = $sidebar_message;
100
+ $results[$sidebar_id]['widgets'] = array();
101
+
102
+ // Loop widgets
103
+ foreach ( $widgets as $widget_instance_id => $widget ) {
104
+
105
+ $fail = false;
106
+
107
+ // Get id_base (remove -# from end) and instance ID number
108
+ $id_base = preg_replace( '/-[0-9]+$/', '', $widget_instance_id );
109
+ $instance_id_number = str_replace( $id_base . '-', '', $widget_instance_id );
110
+
111
+ // Does site support this widget?
112
+ if ( ! $fail && ! isset( $available_widgets[$id_base] ) ) {
113
+ $fail = true;
114
+ $widget_message_type = 'error';
115
+ $widget_message = esc_html__( 'Site does not support widget', 'acme-demo-setup' ); // explain why widget not imported
116
+ }
117
+
118
+ // Filter to modify settings object before conversion to array and import
119
+ // Leave this filter here for backwards compatibility with manipulating objects (before conversion to array below)
120
+ // Ideally the newer wie_widget_settings_array below will be used instead of this
121
+ $widget = apply_filters( 'wie_widget_settings', $widget ); // object
122
+
123
+ // Convert multidimensional objects to multidimensional arrays
124
+ // Some plugins like Jetpack Widget Visibility store settings as multidimensional arrays
125
+ // Without this, they are imported as objects and cause fatal error on Widgets page
126
+ // 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
127
+ // It is probably much more likely that arrays are used than objects, however
128
+ $widget = json_decode( wp_json_encode( $widget ), true );
129
+
130
+ // Filter to modify settings array
131
+ // This is preferred over the older wie_widget_settings filter above
132
+ // Do before identical check because changes may make it identical to end result (such as URL replacements)
133
+ $widget = apply_filters( 'wie_widget_settings_array', $widget );
134
+
135
+ // Does widget with identical settings already exist in same sidebar?
136
+ if ( ! $fail && isset( $widget_instances[$id_base] ) ) {
137
+
138
+ // Get existing widgets in this sidebar
139
+ $sidebars_widgets = get_option( 'sidebars_widgets' );
140
+ $sidebar_widgets = isset( $sidebars_widgets[$use_sidebar_id] ) ? $sidebars_widgets[$use_sidebar_id] : array(); // check Inactive if that's where will go
141
+
142
+ // Loop widgets with ID base
143
+ $single_widget_instances = ! empty( $widget_instances[$id_base] ) ? $widget_instances[$id_base] : array();
144
+ foreach ( $single_widget_instances as $check_id => $check_widget ) {
145
+
146
+ // Is widget in same sidebar and has identical settings?
147
+ if ( in_array( "$id_base-$check_id", $sidebar_widgets ) && (array) $widget == $check_widget ) {
148
+
149
+ $fail = true;
150
+ $widget_message_type = 'warning';
151
+ $widget_message = esc_html__( 'Widget already exists', 'acme-demo-setup' ); // explain why widget not imported
152
+
153
+ break;
154
+
155
+ }
156
+
157
+ }
158
+
159
+ }
160
+
161
+ // No failure
162
+ if ( ! $fail ) {
163
+
164
+ // Add widget instance
165
+ $single_widget_instances = get_option( 'widget_' . $id_base ); // all instances for that widget ID base, get fresh every time
166
+ $single_widget_instances = ! empty( $single_widget_instances ) ? $single_widget_instances : array( '_multiwidget' => 1 ); // start fresh if have to
167
+ $single_widget_instances[] = $widget; // add it
168
+
169
+ // Get the key it was given
170
+ end( $single_widget_instances );
171
+ $new_instance_id_number = key( $single_widget_instances );
172
+
173
+ // If key is 0, make it 1
174
+ // 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)
175
+ if ( '0' === strval( $new_instance_id_number ) ) {
176
+ $new_instance_id_number = 1;
177
+ $single_widget_instances[$new_instance_id_number] = $single_widget_instances[0];
178
+ unset( $single_widget_instances[0] );
179
+ }
180
+
181
+ // Move _multiwidget to end of array for uniformity
182
+ if ( isset( $single_widget_instances['_multiwidget'] ) ) {
183
+ $multiwidget = $single_widget_instances['_multiwidget'];
184
+ unset( $single_widget_instances['_multiwidget'] );
185
+ $single_widget_instances['_multiwidget'] = $multiwidget;
186
+ }
187
+
188
+ // Update option with new widget
189
+ update_option( 'widget_' . $id_base, $single_widget_instances );
190
+
191
+ // Assign widget instance to sidebar
192
+ $sidebars_widgets = get_option( 'sidebars_widgets' ); // which sidebars have which widgets, get fresh every time
193
+
194
+ // Avoid rarely fatal error when the option is an empty string
195
+ // https://github.com/churchthemes/widget-importer-exporter/pull/11
196
+ if ( ! $sidebars_widgets ) {
197
+ $sidebars_widgets = array();
198
+ }
199
+
200
+ $new_instance_id = $id_base . '-' . $new_instance_id_number; // use ID number from new widget instance
201
+ $sidebars_widgets[$use_sidebar_id][] = $new_instance_id; // add new instance to sidebar
202
+ update_option( 'sidebars_widgets', $sidebars_widgets ); // save the amended data
203
+
204
+ // After widget import action
205
+ $after_widget_import = array(
206
+ 'sidebar' => $use_sidebar_id,
207
+ 'sidebar_old' => $sidebar_id,
208
+ 'widget' => $widget,
209
+ 'widget_type' => $id_base,
210
+ 'widget_id' => $new_instance_id,
211
+ 'widget_id_old' => $widget_instance_id,
212
+ 'widget_id_num' => $new_instance_id_number,
213
+ 'widget_id_num_old' => $instance_id_number
214
+ );
215
+ do_action( 'wie_after_widget_import', $after_widget_import );
216
+
217
+ // Success message
218
+ if ( $sidebar_available ) {
219
+ $widget_message_type = 'success';
220
+ $widget_message = esc_html__( 'Imported', 'acme-demo-setup' );
221
+ } else {
222
+ $widget_message_type = 'warning';
223
+ $widget_message = esc_html__( 'Imported to Inactive', 'acme-demo-setup' );
224
+ }
225
+
226
+ }
227
+
228
+ // Result for widget instance
229
+ $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)
230
+ $results[$sidebar_id]['widgets'][$widget_instance_id]['title'] = ! empty( $widget['title'] ) ? $widget['title'] : esc_html__( 'No Title', 'acme-demo-setup' ); // show "No Title" if widget instance is untitled
231
+ $results[$sidebar_id]['widgets'][$widget_instance_id]['message_type'] = $widget_message_type;
232
+ $results[$sidebar_id]['widgets'][$widget_instance_id]['message'] = $widget_message;
233
+
234
+ }
235
+
236
+ }
237
+
238
+ // Hook after import
239
+ do_action( 'wie_after_import' );
240
+
241
+ // Return results
242
+ return apply_filters( 'wie_import_results', $results );
243
+
244
+ }
inc/frameworks/widget-importer-exporter/widgets.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Widget Functions
4
+ * @since 1.0.0
5
+ */
6
+
7
+ // No direct access
8
+ if ( ! defined( 'ABSPATH' ) ) exit;
9
+
10
+ /**
11
+ * Available widgets
12
+ *
13
+ * Gather site's widgets into array with ID base, name, etc.
14
+ * Used by export and import functions.
15
+ *
16
+ * @since 0.4
17
+ * @global array $wp_registered_widget_updates
18
+ * @return array Widget information
19
+ *
20
+ * Remaning wie_available_widgets to acme_demo_setup_wie_available_widgets
21
+ */
22
+ function acme_demo_setup_wie_available_widgets() {
23
+ global $wp_registered_widget_controls;
24
+ $widget_controls = $wp_registered_widget_controls;
25
+ $available_widgets = array();
26
+ foreach ( $widget_controls as $widget ) {
27
+ if ( ! empty( $widget['id_base'] ) && ! isset( $available_widgets[$widget['id_base']] ) ) { // no dupes
28
+ $available_widgets[$widget['id_base']]['id_base'] = $widget['id_base'];
29
+ $available_widgets[$widget['id_base']]['name'] = $widget['name'];
30
+ }
31
+ }
32
+ return apply_filters( 'acme_demo_setup_wie_available_widgets', $available_widgets );
33
+ }
inc/frameworks/wordpress-importer/parsers.php ADDED
@@ -0,0 +1,689 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * WordPress eXtended RSS file parser implementations
4
+ */
5
+
6
+ /**
7
+ * WordPress Importer class for managing parsing of WXR files.
8
+ * Renaming WXR_Parser to Acme_Demo_Setup_WXR_Parser
9
+ */
10
+ class Acme_Demo_Setup_WXR_Parser {
11
+ function parse( $file ) {
12
+ // Attempt to use proper XML parsers first
13
+ if ( extension_loaded( 'simplexml' ) ) {
14
+ $parser = new Acme_Demo_Setup_WXR_Parser_SimpleXML;
15
+ $result = $parser->parse( $file );
16
+
17
+ // If SimpleXML succeeds or this is an invalid WXR file then return the results
18
+ if ( ! is_wp_error( $result ) || 'SimpleXML_parse_error' != $result->get_error_code() )
19
+ return $result;
20
+ } else if ( extension_loaded( 'xml' ) ) {
21
+ $parser = new Acme_Demo_Setup_WXR_Parser_XML;
22
+ $result = $parser->parse( $file );
23
+
24
+ // If XMLParser succeeds or this is an invalid WXR file then return the results
25
+ if ( ! is_wp_error( $result ) || 'XML_parse_error' != $result->get_error_code() )
26
+ return $result;
27
+ }
28
+
29
+ // We have a malformed XML file, so display the error and fallthrough to regex
30
+ if ( isset($result) && defined('IMPORT_DEBUG') && IMPORT_DEBUG ) {
31
+ echo '<pre>';
32
+ if ( 'SimpleXML_parse_error' == $result->get_error_code() ) {
33
+ foreach ( $result->get_error_data() as $error )
34
+ echo $error->line . ':' . $error->column . ' ' . esc_html( $error->message ) . "\n";
35
+ } else if ( 'XML_parse_error' == $result->get_error_code() ) {
36
+ $error = $result->get_error_data();
37
+ echo $error[0] . ':' . $error[1] . ' ' . esc_html( $error[2] );
38
+ }
39
+ echo '</pre>';
40
+ echo '<p><strong>' . __( 'There was an error when reading this WXR file', 'wordpress-importer' ) . '</strong><br />';
41
+ echo __( 'Details are shown above. The importer will now try again with a different parser...', 'wordpress-importer' ) . '</p>';
42
+ }
43
+
44
+ // use regular expressions if nothing else available or this is bad XML
45
+ $parser = new Acme_Demo_Setup_WXR_Parser_Regex;
46
+ return $parser->parse( $file );
47
+ }
48
+ }
49
+
50
+ /**
51
+ * WXR Parser that makes use of the SimpleXML PHP extension.
52
+ */
53
+ class Acme_Demo_Setup_WXR_Parser_SimpleXML {
54
+ function parse( $file ) {
55
+ $authors = $posts = $categories = $tags = $terms = array();
56
+
57
+ $internal_errors = libxml_use_internal_errors(true);
58
+
59
+ $dom = new DOMDocument;
60
+ $old_value = null;
61
+ if ( function_exists( 'libxml_disable_entity_loader' ) ) {
62
+ $old_value = libxml_disable_entity_loader( true );
63
+ }
64
+ $success = $dom->loadXML( file_get_contents( $file ) );
65
+ if ( ! is_null( $old_value ) ) {
66
+ libxml_disable_entity_loader( $old_value );
67
+ }
68
+
69
+ if ( ! $success || isset( $dom->doctype ) ) {
70
+ return new WP_Error( 'SimpleXML_parse_error', __( 'There was an error when reading this WXR file', 'wordpress-importer' ), libxml_get_errors() );
71
+ }
72
+
73
+ $xml = simplexml_import_dom( $dom );
74
+ unset( $dom );
75
+
76
+ // halt if loading produces an error
77
+ if ( ! $xml )
78
+ return new WP_Error( 'SimpleXML_parse_error', __( 'There was an error when reading this WXR file', 'wordpress-importer' ), libxml_get_errors() );
79
+
80
+ $wxr_version = $xml->xpath('/rss/channel/wp:wxr_version');
81
+ if ( ! $wxr_version )
82
+ return new WP_Error( 'WXR_parse_error', __( 'This does not appear to be a WXR file, missing/invalid WXR version number', 'wordpress-importer' ) );
83
+
84
+ $wxr_version = (string) trim( $wxr_version[0] );
85
+ // confirm that we are dealing with the correct file format
86
+ if ( ! preg_match( '/^\d+\.\d+$/', $wxr_version ) )
87
+ return new WP_Error( 'WXR_parse_error', __( 'This does not appear to be a WXR file, missing/invalid WXR version number', 'wordpress-importer' ) );
88
+
89
+ $base_url = $xml->xpath('/rss/channel/wp:base_site_url');
90
+ $base_url = (string) trim( $base_url[0] );
91
+
92
+ $namespaces = $xml->getDocNamespaces();
93
+ if ( ! isset( $namespaces['wp'] ) )
94
+ $namespaces['wp'] = 'http://wordpress.org/export/1.1/';
95
+ if ( ! isset( $namespaces['excerpt'] ) )
96
+ $namespaces['excerpt'] = 'http://wordpress.org/export/1.1/excerpt/';
97
+
98
+ // grab authors
99
+ foreach ( $xml->xpath('/rss/channel/wp:author') as $author_arr ) {
100
+ $a = $author_arr->children( $namespaces['wp'] );
101
+ $login = (string) $a->author_login;
102
+ $authors[$login] = array(
103
+ 'author_id' => (int) $a->author_id,
104
+ 'author_login' => $login,
105
+ 'author_email' => (string) $a->author_email,
106
+ 'author_display_name' => (string) $a->author_display_name,
107
+ 'author_first_name' => (string) $a->author_first_name,
108
+ 'author_last_name' => (string) $a->author_last_name
109
+ );
110
+ }
111
+
112
+ // grab cats, tags and terms
113
+ foreach ( $xml->xpath('/rss/channel/wp:category') as $term_arr ) {
114
+ $t = $term_arr->children( $namespaces['wp'] );
115
+ $category = array(
116
+ 'term_id' => (int) $t->term_id,
117
+ 'category_nicename' => (string) $t->category_nicename,
118
+ 'category_parent' => (string) $t->category_parent,
119
+ 'cat_name' => (string) $t->cat_name,
120
+ 'category_description' => (string) $t->category_description
121
+ );
122
+
123
+ foreach ( $t->termmeta as $meta ) {
124
+ $category['termmeta'][] = array(
125
+ 'key' => (string) $meta->meta_key,
126
+ 'value' => (string) $meta->meta_value
127
+ );
128
+ }
129
+
130
+ $categories[] = $category;
131
+ }
132
+
133
+ foreach ( $xml->xpath('/rss/channel/wp:tag') as $term_arr ) {
134
+ $t = $term_arr->children( $namespaces['wp'] );
135
+ $tag = array(
136
+ 'term_id' => (int) $t->term_id,
137
+ 'tag_slug' => (string) $t->tag_slug,
138
+ 'tag_name' => (string) $t->tag_name,
139
+ 'tag_description' => (string) $t->tag_description
140
+ );
141
+
142
+ foreach ( $t->termmeta as $meta ) {
143
+ $tag['termmeta'][] = array(
144
+ 'key' => (string) $meta->meta_key,
145
+ 'value' => (string) $meta->meta_value
146
+ );
147
+ }
148
+
149
+ $tags[] = $tag;
150
+ }
151
+
152
+ foreach ( $xml->xpath('/rss/channel/wp:term') as $term_arr ) {
153
+ $t = $term_arr->children( $namespaces['wp'] );
154
+ $term = array(
155
+ 'term_id' => (int) $t->term_id,
156
+ 'term_taxonomy' => (string) $t->term_taxonomy,
157
+ 'slug' => (string) $t->term_slug,
158
+ 'term_parent' => (string) $t->term_parent,
159
+ 'term_name' => (string) $t->term_name,
160
+ 'term_description' => (string) $t->term_description
161
+ );
162
+
163
+ foreach ( $t->termmeta as $meta ) {
164
+ $term['termmeta'][] = array(
165
+ 'key' => (string) $meta->meta_key,
166
+ 'value' => (string) $meta->meta_value
167
+ );
168
+ }
169
+
170
+ $terms[] = $term;
171
+ }
172
+
173
+ // grab posts
174
+ foreach ( $xml->channel->item as $item ) {
175
+ $post = array(
176
+ 'post_title' => (string) $item->title,
177
+ 'guid' => (string) $item->guid,
178
+ );
179
+
180
+ $dc = $item->children( 'http://purl.org/dc/elements/1.1/' );
181
+ $post['post_author'] = (string) $dc->creator;
182
+
183
+ $content = $item->children( 'http://purl.org/rss/1.0/modules/content/' );
184
+ $excerpt = $item->children( $namespaces['excerpt'] );
185
+ $post['post_content'] = (string) $content->encoded;
186
+ $post['post_excerpt'] = (string) $excerpt->encoded;
187
+
188
+ $wp = $item->children( $namespaces['wp'] );
189
+ $post['post_id'] = (int) $wp->post_id;
190
+ $post['post_date'] = (string) $wp->post_date;
191
+ $post['post_date_gmt'] = (string) $wp->post_date_gmt;
192
+ $post['comment_status'] = (string) $wp->comment_status;
193
+ $post['ping_status'] = (string) $wp->ping_status;
194
+ $post['post_name'] = (string) $wp->post_name;
195
+ $post['status'] = (string) $wp->status;
196
+ $post['post_parent'] = (int) $wp->post_parent;
197
+ $post['menu_order'] = (int) $wp->menu_order;
198
+ $post['post_type'] = (string) $wp->post_type;
199
+ $post['post_password'] = (string) $wp->post_password;
200
+ $post['is_sticky'] = (int) $wp->is_sticky;
201
+
202
+ if ( isset($wp->attachment_url) )
203
+ $post['attachment_url'] = (string) $wp->attachment_url;
204
+
205
+ foreach ( $item->category as $c ) {
206
+ $att = $c->attributes();
207
+ if ( isset( $att['nicename'] ) )
208
+ $post['terms'][] = array(
209
+ 'name' => (string) $c,
210
+ 'slug' => (string) $att['nicename'],
211
+ 'domain' => (string) $att['domain']
212
+ );
213
+ }
214
+
215
+ foreach ( $wp->postmeta as $meta ) {
216
+ $post['postmeta'][] = array(
217
+ 'key' => (string) $meta->meta_key,
218
+ 'value' => (string) $meta->meta_value
219
+ );
220
+ }
221
+
222
+ foreach ( $wp->comment as $comment ) {
223
+ $meta = array();
224
+ if ( isset( $comment->commentmeta ) ) {
225
+ foreach ( $comment->commentmeta as $m ) {
226
+ $meta[] = array(
227
+ 'key' => (string) $m->meta_key,
228
+ 'value' => (string) $m->meta_value
229
+ );
230
+ }
231
+ }
232
+
233
+ $post['comments'][] = array(
234
+ 'comment_id' => (int) $comment->comment_id,
235
+ 'comment_author' => (string) $comment->comment_author,
236
+ 'comment_author_email' => (string) $comment->comment_author_email,
237
+ 'comment_author_IP' => (string) $comment->comment_author_IP,
238
+ 'comment_author_url' => (string) $comment->comment_author_url,
239
+ 'comment_date' => (string) $comment->comment_date,
240
+ 'comment_date_gmt' => (string) $comment->comment_date_gmt,
241
+ 'comment_content' => (string) $comment->comment_content,
242
+ 'comment_approved' => (string) $comment->comment_approved,
243
+ 'comment_type' => (string) $comment->comment_type,
244
+ 'comment_parent' => (string) $comment->comment_parent,
245
+ 'comment_user_id' => (int) $comment->comment_user_id,
246
+ 'commentmeta' => $meta,
247
+ );
248
+ }
249
+
250
+ $posts[] = $post;
251
+ }
252
+
253
+ return array(
254
+ 'authors' => $authors,
255
+ 'posts' => $posts,
256
+ 'categories' => $categories,
257
+ 'tags' => $tags,
258
+ 'terms' => $terms,
259
+ 'base_url' => $base_url,
260
+ 'version' => $wxr_version
261
+ );
262
+ }
263
+ }
264
+
265
+ /**
266
+ * WXR Parser that makes use of the XML Parser PHP extension.
267
+ */
268
+ class Acme_Demo_Setup_WXR_Parser_XML {
269
+ var $wp_tags = array(
270
+ 'wp:post_id', 'wp:post_date', 'wp:post_date_gmt', 'wp:comment_status', 'wp:ping_status', 'wp:attachment_url',
271
+ 'wp:status', 'wp:post_name', 'wp:post_parent', 'wp:menu_order', 'wp:post_type', 'wp:post_password',
272
+ 'wp:is_sticky', 'wp:term_id', 'wp:category_nicename', 'wp:category_parent', 'wp:cat_name', 'wp:category_description',
273
+ 'wp:tag_slug', 'wp:tag_name', 'wp:tag_description', 'wp:term_taxonomy', 'wp:term_parent',
274
+ 'wp:term_name', 'wp:term_description', 'wp:author_id', 'wp:author_login', 'wp:author_email', 'wp:author_display_name',
275
+ 'wp:author_first_name', 'wp:author_last_name',
276
+ );
277
+ var $wp_sub_tags = array(
278
+ 'wp:comment_id', 'wp:comment_author', 'wp:comment_author_email', 'wp:comment_author_url',
279
+ 'wp:comment_author_IP', 'wp:comment_date', 'wp:comment_date_gmt', 'wp:comment_content',
280
+ 'wp:comment_approved', 'wp:comment_type', 'wp:comment_parent', 'wp:comment_user_id',
281
+ );
282
+
283
+ function parse( $file ) {
284
+ $this->wxr_version = $this->in_post = $this->cdata = $this->data = $this->sub_data = $this->in_tag = $this->in_sub_tag = false;
285
+ $this->authors = $this->posts = $this->term = $this->category = $this->tag = array();
286
+
287
+ $xml = xml_parser_create( 'UTF-8' );
288
+ xml_parser_set_option( $xml, XML_OPTION_SKIP_WHITE, 1 );
289
+ xml_parser_set_option( $xml, XML_OPTION_CASE_FOLDING, 0 );
290
+ xml_set_object( $xml, $this );
291
+ xml_set_character_data_handler( $xml, 'cdata' );
292
+ xml_set_element_handler( $xml, 'tag_open', 'tag_close' );
293
+
294
+ if ( ! xml_parse( $xml, file_get_contents( $file ), true ) ) {
295
+ $current_line = xml_get_current_line_number( $xml );
296
+ $current_column = xml_get_current_column_number( $xml );
297
+ $error_code = xml_get_error_code( $xml );
298
+ $error_string = xml_error_string( $error_code );
299
+ return new WP_Error( 'XML_parse_error', 'There was an error when reading this WXR file', array( $current_line, $current_column, $error_string ) );
300
+ }
301
+ xml_parser_free( $xml );
302
+
303
+ if ( ! preg_match( '/^\d+\.\d+$/', $this->wxr_version ) )
304
+ return new WP_Error( 'WXR_parse_error', __( 'This does not appear to be a WXR file, missing/invalid WXR version number', 'wordpress-importer' ) );
305
+
306
+ return array(
307
+ 'authors' => $this->authors,
308
+ 'posts' => $this->posts,
309
+ 'categories' => $this->category,
310
+ 'tags' => $this->tag,
311
+ 'terms' => $this->term,
312
+ 'base_url' => $this->base_url,
313
+ 'version' => $this->wxr_version
314
+ );
315
+ }
316
+
317
+ function tag_open( $parse, $tag, $attr ) {
318
+ if ( in_array( $tag, $this->wp_tags ) ) {
319
+ $this->in_tag = substr( $tag, 3 );
320
+ return;
321
+ }
322
+
323
+ if ( in_array( $tag, $this->wp_sub_tags ) ) {
324
+ $this->in_sub_tag = substr( $tag, 3 );
325
+ return;
326
+ }
327
+
328
+ switch ( $tag ) {
329
+ case 'category':
330
+ if ( isset($attr['domain'], $attr['nicename']) ) {
331
+ $this->sub_data['domain'] = $attr['domain'];
332
+ $this->sub_data['slug'] = $attr['nicename'];
333
+ }
334
+ break;
335
+ case 'item': $this->in_post = true;
336
+ case 'title': if ( $this->in_post ) $this->in_tag = 'post_title'; break;
337
+ case 'guid': $this->in_tag = 'guid'; break;
338
+ case 'dc:creator': $this->in_tag = 'post_author'; break;
339
+ case 'content:encoded': $this->in_tag = 'post_content'; break;
340
+ case 'excerpt:encoded': $this->in_tag = 'post_excerpt'; break;
341
+
342
+ case 'wp:term_slug': $this->in_tag = 'slug'; break;
343
+ case 'wp:meta_key': $this->in_sub_tag = 'key'; break;
344
+ case 'wp:meta_value': $this->in_sub_tag = 'value'; break;
345
+ }
346
+ }
347
+
348
+ function cdata( $parser, $cdata ) {
349
+ if ( ! trim( $cdata ) )
350
+ return;
351
+
352
+ if ( false !== $this->in_tag || false !== $this->in_sub_tag ) {
353
+ $this->cdata .= $cdata;
354
+ } else {
355
+ $this->cdata .= trim( $cdata );
356
+ }
357
+ }
358
+
359
+ function tag_close( $parser, $tag ) {
360
+ switch ( $tag ) {
361
+ case 'wp:comment':
362
+ unset( $this->sub_data['key'], $this->sub_data['value'] ); // remove meta sub_data
363
+ if ( ! empty( $this->sub_data ) )
364
+ $this->data['comments'][] = $this->sub_data;
365
+ $this->sub_data = false;
366
+ break;
367
+ case 'wp:commentmeta':
368
+ $this->sub_data['commentmeta'][] = array(
369
+ 'key' => $this->sub_data['key'],
370
+ 'value' => $this->sub_data['value']
371
+ );
372
+ break;
373
+ case 'category':
374
+ if ( ! empty( $this->sub_data ) ) {
375
+ $this->sub_data['name'] = $this->cdata;
376
+ $this->data['terms'][] = $this->sub_data;
377
+ }
378
+ $this->sub_data = false;
379
+ break;
380
+ case 'wp:postmeta':
381
+ if ( ! empty( $this->sub_data ) )
382
+ $this->data['postmeta'][] = $this->sub_data;
383
+ $this->sub_data = false;
384
+ break;
385
+ case 'item':
386
+ $this->posts[] = $this->data;
387
+ $this->data = false;
388
+ break;
389
+ case 'wp:category':
390
+ case 'wp:tag':
391
+ case 'wp:term':
392
+ $n = substr( $tag, 3 );
393