Version Description
Download this release
Release Info
Developer | Nikschavan |
Plugin | Astra Starter Sites |
Version | 1.0.0 |
Comparing to | |
See all releases |
Version 1.0.0
- admin/class-astra-sites-admin.php +82 -0
- admin/view-astra-sites.php +228 -0
- assets/css/admin.css +164 -0
- assets/js/admin.js +694 -0
- astra-sites.php +23 -0
- classes/class-astra-sites.php +631 -0
- importers/class-astra-customizer-import.php +51 -0
- importers/class-astra-site-options-import.php +120 -0
- importers/class-astra-sites-helper.php +122 -0
- importers/class-widgets-importer.php +278 -0
- importers/wxr-importer/class-astra-wxr-importer.php +119 -0
- importers/wxr-importer/class-logger.php +136 -0
- importers/wxr-importer/class-wxr-importer.php +2299 -0
- readme.txt +26 -0
admin/class-astra-sites-admin.php
ADDED
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Astra Demo Importer Admin
|
4 |
+
*
|
5 |
+
* @package Astra Addon
|
6 |
+
*/
|
7 |
+
|
8 |
+
defined( 'ABSPATH' ) or exit;
|
9 |
+
|
10 |
+
/**
|
11 |
+
* Astra Demo Importer Admin
|
12 |
+
*
|
13 |
+
* @since 1.0.0
|
14 |
+
*/
|
15 |
+
class Astra_Sites_Admin {
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Instance of Astra_Sites_Admin
|
19 |
+
*
|
20 |
+
* @since 1.0.0
|
21 |
+
* @var Astra_Sites_Admin
|
22 |
+
*/
|
23 |
+
private static $_instance = null;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Instanciate Astra_Sites_Admin
|
27 |
+
*
|
28 |
+
* @since 1.0.0
|
29 |
+
* @return (Object) Astra_Sites_Admin
|
30 |
+
*/
|
31 |
+
public static function instance() {
|
32 |
+
if ( ! isset( self::$_instance ) ) {
|
33 |
+
self::$_instance = new self;
|
34 |
+
}
|
35 |
+
|
36 |
+
return self::$_instance;
|
37 |
+
}
|
38 |
+
|
39 |
+
/**
|
40 |
+
* Constructor
|
41 |
+
*
|
42 |
+
* @since 1.0.0
|
43 |
+
*/
|
44 |
+
private function __construct() {
|
45 |
+
|
46 |
+
add_filter( 'astra_menu_options', array( $this, 'menu' ) );
|
47 |
+
add_action( 'astra_menu_astra_sites_action', array( $this, 'view_demos' ) );
|
48 |
+
|
49 |
+
}
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Register admin menu for demo importer
|
53 |
+
*
|
54 |
+
* @since 1.0.0
|
55 |
+
*
|
56 |
+
* @param (Array) $actions Previously registered tabs menus.
|
57 |
+
*
|
58 |
+
* @return (Array) registered tabs menus in Astra menu.
|
59 |
+
*/
|
60 |
+
public function menu( $actions ) {
|
61 |
+
|
62 |
+
$actions['astra-sites'] = array(
|
63 |
+
'label' => __( 'Astra Sites', 'astra-sites' ),
|
64 |
+
'show' => ! is_network_admin(),
|
65 |
+
);
|
66 |
+
|
67 |
+
return $actions;
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* View Astra Sites
|
72 |
+
*
|
73 |
+
* @since 1.0.0
|
74 |
+
*/
|
75 |
+
public function view_demos() {
|
76 |
+
|
77 |
+
include ASTRA_SITES_DIR . 'admin/view-astra-sites.php';
|
78 |
+
}
|
79 |
+
|
80 |
+
}
|
81 |
+
|
82 |
+
Astra_Sites_Admin::instance();
|
admin/view-astra-sites.php
ADDED
@@ -0,0 +1,228 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Astra Demo View.
|
4 |
+
*
|
5 |
+
* @package Astra Addon
|
6 |
+
*/
|
7 |
+
|
8 |
+
defined( 'ABSPATH' ) or exit;
|
9 |
+
|
10 |
+
// Enqueue scripts.
|
11 |
+
wp_enqueue_script( 'astra-sites-admin' );
|
12 |
+
wp_enqueue_style( 'astra-sites-admin' );
|
13 |
+
|
14 |
+
// Load demo importer markup.
|
15 |
+
$all_demos = Astra_Sites::get_astra_all_demos();
|
16 |
+
|
17 |
+
do_action( 'astra_sites_before_site_grid', $all_demos );
|
18 |
+
|
19 |
+
if ( count( $all_demos ) > 0 ) {
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Initial Demo List
|
23 |
+
*
|
24 |
+
* Generated though PHP
|
25 |
+
*/
|
26 |
+
?>
|
27 |
+
<div class="wrap">
|
28 |
+
|
29 |
+
<div class="wp-filter hide-if-no-js">
|
30 |
+
|
31 |
+
<ul class="filter-links">
|
32 |
+
|
33 |
+
<li><a href="#" data-sort="all" class="current" data-id="all"><?php esc_html_e( 'All', 'astra-sites' ); ?></a></li>
|
34 |
+
|
35 |
+
<?php foreach ( Astra_Sites::get_demo_categories() as $key => $category ) { ?>
|
36 |
+
<li>
|
37 |
+
<a href="#"
|
38 |
+
data-sort="<?php echo esc_attr( $category['slug'] ); ?>"
|
39 |
+
data-id="<?php echo esc_attr( $category['id'] ); ?>">
|
40 |
+
<?php echo esc_attr( $category['name'] ); ?>
|
41 |
+
</a>
|
42 |
+
</li>
|
43 |
+
<?php } ?>
|
44 |
+
</ul>
|
45 |
+
|
46 |
+
<div class="search-form">
|
47 |
+
<label class="screen-reader-text" for="wp-filter-search-input"><?php esc_html_e( 'Search Sites', 'astra-sites' ); ?></label>
|
48 |
+
<input placeholder="<?php esc_attr_e( 'Search Sites...', 'astra-sites' ); ?>" type="search" aria-describedby="live-search-desc" id="wp-filter-search-input" class="wp-filter-search">
|
49 |
+
</div>
|
50 |
+
|
51 |
+
</div>
|
52 |
+
|
53 |
+
<span class="spinner"></span>
|
54 |
+
|
55 |
+
<div class="theme-browser rendered">
|
56 |
+
<div class="themes wp-clearfix">
|
57 |
+
|
58 |
+
<?php foreach ( $all_demos as $key => $demo ) { ?>
|
59 |
+
|
60 |
+
<div class="theme astra-theme" tabindex="0" aria-describedby="astra-theme-action astra-theme-name"
|
61 |
+
data-demo-id="<?php echo esc_attr( $demo['id'] ); ?>"
|
62 |
+
data-demo-type="<?php echo esc_attr( $demo['astra_demo_type'] ); ?>"
|
63 |
+
data-demo-url="<?php echo esc_url( $demo['astra_demo_url'] ); ?>"
|
64 |
+
data-demo-api="<?php echo esc_url( $demo['demo_api'] ); ?>"
|
65 |
+
data-screenshot="<?php echo esc_url( $demo['featured_image_url'] ); ?>"
|
66 |
+
data-demo-name="<?php echo esc_attr( $demo['title'] ); ?>"
|
67 |
+
data-demo-slug="<?php echo esc_attr( $demo['slug'] ); ?>"
|
68 |
+
data-content="<?php echo esc_attr( $demo['content'] ); ?>"
|
69 |
+
data-required-plugins="<?php echo esc_attr( $demo['required_plugins'] ); ?>">
|
70 |
+
|
71 |
+
<?php if ( 'premium' === $demo['astra_demo_type'] ) { ?>
|
72 |
+
<span class="demo-type <?php echo esc_attr( $demo['astra_demo_type'] ); ?>"><?php echo esc_attr( $demo['astra_demo_type'] ); ?></span>
|
73 |
+
<?php } ?>
|
74 |
+
|
75 |
+
<div class="theme-screenshot">
|
76 |
+
<?php if ( ! empty( $demo['featured_image_url'] ) ) { ?>
|
77 |
+
<img src="<?php echo esc_attr( $demo['featured_image_url'] ); ?>" alt="">
|
78 |
+
<?php } ?>
|
79 |
+
</div>
|
80 |
+
|
81 |
+
<a href="<?php echo esc_url( $demo['astra_demo_url'] ); ?>" target="_blank">
|
82 |
+
<span class="more-details" id="astra-theme-action"><?php esc_html_e( 'Details & Preview', 'astra-sites' ); ?></span>
|
83 |
+
</a>
|
84 |
+
|
85 |
+
<h3 class="theme-name" id="astra-theme-name"><?php echo esc_attr( $demo['title'] ); ?></h3>
|
86 |
+
<div class="theme-actions">
|
87 |
+
<button class="button preview install-theme-preview"><?php esc_html_e( 'Preview', 'astra-sites' ); ?></button>
|
88 |
+
</div>
|
89 |
+
</div>
|
90 |
+
|
91 |
+
<?php } ?>
|
92 |
+
|
93 |
+
</div>
|
94 |
+
</div>
|
95 |
+
|
96 |
+
</div>
|
97 |
+
|
98 |
+
<?php
|
99 |
+
/**
|
100 |
+
* Regenerated Demo List
|
101 |
+
*
|
102 |
+
* Generated though JS after search demo, filter demo etc.
|
103 |
+
*/
|
104 |
+
?>
|
105 |
+
<script type="text/template" id="tmpl-astra-single-demo">
|
106 |
+
<div class="theme astra-theme" tabindex="0" aria-describedby="astra-theme-action astra-theme-name"
|
107 |
+
data-demo-id="{{{data.id}}}"
|
108 |
+
data-demo-type="{{{data.astra_demo_type}}}"
|
109 |
+
data-demo-url="{{{data.astra_demo_url}}}"
|
110 |
+
data-demo-api="{{{data.demo_api}}}"
|
111 |
+
data-demo-name="{{{data.demo_name}}}"
|
112 |
+
data-demo-slug="{{{data.slug}}}"
|
113 |
+
data-screenshot="{{{data.screenshot}}}"
|
114 |
+
data-content="{{{data.content}}}"
|
115 |
+
data-required-plugins="{{data.required_plugins}}">
|
116 |
+
|
117 |
+
<span class="demo-type {{{data.astra_demo_type}}}">{{{data.astra_demo_type}}}</span>
|
118 |
+
|
119 |
+
<div class="theme-screenshot">
|
120 |
+
<# if ( data.screenshot.length ) { #>
|
121 |
+
<img src="{{{data.screenshot}}}" alt="">
|
122 |
+
<# } #>
|
123 |
+
</div>
|
124 |
+
|
125 |
+
<a href="{{{data.astra_demo_url}}}" target="_blank">
|
126 |
+
<span class="more-details" id="astra-theme-action"><?php esc_html_e( 'Details & Preview', 'astra-sites' ); ?></span>
|
127 |
+
</a>
|
128 |
+
|
129 |
+
<h3 class="theme-name" id="astra-theme-name">{{{data.demo_name}}}</h3>
|
130 |
+
|
131 |
+
<div class="theme-actions">
|
132 |
+
<button class="button preview install-theme-preview"><?php esc_html_e( 'Preview', 'astra-sites' ); ?></button>
|
133 |
+
|
134 |
+
</div>
|
135 |
+
|
136 |
+
</div>
|
137 |
+
</script>
|
138 |
+
|
139 |
+
<?php
|
140 |
+
/**
|
141 |
+
* Single Demo Preview
|
142 |
+
*/
|
143 |
+
?>
|
144 |
+
<script type="text/template" id="tmpl-astra-demo-preview">
|
145 |
+
<div class="astra-sites-preview theme-install-overlay wp-full-overlay expanded">
|
146 |
+
<div class="wp-full-overlay-sidebar">
|
147 |
+
<div class="wp-full-overlay-header"
|
148 |
+
data-demo-id="{{{data.id}}}"
|
149 |
+
data-demo-type="{{{data.astra_demo_type}}}"
|
150 |
+
data-demo-url="{{{data.astra_demo_url}}}"
|
151 |
+
data-demo-api="{{{data.demo_api}}}"
|
152 |
+
data-demo-name="{{{data.demo_name}}}"
|
153 |
+
data-demo-slug="{{{data.slug}}}"
|
154 |
+
data-screenshot="{{{data.screenshot}}}"
|
155 |
+
data-content="{{{data.content}}}"
|
156 |
+
data-required-plugins="{{data.required_plugins}}">
|
157 |
+
<button class="close-full-overlay"><span class="screen-reader-text"><?php esc_html_e( 'Close', 'astra-sites' ); ?></span></button>
|
158 |
+
<button class="previous-theme"><span class="screen-reader-text"><?php esc_html_e( 'Previous', 'astra-sites' ); ?></span></button>
|
159 |
+
<button class="next-theme"><span class="screen-reader-text"><?php esc_html_e( 'Next', 'astra-sites' ); ?></span></button>
|
160 |
+
<a class="button hide-if-no-customize astra-demo-import" href="#" data-import="disabled"><?php esc_html_e( 'Install Plugins', 'astra-sites' ); ?></a>
|
161 |
+
|
162 |
+
</div>
|
163 |
+
<div class="wp-full-overlay-sidebar-content">
|
164 |
+
<div class="install-theme-info">
|
165 |
+
|
166 |
+
<span class="demo-type {{{data.astra_demo_type}}}">{{{data.astra_demo_type}}}</span>
|
167 |
+
<h3 class="theme-name">{{{data.demo_name}}}</h3>
|
168 |
+
|
169 |
+
<# if ( data.screenshot.length ) { #>
|
170 |
+
<img class="theme-screenshot" src="{{{data.screenshot}}}" alt="">
|
171 |
+
<# } #>
|
172 |
+
|
173 |
+
<div class="theme-details">
|
174 |
+
{{{data.content}}}
|
175 |
+
</div>
|
176 |
+
<a href="#" class="theme-details-read-more"><?php _e( 'Read more', 'astra-sites' ); ?> …</a>
|
177 |
+
|
178 |
+
<div class="required-plugins-wrap">
|
179 |
+
<h4><?php _e( 'Required Plugins', 'astra-sites' ); ?> </h4>
|
180 |
+
<div class="required-plugins"></div>
|
181 |
+
</div>
|
182 |
+
</div>
|
183 |
+
</div>
|
184 |
+
|
185 |
+
<div class="wp-full-overlay-footer">
|
186 |
+
<div class="footer-import-button-wrap">
|
187 |
+
<a class="button button-hero hide-if-no-customize astra-demo-import" href="#" data-import="disabled">
|
188 |
+
<?php esc_html_e( 'Install Plugins', 'astra-sites' ); ?>
|
189 |
+
</a>
|
190 |
+
</div>
|
191 |
+
<button type="button" class="collapse-sidebar button" aria-expanded="true"
|
192 |
+
aria-label="Collapse Sidebar">
|
193 |
+
<span class="collapse-sidebar-arrow"></span>
|
194 |
+
<span class="collapse-sidebar-label"><?php esc_html_e( 'Collapse', 'astra-sites' ); ?></span>
|
195 |
+
</button>
|
196 |
+
</div>
|
197 |
+
</div>
|
198 |
+
<div class="wp-full-overlay-main">
|
199 |
+
<iframe src="{{{data.astra_demo_url}}}" title="<?php esc_attr_e( 'Preview', 'astra-sites' ); ?>"></iframe>
|
200 |
+
</div>
|
201 |
+
</div>
|
202 |
+
</script>
|
203 |
+
|
204 |
+
<?php
|
205 |
+
|
206 |
+
// Load demo importer welcome.
|
207 |
+
} else {
|
208 |
+
?>
|
209 |
+
<div class="no-themes">
|
210 |
+
<?php
|
211 |
+
|
212 |
+
/* translators: %1$s & %2$s are a Demo API URL */
|
213 |
+
printf( __( '<p> It seems the demo data server, <i><a href="%1$s">%2$s</a></i> is unreachable from your site.</p>', 'astra-sites' ) , esc_url( Astra_Sites::$api_url ), esc_url( Astra_Sites::$api_url ) );
|
214 |
+
|
215 |
+
_e( '<p class="left-margin"> 1. Sometimes, simple page reload fixes any temporary issues. No kidding!</p>', 'astra-sites' );
|
216 |
+
|
217 |
+
_e( '<p class="left-margin"> 2. If that does not work, you will need to talk to your server administrator and check if demo server is being blocked by the firewall!</p>', 'astra-sites' );
|
218 |
+
|
219 |
+
/* translators: %1$s is a support link */
|
220 |
+
printf( __( '<p>If that does not help, please open up a <a href="%1$s" target="_blank">Support Ticket</a> and we will be glad take a closer look for you.</p>', 'astra-sites' ), esc_url( 'https://wpastra.com/support/' ) );
|
221 |
+
?>
|
222 |
+
|
223 |
+
</div>
|
224 |
+
</p>
|
225 |
+
<?php
|
226 |
+
}// End if().
|
227 |
+
|
228 |
+
do_action( 'astra_sites_after_site_grid', $all_demos );
|
assets/css/admin.css
ADDED
@@ -0,0 +1,164 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
.theme-browser .theme.focus .theme-actions,
|
2 |
+
.theme-browser .theme:focus .theme-actions,
|
3 |
+
.theme-browser .theme:hover .theme-actions {
|
4 |
+
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";
|
5 |
+
opacity: 1
|
6 |
+
}
|
7 |
+
.theme-browser .theme .theme-screenshot:after {
|
8 |
+
content: "";
|
9 |
+
display: block;
|
10 |
+
padding-top: 66.66666%
|
11 |
+
}
|
12 |
+
|
13 |
+
.wrap .demo-type {
|
14 |
+
position: absolute;
|
15 |
+
z-index: 1;
|
16 |
+
color: #fff;
|
17 |
+
padding: 0.5em 1em;
|
18 |
+
top: -0.5em;
|
19 |
+
left: -0.5em;
|
20 |
+
text-transform: uppercase;
|
21 |
+
}
|
22 |
+
.wrap .demo-type.premium {
|
23 |
+
background: #0073aa;
|
24 |
+
}
|
25 |
+
.wrap .demo-type.free {
|
26 |
+
display: none;
|
27 |
+
}
|
28 |
+
|
29 |
+
.theme {
|
30 |
+
position: relative;
|
31 |
+
}
|
32 |
+
.wrap .astra-sites-preview .demo-type.premium {
|
33 |
+
display: block;
|
34 |
+
display: none;
|
35 |
+
position: relative;
|
36 |
+
margin: 0.5em 0em 1em 0em;
|
37 |
+
top: 0;
|
38 |
+
left: 0;
|
39 |
+
text-align: center;
|
40 |
+
}
|
41 |
+
|
42 |
+
.theme-details-read-more.open {
|
43 |
+
margin: 0.5em 0 0 0;
|
44 |
+
}
|
45 |
+
|
46 |
+
.astra-sites-preview .theme-screenshot {
|
47 |
+
width: 100%;
|
48 |
+
}
|
49 |
+
|
50 |
+
/**
|
51 |
+
* Required Plugins
|
52 |
+
*/
|
53 |
+
.required-plugins.loading {
|
54 |
+
text-align: center;
|
55 |
+
}
|
56 |
+
.required-plugins button {
|
57 |
+
float: right;
|
58 |
+
}
|
59 |
+
.required-plugins .plugin-card {
|
60 |
+
float: none;
|
61 |
+
width: 100%;
|
62 |
+
border: none;
|
63 |
+
margin: 0 0 0.8em 0;
|
64 |
+
display: flex;
|
65 |
+
justify-content: space-between;
|
66 |
+
align-items: center;
|
67 |
+
transition: background ease 0.8s;
|
68 |
+
}
|
69 |
+
.required-plugins .plugin-card.plugin-card-update-failed {
|
70 |
+
flex-wrap: wrap;
|
71 |
+
}
|
72 |
+
.required-plugins .spinner {
|
73 |
+
float: none;
|
74 |
+
}
|
75 |
+
|
76 |
+
.expanded .wp-full-overlay-footer {
|
77 |
+
height: 100px;
|
78 |
+
}
|
79 |
+
|
80 |
+
.wp-full-overlay-footer .view-site,
|
81 |
+
.wp-full-overlay-footer .go-pro,
|
82 |
+
.wp-full-overlay-footer .astra-demo-import {
|
83 |
+
width: 100%;
|
84 |
+
text-align: center;
|
85 |
+
}
|
86 |
+
|
87 |
+
.wp-full-overlay-footer .installing:before {
|
88 |
+
vertical-align: text-bottom;
|
89 |
+
}
|
90 |
+
|
91 |
+
.required-plugins-wrap h4 {
|
92 |
+
margin: 1em 0 0.5em 0;
|
93 |
+
padding: 0.5em 0;
|
94 |
+
transition: all ease 0.3s;
|
95 |
+
}
|
96 |
+
|
97 |
+
/**
|
98 |
+
* Read more link
|
99 |
+
*/
|
100 |
+
.wp-core-ui .theme-details-read-more:focus,
|
101 |
+
.wp-core-ui .theme-details-read-more:hover {
|
102 |
+
outline: none;
|
103 |
+
box-shadow: none;
|
104 |
+
}
|
105 |
+
.wp-core-ui .theme-details-read-more {
|
106 |
+
margin: 10px 0;
|
107 |
+
display: none;
|
108 |
+
text-decoration: none;
|
109 |
+
}
|
110 |
+
|
111 |
+
/**
|
112 |
+
* Go pro.
|
113 |
+
*/
|
114 |
+
.wp-core-ui .go-pro.button[disabled] {
|
115 |
+
background-color: #fcb92c !important;
|
116 |
+
color: white !important;
|
117 |
+
box-shadow: 1px 0 #eab23a !important;
|
118 |
+
text-shadow: 1px 0 #6b4e13 !important;
|
119 |
+
border-color: #e2a932 !important;
|
120 |
+
cursor: pointer;
|
121 |
+
}
|
122 |
+
.wp-core-ui .view-site .dashicons,
|
123 |
+
.wp-core-ui .go-pro .dashicons {
|
124 |
+
font-size: 1rem;
|
125 |
+
vertical-align: middle;
|
126 |
+
}
|
127 |
+
|
128 |
+
/**
|
129 |
+
* Errors
|
130 |
+
*/
|
131 |
+
.plugin-card-update-failed .notice {
|
132 |
+
margin-top: 1.5em;
|
133 |
+
}
|
134 |
+
|
135 |
+
.no-themes {
|
136 |
+
margin-top: 40px;
|
137 |
+
}
|
138 |
+
|
139 |
+
.no-themes p {
|
140 |
+
font-size: 15px;
|
141 |
+
}
|
142 |
+
|
143 |
+
.no-themes .left-margin {
|
144 |
+
margin-left: 30px;
|
145 |
+
}
|
146 |
+
|
147 |
+
/**
|
148 |
+
*
|
149 |
+
*/
|
150 |
+
.astra-sites-preview .wp-full-overlay-sidebar-content {
|
151 |
+
bottom: 100px;
|
152 |
+
}
|
153 |
+
|
154 |
+
.footer-import-button-wrap {
|
155 |
+
padding: 10px 20px;
|
156 |
+
}
|
157 |
+
|
158 |
+
.footer-import-button-wrap .button {
|
159 |
+
margin: 0;
|
160 |
+
}
|
161 |
+
|
162 |
+
.astra-sites-preview.expanded .wp-full-overlay-footer {
|
163 |
+
left: initial;
|
164 |
+
}
|
assets/js/admin.js
ADDED
@@ -0,0 +1,694 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
jQuery(document).ready(function ($) {
|
2 |
+
resetPagedCount();
|
3 |
+
});
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Enable Demo Import Button.
|
7 |
+
*/
|
8 |
+
function enable_demo_import_button( type = 'free' ) {
|
9 |
+
|
10 |
+
if( 'free' === type ) {
|
11 |
+
|
12 |
+
// Get initial required plugins count.
|
13 |
+
var remaining = parseInt( astraDemo.requiredPluginsCount ) || 0;
|
14 |
+
|
15 |
+
// Enable demo import button.
|
16 |
+
if( 0 >= remaining ) {
|
17 |
+
|
18 |
+
jQuery('.astra-demo-import')
|
19 |
+
.removeAttr('data-import')
|
20 |
+
.addClass('button-primary')
|
21 |
+
.text( astraDemo.strings.importDemo );
|
22 |
+
}
|
23 |
+
} else {
|
24 |
+
|
25 |
+
var demo_slug = jQuery('.wp-full-overlay-header').attr('data-demo-slug');
|
26 |
+
|
27 |
+
jQuery('.astra-demo-import')
|
28 |
+
.addClass('go-pro button-primary')
|
29 |
+
.removeClass('astra-demo-import')
|
30 |
+
.attr('target', '_blank')
|
31 |
+
.attr('href', astraDemo.getProURL + demo_slug )
|
32 |
+
.text( astraDemo.getProText )
|
33 |
+
.append('<i class="dashicons dashicons-external"></i>');
|
34 |
+
}
|
35 |
+
}
|
36 |
+
|
37 |
+
function resetPagedCount() {
|
38 |
+
categoryId = jQuery('.filter-links li .current').data('id');
|
39 |
+
jQuery('body').attr('data-astra-demo-paged', '1');
|
40 |
+
jQuery('body').attr('data-astra-site-category', categoryId);
|
41 |
+
jQuery('body').attr('data-astra-demo-search', '');
|
42 |
+
jQuery('body').attr('data-scrolling', false);
|
43 |
+
jQuery('body').attr( 'data-required-plugins', 0 )
|
44 |
+
}
|
45 |
+
|
46 |
+
function updatedPagedCount() {
|
47 |
+
paged = parseInt(jQuery('body').attr('data-astra-demo-paged'));
|
48 |
+
jQuery('body').attr('data-astra-demo-paged', paged + 1);
|
49 |
+
window.setTimeout(function () {
|
50 |
+
jQuery('body').data('scrolling', false);
|
51 |
+
}, 800);
|
52 |
+
}
|
53 |
+
|
54 |
+
jQuery(document).scroll(function (event) {
|
55 |
+
var scrollDistance = jQuery(window).scrollTop();
|
56 |
+
|
57 |
+
var themesBottom = Math.abs(jQuery(window).height() - jQuery('.themes').offset().top - jQuery('.themes').height());
|
58 |
+
themesBottom = themesBottom * 20 / 100;
|
59 |
+
|
60 |
+
ajaxLoading = jQuery('body').data('scrolling');
|
61 |
+
|
62 |
+
if (scrollDistance > themesBottom && ajaxLoading == false) {
|
63 |
+
updatedPagedCount();
|
64 |
+
jQuery('body').data('scrolling', true);
|
65 |
+
body = jQuery('body');
|
66 |
+
id = body.attr('data-astra-site-category');
|
67 |
+
search = body.attr('data-astra-demo-search');
|
68 |
+
paged = body.attr('data-astra-demo-paged');
|
69 |
+
|
70 |
+
if (search !== '') {
|
71 |
+
id = '';
|
72 |
+
} else {
|
73 |
+
search = '';
|
74 |
+
}
|
75 |
+
|
76 |
+
jQuery('.no-themes').remove();
|
77 |
+
|
78 |
+
jQuery.ajax({
|
79 |
+
url: astraDemo.ajaxurl,
|
80 |
+
type: 'POST',
|
81 |
+
dataType: 'json',
|
82 |
+
data: {
|
83 |
+
action: 'astra-list-sites',
|
84 |
+
id: id,
|
85 |
+
paged: paged,
|
86 |
+
search: search
|
87 |
+
},
|
88 |
+
})
|
89 |
+
.done(function (demos) {
|
90 |
+
jQuery('body').removeClass('loading-content');
|
91 |
+
renderDemoGrid(demos);
|
92 |
+
})
|
93 |
+
.fail(function () {
|
94 |
+
jQuery('body').removeClass('loading-content');
|
95 |
+
jQuery('.spinner').after('<p class="no-themes" style="display:block;">'+astraDemo.strings.responseError+'</p>');
|
96 |
+
});
|
97 |
+
|
98 |
+
}
|
99 |
+
});
|
100 |
+
|
101 |
+
/**
|
102 |
+
* Individual Site Preview
|
103 |
+
*
|
104 |
+
* On click on image, more link & preview button.
|
105 |
+
*/
|
106 |
+
jQuery(document).on('click', '.theme-browser .theme-screenshot, .theme-browser .more-details, .theme-browser .install-theme-preview', function (event) {
|
107 |
+
event.preventDefault();
|
108 |
+
|
109 |
+
$this = jQuery(this).parents('.theme');
|
110 |
+
$this.addClass('theme-preview-on');
|
111 |
+
|
112 |
+
renderDemoPreview($this);
|
113 |
+
});
|
114 |
+
|
115 |
+
jQuery(document).on('click', '.close-full-overlay', function (event) {
|
116 |
+
event.preventDefault();
|
117 |
+
|
118 |
+
jQuery('.theme-install-overlay').css('display', 'none');
|
119 |
+
jQuery('.theme-install-overlay').remove();
|
120 |
+
jQuery('.theme-preview-on').removeClass('theme-preview-on');
|
121 |
+
});
|
122 |
+
|
123 |
+
jQuery(document).on('click', '.next-theme', function (event) {
|
124 |
+
event.preventDefault();
|
125 |
+
currentDemo = jQuery('.theme-preview-on')
|
126 |
+
currentDemo.removeClass('theme-preview-on');
|
127 |
+
nextDemo = currentDemo.nextAll('.theme');
|
128 |
+
nextDemo.addClass('theme-preview-on');
|
129 |
+
|
130 |
+
renderDemoPreview( nextDemo );
|
131 |
+
|
132 |
+
});
|
133 |
+
|
134 |
+
jQuery(document).on('click', '.previous-theme', function (event) {
|
135 |
+
event.preventDefault();
|
136 |
+
|
137 |
+
currentDemo = jQuery('.theme-preview-on');
|
138 |
+
currentDemo.removeClass('theme-preview-on');
|
139 |
+
prevDemo = currentDemo.prevAll('.theme');
|
140 |
+
prevDemo.addClass('theme-preview-on');
|
141 |
+
|
142 |
+
renderDemoPreview(prevDemo);
|
143 |
+
});
|
144 |
+
|
145 |
+
/**
|
146 |
+
* Click handler for plugin installs in plugin install view.
|
147 |
+
*
|
148 |
+
* @since 4.6.0
|
149 |
+
*
|
150 |
+
* @param {Event} event Event interface.
|
151 |
+
*/
|
152 |
+
jQuery(document).on('click', '.install-now', function (event) {
|
153 |
+
event.preventDefault();
|
154 |
+
|
155 |
+
var $button = jQuery( event.target ),
|
156 |
+
$document = jQuery(document);
|
157 |
+
|
158 |
+
if ( $button.hasClass( 'updating-message' ) || $button.hasClass( 'button-disabled' ) ) {
|
159 |
+
return;
|
160 |
+
}
|
161 |
+
|
162 |
+
if ( wp.updates.shouldRequestFilesystemCredentials && ! wp.updates.ajaxLocked ) {
|
163 |
+
wp.updates.requestFilesystemCredentials( event );
|
164 |
+
|
165 |
+
$document.on( 'credential-modal-cancel', function() {
|
166 |
+
var $message = $( '.install-now.updating-message' );
|
167 |
+
|
168 |
+
$message
|
169 |
+
.removeClass( 'updating-message' )
|
170 |
+
.text( wp.updates.l10n.installNow );
|
171 |
+
|
172 |
+
wp.a11y.speak( wp.updates.l10n.updateCancel, 'polite' );
|
173 |
+
} );
|
174 |
+
}
|
175 |
+
|
176 |
+
wp.updates.installPlugin( {
|
177 |
+
slug: $button.data( 'slug' )
|
178 |
+
} );
|
179 |
+
|
180 |
+
} );
|
181 |
+
|
182 |
+
jQuery(document).on( 'wp-plugin-install-error', function( event, response ) {
|
183 |
+
|
184 |
+
var $message = jQuery( '.plugin-card-' + response.slug ).find( '.install-now' );
|
185 |
+
|
186 |
+
$message.removeClass( 'button-disabled' )
|
187 |
+
.addClass( 'button-primary' )
|
188 |
+
.html( wp.updates.l10n.installNow );
|
189 |
+
|
190 |
+
});
|
191 |
+
|
192 |
+
jQuery(document).on( 'wp-plugin-install-success', function( event, response ) {
|
193 |
+
event.preventDefault();
|
194 |
+
|
195 |
+
var $message = jQuery( '.plugin-card-' + response.slug ).find( '.install-now' );
|
196 |
+
|
197 |
+
// Transform the 'Install' button into an 'Activate' button.
|
198 |
+
var $init = $message.data('init');
|
199 |
+
|
200 |
+
$message.removeClass( 'install-now installed button-disabled updated-message' )
|
201 |
+
.addClass('updating-message')
|
202 |
+
.html( astraDemo.strings.btnActivating );
|
203 |
+
|
204 |
+
// WordPress adds "Activate" button after waiting for 1000ms. So we will run our activation after that.
|
205 |
+
setTimeout( function() {
|
206 |
+
|
207 |
+
jQuery.ajax({
|
208 |
+
url: astraDemo.ajaxurl,
|
209 |
+
type: 'POST',
|
210 |
+
dataType: 'json',
|
211 |
+
data: {
|
212 |
+
'action' : 'astra-required-plugin-activate',
|
213 |
+
'init' : $init
|
214 |
+
},
|
215 |
+
})
|
216 |
+
.done(function (result) {
|
217 |
+
|
218 |
+
if( result.success ) {
|
219 |
+
$message.removeClass( 'button-primary activate-now updating-message' )
|
220 |
+
.attr('disabled', 'disabled')
|
221 |
+
.addClass('disabled')
|
222 |
+
.text( astraDemo.strings.btnActive );
|
223 |
+
|
224 |
+
// Enable Demo Import Button
|
225 |
+
astraDemo.requiredPluginsCount--;
|
226 |
+
enable_demo_import_button();
|
227 |
+
}
|
228 |
+
});
|
229 |
+
|
230 |
+
}, 1000 );
|
231 |
+
|
232 |
+
});
|
233 |
+
|
234 |
+
|
235 |
+
/**
|
236 |
+
* Click handler for plugin installs in plugin install view.
|
237 |
+
*
|
238 |
+
* @since 4.6.0
|
239 |
+
*
|
240 |
+
* @param {Event} event Event interface.
|
241 |
+
*/
|
242 |
+
jQuery(document).on('click', '.activate-now', function (event) {
|
243 |
+
event.preventDefault();
|
244 |
+
|
245 |
+
var $button = jQuery( event.target ),
|
246 |
+
$init = $button.data( 'init' );
|
247 |
+
|
248 |
+
if ( $button.hasClass( 'updating-message' ) || $button.hasClass( 'button-disabled' ) ) {
|
249 |
+
return;
|
250 |
+
}
|
251 |
+
|
252 |
+
$button.addClass( 'updating-message' )
|
253 |
+
.html( astraDemo.strings.btnActivating );
|
254 |
+
|
255 |
+
jQuery.ajax({
|
256 |
+
url: astraDemo.ajaxurl,
|
257 |
+
type: 'POST',
|
258 |
+
dataType: 'json',
|
259 |
+
data: {
|
260 |
+
'action' : 'astra-required-plugin-activate',
|
261 |
+
'init' : $init
|
262 |
+
},
|
263 |
+
})
|
264 |
+
.done(function (result) {
|
265 |
+
|
266 |
+
if( result.success ) {
|
267 |
+
$button.removeClass( 'button-primary activate-now updating-message' )
|
268 |
+
.attr('disabled', 'disabled')
|
269 |
+
.addClass('disabled')
|
270 |
+
.text( astraDemo.strings.btnActive );
|
271 |
+
|
272 |
+
// Enable Demo Import Button
|
273 |
+
astraDemo.requiredPluginsCount--;
|
274 |
+
enable_demo_import_button();
|
275 |
+
}
|
276 |
+
|
277 |
+
})
|
278 |
+
.fail(function () {
|
279 |
+
});
|
280 |
+
|
281 |
+
} );
|
282 |
+
|
283 |
+
function renderDemoPreview(anchor) {
|
284 |
+
|
285 |
+
var demoId = anchor.data('id') || '',
|
286 |
+
apiURL = anchor.data('demo-api') || '',
|
287 |
+
demoType = anchor.data('demo-type') || '',
|
288 |
+
demoURL = anchor.data('demo-url') || '',
|
289 |
+
screenshot = anchor.data('screenshot') || '',
|
290 |
+
demo_name = anchor.data('demo-name') || '',
|
291 |
+
demo_slug = anchor.data('demo-slug') || '',
|
292 |
+
content = anchor.data('content') || '',
|
293 |
+
requiredPlugins = anchor.data('required-plugins') || '';
|
294 |
+
|
295 |
+
var template = wp.template('astra-demo-preview');
|
296 |
+
|
297 |
+
templateData = [{
|
298 |
+
id : demoId,
|
299 |
+
astra_demo_type : demoType,
|
300 |
+
astra_demo_url : demoURL,
|
301 |
+
demo_api : apiURL,
|
302 |
+
screenshot : screenshot,
|
303 |
+
demo_name : demo_name,
|
304 |
+
slug : demo_slug,
|
305 |
+
content : content,
|
306 |
+
requiredPlugins : requiredPlugins
|
307 |
+
}];
|
308 |
+
|
309 |
+
// Initial set count.
|
310 |
+
astraDemo.requiredPluginsCount = requiredPlugins.length || 0;
|
311 |
+
|
312 |
+
// delete any earlier fullscreen preview before we render new one.
|
313 |
+
jQuery('.theme-install-overlay').remove();
|
314 |
+
|
315 |
+
jQuery('#ast-menu-page').append(template(templateData[0]));
|
316 |
+
jQuery('.theme-install-overlay').css('display', 'block');
|
317 |
+
checkNextPrevButtons();
|
318 |
+
|
319 |
+
var desc = jQuery('.theme-details');
|
320 |
+
var descHeight = parseInt( desc.outerHeight() );
|
321 |
+
var descBtn = jQuery('.theme-details-read-more');
|
322 |
+
|
323 |
+
if( 'free' === demoType && descHeight >= 55 ) {
|
324 |
+
|
325 |
+
// Show button.
|
326 |
+
descBtn.css( 'display', 'inline-block' );
|
327 |
+
|
328 |
+
// Set height upto 3 line.
|
329 |
+
desc.css( 'height', 57 );
|
330 |
+
|
331 |
+
// Button Click.
|
332 |
+
descBtn.click(function(event) {
|
333 |
+
|
334 |
+
if( descBtn.hasClass('open') ) {
|
335 |
+
desc.animate({ height: 57 },
|
336 |
+
300, function() {
|
337 |
+
descBtn.removeClass('open');
|
338 |
+
descBtn.html( astraDemo.strings.DescExpand );
|
339 |
+
});
|
340 |
+
} else {
|
341 |
+
desc.animate({ height: descHeight },
|
342 |
+
300, function() {
|
343 |
+
descBtn.addClass('open');
|
344 |
+
descBtn.html( astraDemo.strings.DescCollapse );
|
345 |
+
});
|
346 |
+
}
|
347 |
+
|
348 |
+
});
|
349 |
+
}
|
350 |
+
|
351 |
+
if( 'free' === demoType ) {
|
352 |
+
|
353 |
+
// or
|
354 |
+
var $pluginsFilter = jQuery( '#plugin-filter' ),
|
355 |
+
data = {
|
356 |
+
_ajax_nonce : astraDemo._ajax_nonce,
|
357 |
+
required_plugins : requiredPlugins
|
358 |
+
};
|
359 |
+
|
360 |
+
jQuery('.required-plugins').addClass('loading').html('<span class="spinner is-active"></span>');
|
361 |
+
|
362 |
+
wp.ajax.post( 'astra-required-plugins', data ).done( function( response ) {
|
363 |
+
|
364 |
+
// Remove loader.
|
365 |
+
jQuery('.required-plugins').removeClass('loading').html('');
|
366 |
+
|
367 |
+
/**
|
368 |
+
* Count remaining plugins.
|
369 |
+
* @type number
|
370 |
+
*/
|
371 |
+
var remaining_plugins = 0;
|
372 |
+
|
373 |
+
/**
|
374 |
+
* Not Installed
|
375 |
+
*
|
376 |
+
* List of not installed required plugins.
|
377 |
+
*/
|
378 |
+
if ( typeof response.notinstalled !== 'undefined' ) {
|
379 |
+
|
380 |
+
// Add not have installed plugins count.
|
381 |
+
remaining_plugins += parseInt( response.notinstalled.length );
|
382 |
+
|
383 |
+
jQuery( response.notinstalled ).each(function( index, plugin ) {
|
384 |
+
|
385 |
+
var output = '<div class="plugin-card ';
|
386 |
+
output += ' plugin-card-'+plugin.slug+'"';
|
387 |
+
output += ' data-slug="'+plugin.slug+'">';
|
388 |
+
output += ' <span class="title">'+plugin.name+'</span>';
|
389 |
+
output += ' <button class="button install-now"';
|
390 |
+
output += ' data-init="' + plugin.init + '"';
|
391 |
+
output += ' data-slug="' + plugin.slug + '"';
|
392 |
+
output += ' data-name="' + plugin.name + '">';
|
393 |
+
output += wp.updates.l10n.installNow;
|
394 |
+
output += ' </button>';
|
395 |
+
output += '</div>';
|
396 |
+
|
397 |
+
jQuery('.required-plugins').append(output);
|
398 |
+
|
399 |
+
});
|
400 |
+
}
|
401 |
+
|
402 |
+
/**
|
403 |
+
* Inactive
|
404 |
+
*
|
405 |
+
* List of not inactive required plugins.
|
406 |
+
*/
|
407 |
+
if ( typeof response.inactive !== 'undefined' ) {
|
408 |
+
|
409 |
+
// Add inactive plugins count.
|
410 |
+
remaining_plugins += parseInt( response.inactive.length );
|
411 |
+
|
412 |
+
jQuery( response.inactive ).each(function( index, plugin ) {
|
413 |
+
|
414 |
+
var output = '<div class="plugin-card ';
|
415 |
+
output += ' plugin-card-'+plugin.slug+'"';
|
416 |
+
output += ' data-slug="'+plugin.slug+'">';
|
417 |
+
output += ' <span class="title">'+plugin.name+'</span>';
|
418 |
+
|
419 |
+
output += ' <button class="button activate-now button-primary"';
|
420 |
+
output += ' data-init="' + plugin.init + '">';
|
421 |
+
output += wp.updates.l10n.activatePlugin;
|
422 |
+
output += ' </button>';
|
423 |
+
output += '</div>';
|
424 |
+
|
425 |
+
jQuery('.required-plugins').append(output);
|
426 |
+
|
427 |
+
});
|
428 |
+
}
|
429 |
+
|
430 |
+
/**
|
431 |
+
* Active
|
432 |
+
*
|
433 |
+
* List of not active required plugins.
|
434 |
+
*/
|
435 |
+
if ( typeof response.active !== 'undefined' ) {
|
436 |
+
|
437 |
+
jQuery( response.active ).each(function( index, plugin ) {
|
438 |
+
|
439 |
+
var output = '<div class="plugin-card ';
|
440 |
+
output += ' plugin-card-'+plugin.slug+'"';
|
441 |
+
output += ' data-slug="'+plugin.slug+'">';
|
442 |
+
output += ' <span class="title">'+plugin.name+'</span>';
|
443 |
+
output += ' <button class="button disabled"';
|
444 |
+
output += ' data-slug="' + plugin.slug + '"';
|
445 |
+
output += ' data-name="' + plugin.name + '">';
|
446 |
+
output += astraDemo.strings.btnActive;
|
447 |
+
output += ' </button>';
|
448 |
+
output += '</div>';
|
449 |
+
|
450 |
+
jQuery('.required-plugins').append(output);
|
451 |
+
|
452 |
+
});
|
453 |
+
}
|
454 |
+
|
455 |
+
/**
|
456 |
+
* Enable Demo Import Button
|
457 |
+
* @type number
|
458 |
+
*/
|
459 |
+
astraDemo.requiredPluginsCount = remaining_plugins;
|
460 |
+
enable_demo_import_button();
|
461 |
+
|
462 |
+
} );
|
463 |
+
|
464 |
+
} else {
|
465 |
+
|
466 |
+
// Enable Demo Import Button
|
467 |
+
enable_demo_import_button( demoType );
|
468 |
+
jQuery('.required-plugins-wrap').remove();
|
469 |
+
}
|
470 |
+
|
471 |
+
return;
|
472 |
+
}
|
473 |
+
|
474 |
+
function checkNextPrevButtons() {
|
475 |
+
currentDemo = jQuery('.theme-preview-on');
|
476 |
+
nextDemo = currentDemo.nextAll('.theme').length;
|
477 |
+
prevDemo = currentDemo.prevAll('.theme').length;
|
478 |
+
|
479 |
+
if (nextDemo == 0) {
|
480 |
+
jQuery('.next-theme').addClass('disabled');
|
481 |
+
} else if (nextDemo != 0) {
|
482 |
+
jQuery('.next-theme').removeClass('disabled');
|
483 |
+
}
|
484 |
+
|
485 |
+
if (prevDemo == 0) {
|
486 |
+
jQuery('.previous-theme').addClass('disabled');
|
487 |
+
} else if (prevDemo != 0) {
|
488 |
+
jQuery('.previous-theme').removeClass('disabled');
|
489 |
+
}
|
490 |
+
|
491 |
+
return;
|
492 |
+
}
|
493 |
+
|
494 |
+
jQuery(document).on('click', '.filter-links li a', function (event) {
|
495 |
+
event.preventDefault();
|
496 |
+
|
497 |
+
$this = jQuery(this);
|
498 |
+
$this.parent('li').siblings().find('.current').removeClass('current');
|
499 |
+
$this.addClass('current');
|
500 |
+
slug = $this.data('sort');
|
501 |
+
id = $this.data('id');
|
502 |
+
|
503 |
+
resetPagedCount();
|
504 |
+
paged = parseInt(jQuery('body').attr('data-astra-demo-paged'));
|
505 |
+
|
506 |
+
if (slug == 'all') {
|
507 |
+
category = 'all';
|
508 |
+
} else {
|
509 |
+
category = slug;
|
510 |
+
}
|
511 |
+
|
512 |
+
jQuery('body').addClass('loading-content');
|
513 |
+
jQuery('.theme-browser .theme').remove();
|
514 |
+
jQuery('.no-themes').remove();
|
515 |
+
jQuery('#wp-filter-search-input').val('');
|
516 |
+
|
517 |
+
jQuery.ajax({
|
518 |
+
url: astraDemo.ajaxurl,
|
519 |
+
type: 'POST',
|
520 |
+
dataType: 'json',
|
521 |
+
data: {
|
522 |
+
action: 'astra-list-sites',
|
523 |
+
category: category,
|
524 |
+
id: id,
|
525 |
+
paged: paged,
|
526 |
+
},
|
527 |
+
})
|
528 |
+
.done(function (demos) {
|
529 |
+
jQuery('body').removeClass('loading-content');
|
530 |
+
renderDemoGrid(demos);
|
531 |
+
})
|
532 |
+
.fail(function () {
|
533 |
+
jQuery('body').removeClass('loading-content');
|
534 |
+
jQuery('.spinner').after('<p class="no-themes" style="display:block;">There was a problem receiving a response from server.</p>');
|
535 |
+
});
|
536 |
+
|
537 |
+
});
|
538 |
+
|
539 |
+
var ref;
|
540 |
+
jQuery(document).on('keyup input', '#wp-filter-search-input', function () {
|
541 |
+
$this = jQuery('#wp-filter-search-input').val();
|
542 |
+
|
543 |
+
id = '';
|
544 |
+
if ($this.length < 2) {
|
545 |
+
id = 'all';
|
546 |
+
}
|
547 |
+
|
548 |
+
window.clearTimeout(ref);
|
549 |
+
ref = window.setTimeout(function () {
|
550 |
+
ref = null;
|
551 |
+
|
552 |
+
resetPagedCount();
|
553 |
+
jQuery('body').addClass('loading-content');
|
554 |
+
jQuery('.theme-browser .theme').remove();
|
555 |
+
jQuery('.no-themes').remove();
|
556 |
+
jQuery('body').attr('data-astra-demo-search', $this);
|
557 |
+
|
558 |
+
jQuery.ajax({
|
559 |
+
url: astraDemo.ajaxurl,
|
560 |
+
type: 'POST',
|
561 |
+
dataType: 'json',
|
562 |
+
data: {
|
563 |
+
action: 'astra-list-sites',
|
564 |
+
search: $this,
|
565 |
+
id: id,
|
566 |
+
},
|
567 |
+
})
|
568 |
+
.done(function (demos) {
|
569 |
+
jQuery('.filter-links li a[data-id="all"]').addClass('current');
|
570 |
+
jQuery('.filter-links li a[data-id="all"]').parent('li').siblings().find('.current').removeClass('current');
|
571 |
+
jQuery('body').removeClass('loading-content');
|
572 |
+
|
573 |
+
if (demos.length > 0) {
|
574 |
+
renderDemoGrid(demos);
|
575 |
+
} else {
|
576 |
+
jQuery('.spinner').after('<p class="no-themes" style="display:block;">'+astraDemo.strings.searchNoFound+'</p>');
|
577 |
+
}
|
578 |
+
|
579 |
+
})
|
580 |
+
.fail(function () {
|
581 |
+
jQuery('body').removeClass('loading-content');
|
582 |
+
jQuery('.spinner').after('<p class="no-themes" style="display:block;">'+astraDemo.strings.responseError+'.</p>');
|
583 |
+
});
|
584 |
+
|
585 |
+
}, 500);
|
586 |
+
|
587 |
+
});
|
588 |
+
|
589 |
+
function renderDemoGrid(demos) {
|
590 |
+
jQuery.each(demos, function (index, demo) {
|
591 |
+
|
592 |
+
id = demo.id;
|
593 |
+
content = demo.content;
|
594 |
+
demo_api = demo.demo_api;
|
595 |
+
demo_name = demo.title;
|
596 |
+
demo_slug = demo.slug;
|
597 |
+
screenshot = demo.featured_image_url;
|
598 |
+
astra_demo_url = demo.astra_demo_url;
|
599 |
+
astra_demo_type = demo.astra_demo_type;
|
600 |
+
requiredPlugins = demo.required_plugins;
|
601 |
+
|
602 |
+
templateData = [{
|
603 |
+
id: id,
|
604 |
+
astra_demo_type: astra_demo_type,
|
605 |
+
astra_demo_url: astra_demo_url,
|
606 |
+
demo_api: demo_api,
|
607 |
+
screenshot: screenshot,
|
608 |
+
demo_name: demo_name,
|
609 |
+
slug: demo_slug,
|
610 |
+
content: content,
|
611 |
+
required_plugins: requiredPlugins
|
612 |
+
}]
|
613 |
+
|
614 |
+
var template = wp.template('astra-single-demo');
|
615 |
+
jQuery('.themes').append(template(templateData[0]));
|
616 |
+
});
|
617 |
+
}
|
618 |
+
|
619 |
+
jQuery(document).on('click', '.collapse-sidebar', function (event) {
|
620 |
+
event.preventDefault();
|
621 |
+
|
622 |
+
overlay = jQuery('.wp-full-overlay');
|
623 |
+
|
624 |
+
if (overlay.hasClass('expanded')) {
|
625 |
+
overlay.removeClass('expanded');
|
626 |
+
overlay.addClass('collapsed');
|
627 |
+
return;
|
628 |
+
}
|
629 |
+
|
630 |
+
if (overlay.hasClass('collapsed')) {
|
631 |
+
overlay.removeClass('collapsed');
|
632 |
+
overlay.addClass('expanded');
|
633 |
+
return;
|
634 |
+
}
|
635 |
+
});
|
636 |
+
|
637 |
+
jQuery(document).on('click', '.astra-demo-import', function (event) {
|
638 |
+
event.preventDefault();
|
639 |
+
|
640 |
+
var $this = jQuery(this),
|
641 |
+
disabled = $this.attr('data-import');
|
642 |
+
|
643 |
+
if ( typeof disabled !== 'undefined' && disabled === 'disabled' ) {
|
644 |
+
|
645 |
+
// Highlight required plugins list.
|
646 |
+
var pluginTitle = jQuery('.required-plugins-wrap h4');
|
647 |
+
pluginTitle.css({'background-color':'rgba(255, 235, 59, 0.20)'});
|
648 |
+
setTimeout(function() {
|
649 |
+
pluginTitle.css({'background-color':''});
|
650 |
+
}, 1000);
|
651 |
+
|
652 |
+
return;
|
653 |
+
}
|
654 |
+
|
655 |
+
// Proceed?
|
656 |
+
if( ! confirm( astraDemo.strings.importWarning ) ) {
|
657 |
+
return;
|
658 |
+
}
|
659 |
+
|
660 |
+
jQuery('.astra-demo-import').attr('data-import', 'disabled')
|
661 |
+
.addClass('updating-message installing')
|
662 |
+
.text('Importing Demo');
|
663 |
+
|
664 |
+
$this.closest('.theme').focus();
|
665 |
+
|
666 |
+
var $theme = $this.closest('.astra-sites-preview').find('.wp-full-overlay-header');
|
667 |
+
|
668 |
+
var apiURL = $theme.data('demo-api') || '';
|
669 |
+
|
670 |
+
jQuery.ajax({
|
671 |
+
url: astraDemo.ajaxurl,
|
672 |
+
type: 'POST',
|
673 |
+
dataType: 'json',
|
674 |
+
data: {
|
675 |
+
action: 'astra-import-demo',
|
676 |
+
api_url: apiURL
|
677 |
+
},
|
678 |
+
})
|
679 |
+
.done(function ( demos ) {
|
680 |
+
|
681 |
+
jQuery('.astra-demo-import').removeClass('updating-message installing')
|
682 |
+
.removeAttr('data-import')
|
683 |
+
.addClass('view-site')
|
684 |
+
.removeClass('astra-demo-import')
|
685 |
+
.text( astraDemo.strings.viewSite )
|
686 |
+
.attr('target', '_blank')
|
687 |
+
.append('<i class="dashicons dashicons-external"></i>')
|
688 |
+
.attr('href', astraDemo.siteURL );
|
689 |
+
})
|
690 |
+
.fail(function ( demos ) {
|
691 |
+
jQuery('.astra-demo-import').removeClass('updating-message installing').text('Error.');
|
692 |
+
});
|
693 |
+
|
694 |
+
});
|
astra-sites.php
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Plugin Name: Astra Sites
|
4 |
+
* Plugin URI: http://www.wpastra.com/pro/
|
5 |
+
* Description: Import sites build with Astra theme.
|
6 |
+
* Version: 1.0.0
|
7 |
+
* Author: Brainstorm Force
|
8 |
+
* Author URI: http://www.brainstormforce.com
|
9 |
+
* Text Domain: astra-sites
|
10 |
+
*
|
11 |
+
* @package Astra Sites
|
12 |
+
*/
|
13 |
+
|
14 |
+
/**
|
15 |
+
* Set constants.
|
16 |
+
*/
|
17 |
+
define( 'ASTRA_SITES_VER', '1.0.0' );
|
18 |
+
define( 'ASTRA_SITES_FILE', __FILE__ );
|
19 |
+
define( 'ASTRA_SITES_BASE', plugin_basename( ASTRA_SITES_FILE ) );
|
20 |
+
define( 'ASTRA_SITES_DIR', plugin_dir_path( ASTRA_SITES_FILE ) );
|
21 |
+
define( 'ASTRA_SITES_URI', plugins_url( '/', ASTRA_SITES_FILE ) );
|
22 |
+
|
23 |
+
require_once ASTRA_SITES_DIR . 'classes/class-astra-sites.php';
|
classes/class-astra-sites.php
ADDED
@@ -0,0 +1,631 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Astra Sites
|
4 |
+
*
|
5 |
+
* @since 1.0.0
|
6 |
+
* @package Astra Sites
|
7 |
+
*/
|
8 |
+
|
9 |
+
defined( 'ABSPATH' ) or exit;
|
10 |
+
|
11 |
+
if ( ! class_exists( 'Astra_Sites' ) ) :
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Astra_Sites
|
15 |
+
*/
|
16 |
+
class Astra_Sites {
|
17 |
+
|
18 |
+
/**
|
19 |
+
* API URL which is used to get the response from.
|
20 |
+
*
|
21 |
+
* @since 1.0.0
|
22 |
+
* @var (String) URL
|
23 |
+
*/
|
24 |
+
public static $api_url;
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Instance of Astra_Sites
|
28 |
+
*
|
29 |
+
* @since 1.0.0
|
30 |
+
* @var (Object) Astra_Sites
|
31 |
+
*/
|
32 |
+
private static $_instance = null;
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Instance of Astra_Sites.
|
36 |
+
*
|
37 |
+
* @since 1.0.0
|
38 |
+
*
|
39 |
+
* @return object Class object.
|
40 |
+
*/
|
41 |
+
public static function set_instance() {
|
42 |
+
if ( ! isset( self::$_instance ) ) {
|
43 |
+
self::$_instance = new self;
|
44 |
+
}
|
45 |
+
|
46 |
+
return self::$_instance;
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Constructor.
|
51 |
+
*
|
52 |
+
* @since 1.0.0
|
53 |
+
*/
|
54 |
+
private function __construct() {
|
55 |
+
|
56 |
+
add_action( 'admin_notices', array( $this, 'admin_notices' ) );
|
57 |
+
|
58 |
+
self::set_api_url();
|
59 |
+
|
60 |
+
$this->includes();
|
61 |
+
|
62 |
+
add_action( 'wp_enqueue_scripts', array( $this, 'admin_enqueue' ) );
|
63 |
+
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue' ) );
|
64 |
+
add_action( 'wp_ajax_astra-import-demo', array( $this, 'demo_ajax_import' ) );
|
65 |
+
add_action( 'wp_ajax_astra-list-sites', array( $this, 'list_demos' ) );
|
66 |
+
add_action( 'wp_ajax_astra-required-plugins', array( $this, 'required_plugin' ) );
|
67 |
+
add_action( 'wp_ajax_astra-required-plugin-activate', array( $this, 'required_plugin_activate' ) );
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Admin Notices
|
72 |
+
*
|
73 |
+
* @since 1.0.0
|
74 |
+
* @return void
|
75 |
+
*/
|
76 |
+
function admin_notices() {
|
77 |
+
|
78 |
+
if ( ! defined( 'ASTRA_THEME_SETTINGS' ) ) {
|
79 |
+
?>
|
80 |
+
<div class="notice notice-error ast-active-notice is-dismissible">
|
81 |
+
<p>
|
82 |
+
<?php
|
83 |
+
printf(
|
84 |
+
/* translators: 1: theme.php file*/
|
85 |
+
__( 'Astra Theme needs to be active for you to use currently installed "Astra Sites" plugin. <a href="%1$s">Install & Activate Now</a>', 'astra-sites' ),
|
86 |
+
esc_url( admin_url( 'themes.php?theme=astra' ) )
|
87 |
+
);
|
88 |
+
?>
|
89 |
+
</p>
|
90 |
+
</div>
|
91 |
+
<?php
|
92 |
+
return;
|
93 |
+
}
|
94 |
+
|
95 |
+
add_action( 'plugin_action_links_' . ASTRA_SITES_BASE, array( $this, 'action_links' ) );
|
96 |
+
}
|
97 |
+
|
98 |
+
/**
|
99 |
+
* Show action links on the plugin screen.
|
100 |
+
*
|
101 |
+
* @param mixed $links Plugin Action links.
|
102 |
+
* @return array
|
103 |
+
*/
|
104 |
+
function action_links( $links ) {
|
105 |
+
$action_links = array(
|
106 |
+
'settings' => '<a href="' . admin_url( 'themes.php?page=astra&action=astra-sites' ) . '" aria-label="' . esc_attr__( 'See Library', 'astra-sites' ) . '">' . esc_html__( 'See Library', 'astra-sites' ) . '</a>',
|
107 |
+
);
|
108 |
+
|
109 |
+
return array_merge( $action_links, $links );
|
110 |
+
}
|
111 |
+
|
112 |
+
/**
|
113 |
+
* Setter for $api_url
|
114 |
+
*
|
115 |
+
* @since 1.0.0
|
116 |
+
*/
|
117 |
+
public static function set_api_url() {
|
118 |
+
|
119 |
+
self::$api_url = apply_filters( 'astra_demo_api_url', 'https://sites.wpastra.com/wp-json/wp/v2/' );
|
120 |
+
|
121 |
+
}
|
122 |
+
|
123 |
+
/**
|
124 |
+
* Returns the API URL that depending based on the category, search term and pagination.
|
125 |
+
*
|
126 |
+
* @since 1.0.0
|
127 |
+
*
|
128 |
+
* @param object $args Arguments for selecting correct list of demos.
|
129 |
+
* args->id = ID of the demo.
|
130 |
+
* $args->search = Search term used in the demo.
|
131 |
+
* @param string $page Page number for pagination.
|
132 |
+
*
|
133 |
+
* @return string URL that can be queried to return the demos.
|
134 |
+
*/
|
135 |
+
public static function get_api_url( $args, $page = '1' ) {
|
136 |
+
|
137 |
+
$request_params = array(
|
138 |
+
'page' => $page,
|
139 |
+
'per_page' => '15',
|
140 |
+
|
141 |
+
// Use this for premium demos.
|
142 |
+
'purchase_key' => '',
|
143 |
+
'site_url' => '',
|
144 |
+
);
|
145 |
+
|
146 |
+
$args_search = isset( $args->search ) ? $args->search : '';
|
147 |
+
$args_id = isset( $args->id ) ? $args->id : '';
|
148 |
+
|
149 |
+
// Not Search?
|
150 |
+
if ( '' !== $args_search ) {
|
151 |
+
$request_params['search'] = $args_search;
|
152 |
+
|
153 |
+
// Not All?
|
154 |
+
} elseif ( 'all' != $args_id ) {
|
155 |
+
$request_params['astra-site-category'] = $args_id;
|
156 |
+
}
|
157 |
+
|
158 |
+
return add_query_arg( $request_params, self::$api_url . 'astra-sites' );
|
159 |
+
}
|
160 |
+
|
161 |
+
/**
|
162 |
+
* Returns the API URL for searching demos basedon taxanomies.
|
163 |
+
*
|
164 |
+
* @since 1.0.0
|
165 |
+
* @return (String) URL that can be queried to return the demos.
|
166 |
+
*/
|
167 |
+
public static function get_taxanomy_api_url() {
|
168 |
+
return self::$api_url . 'astra-site-category/';
|
169 |
+
}
|
170 |
+
|
171 |
+
/**
|
172 |
+
* Enqueue admin scripts.
|
173 |
+
*
|
174 |
+
* @since 1.0.0
|
175 |
+
*/
|
176 |
+
public function admin_enqueue() {
|
177 |
+
|
178 |
+
wp_register_script(
|
179 |
+
'astra-sites-admin', ASTRA_SITES_URI . 'assets/js/admin.js', array(
|
180 |
+
'jquery',
|
181 |
+
'wp-util',
|
182 |
+
'updates',
|
183 |
+
), ASTRA_SITES_VER, true
|
184 |
+
);
|
185 |
+
|
186 |
+
wp_register_style( 'astra-sites-admin', ASTRA_SITES_URI . 'assets/css/admin.css', ASTRA_SITES_VER, true );
|
187 |
+
|
188 |
+
wp_localize_script(
|
189 |
+
'astra-sites-admin', 'astraDemo', array(
|
190 |
+
'ajaxurl' => esc_url( admin_url( 'admin-ajax.php' ) ),
|
191 |
+
'siteURL' => site_url(),
|
192 |
+
'getProText' => __( 'Purchase', 'astra-sites' ),
|
193 |
+
'getProURL' => esc_url( 'https://wpastra.com/pro/?utm_source=demo-import-panel&utm_campaign=astra-sites&utm_medium=' ),
|
194 |
+
'_ajax_nonce' => wp_create_nonce( 'astra-sites' ),
|
195 |
+
'requiredPluginsCount' => 0,
|
196 |
+
'strings' => array(
|
197 |
+
'viewSite' => __( 'Done! View Site', 'astra-sites' ),
|
198 |
+
'btnActivating' => __( 'Activating', 'astra-sites' ) . '…',
|
199 |
+
'btnActive' => __( 'Active', 'astra-sites' ),
|
200 |
+
'importDemo' => __( 'Import This Site', 'astra-sites' ),
|
201 |
+
'DescExpand' => __( 'Read more', 'astra-sites' ) . '…',
|
202 |
+
'DescCollapse' => __( 'Hide', 'astra-sites' ),
|
203 |
+
'responseError' => __( 'There was a problem receiving a response from server.', 'astra-sites' ),
|
204 |
+
'searchNoFound' => __( 'No Demos found, Try a different search.', 'astra-sites' ),
|
205 |
+
'importWarning' => __( "Executing Demo Import will make your site similar as ours. Please bear in mind -\n\n1. It is recommended to run import on a fresh WordPress installation.\n\n2. Importing site does not delete any pages or posts. However, it can overwrite your existing content.\n\n3. Copyrighted media will not be imported. Instead it will be replaced with placeholders.", 'astra-sites' ),
|
206 |
+
),
|
207 |
+
)
|
208 |
+
);
|
209 |
+
|
210 |
+
}
|
211 |
+
|
212 |
+
/**
|
213 |
+
* Load all the required files in the importer.
|
214 |
+
*
|
215 |
+
* @since 1.0.0
|
216 |
+
*/
|
217 |
+
private function includes() {
|
218 |
+
|
219 |
+
require_once ASTRA_SITES_DIR . 'admin/class-astra-sites-admin.php';
|
220 |
+
|
221 |
+
// Load the Importers.
|
222 |
+
require_once ASTRA_SITES_DIR . 'importers/class-astra-sites-helper.php';
|
223 |
+
require_once ASTRA_SITES_DIR . 'importers/class-widgets-importer.php';
|
224 |
+
require_once ASTRA_SITES_DIR . 'importers/class-astra-customizer-import.php';
|
225 |
+
require_once ASTRA_SITES_DIR . 'importers/wxr-importer/class-astra-wxr-importer.php';
|
226 |
+
require_once ASTRA_SITES_DIR . 'importers/class-astra-site-options-import.php';
|
227 |
+
}
|
228 |
+
|
229 |
+
/**
|
230 |
+
* Required Plugin Activate
|
231 |
+
*
|
232 |
+
* @since 1.0.0
|
233 |
+
*/
|
234 |
+
public function required_plugin_activate() {
|
235 |
+
|
236 |
+
if ( ! current_user_can( 'install_plugins' ) || ! isset( $_POST['init'] ) || ! $_POST['init'] ) {
|
237 |
+
wp_send_json_error(
|
238 |
+
array(
|
239 |
+
'success' => false,
|
240 |
+
'message' => __( 'No plugin specified', 'astra-sites' ),
|
241 |
+
)
|
242 |
+
);
|
243 |
+
}
|
244 |
+
|
245 |
+
$plugin_init = esc_attr( $_POST['init'] );
|
246 |
+
|
247 |
+
$activate = activate_plugin( $plugin_init, '', false, true );
|
248 |
+
|
249 |
+
if ( is_wp_error( $activate ) ) {
|
250 |
+
wp_send_json_error(
|
251 |
+
array(
|
252 |
+
'success' => false,
|
253 |
+
'message' => $activate->get_error_message(),
|
254 |
+
)
|
255 |
+
);
|
256 |
+
}
|
257 |
+
|
258 |
+
wp_send_json_success(
|
259 |
+
array(
|
260 |
+
'success' => true,
|
261 |
+
'message' => __( 'Plugin Successfully Activated', 'astra-sites' ),
|
262 |
+
)
|
263 |
+
);
|
264 |
+
|
265 |
+
}
|
266 |
+
|
267 |
+
/**
|
268 |
+
* Required Plugin
|
269 |
+
*
|
270 |
+
* @since 1.0.0
|
271 |
+
* @return void
|
272 |
+
*/
|
273 |
+
public function required_plugin() {
|
274 |
+
|
275 |
+
// Verify Nonce.
|
276 |
+
check_ajax_referer( 'astra-sites', '_ajax_nonce' );
|
277 |
+
|
278 |
+
$response = array(
|
279 |
+
'active' => array(),
|
280 |
+
'inactive' => array(),
|
281 |
+
'notinstalled' => array(),
|
282 |
+
);
|
283 |
+
|
284 |
+
if ( ! current_user_can( 'customize' ) ) {
|
285 |
+
wp_send_json_error( $response );
|
286 |
+
}
|
287 |
+
|
288 |
+
$required_plugins = ( isset( $_POST['required_plugins'] ) ) ? $_POST['required_plugins'] : array();
|
289 |
+
|
290 |
+
if ( count( $required_plugins ) > 0 ) {
|
291 |
+
foreach ( $required_plugins as $key => $plugin ) {
|
292 |
+
|
293 |
+
// Inactive plugins.
|
294 |
+
if ( file_exists( WP_PLUGIN_DIR . '/' . $plugin['init'] ) && is_plugin_inactive( $plugin['init'] ) ) {
|
295 |
+
$response['inactive'][] = $plugin;
|
296 |
+
|
297 |
+
// Not Installed plugins.
|
298 |
+
} elseif ( ! file_exists( WP_PLUGIN_DIR . '/' . $plugin['init'] ) ) {
|
299 |
+
$response['notinstalled'][] = $plugin;
|
300 |
+
|
301 |
+
// Active plugins.
|
302 |
+
} else {
|
303 |
+
$response['active'][] = $plugin;
|
304 |
+
}
|
305 |
+
}
|
306 |
+
}
|
307 |
+
|
308 |
+
// Send response.
|
309 |
+
wp_send_json_success( $response );
|
310 |
+
}
|
311 |
+
|
312 |
+
/**
|
313 |
+
* Ajax callback for demo import action.
|
314 |
+
*
|
315 |
+
* @since 1.0.0
|
316 |
+
*/
|
317 |
+
public function demo_ajax_import() {
|
318 |
+
|
319 |
+
if ( ! current_user_can( 'customize' ) ) {
|
320 |
+
return;
|
321 |
+
}
|
322 |
+
|
323 |
+
$demo_api_uri = isset( $_POST['api_url'] ) ? esc_url( $_POST['api_url'] ) : '';
|
324 |
+
$this->import_demo( $demo_api_uri );
|
325 |
+
|
326 |
+
wp_die();
|
327 |
+
}
|
328 |
+
|
329 |
+
/**
|
330 |
+
* Ajax handler for retreiving the list of demos.
|
331 |
+
*
|
332 |
+
* @since 1.0.0
|
333 |
+
* @return (JSON) Json response retreived from the API.
|
334 |
+
*/
|
335 |
+
public function list_demos() {
|
336 |
+
|
337 |
+
if ( ! current_user_can( 'customize' ) ) {
|
338 |
+
return;
|
339 |
+
}
|
340 |
+
|
341 |
+
$args = new stdClass();
|
342 |
+
$args->category = isset( $_POST['category'] ) ? esc_attr( $_POST['category'] ) : '';
|
343 |
+
$args->id = isset( $_POST['id'] ) ? esc_attr( $_POST['id'] ) : '';
|
344 |
+
$args->search = isset( $_POST['search'] ) ? esc_attr( $_POST['search'] ) : '';
|
345 |
+
$paged = isset( $_POST['paged'] ) ? esc_attr( $_POST['paged'] ) : '1';
|
346 |
+
|
347 |
+
return wp_send_json( self::get_astra_demos( $args, $paged ) );
|
348 |
+
}
|
349 |
+
|
350 |
+
/**
|
351 |
+
* Get the list of demos.
|
352 |
+
*
|
353 |
+
* @since 1.0.0
|
354 |
+
* @see admin/view-astra-sites.php
|
355 |
+
* @return (Array) Demos.
|
356 |
+
*/
|
357 |
+
public static function get_astra_all_demos() {
|
358 |
+
$args = new stdClass();
|
359 |
+
$args->id = 'all';
|
360 |
+
|
361 |
+
return self::get_astra_demos( $args );
|
362 |
+
}
|
363 |
+
|
364 |
+
/**
|
365 |
+
* Import the demo.
|
366 |
+
*
|
367 |
+
* @since 1.0.0
|
368 |
+
*
|
369 |
+
* @param (String) $demo_api_uri API URL for the single demo.
|
370 |
+
*/
|
371 |
+
public function import_demo( $demo_api_uri ) {
|
372 |
+
|
373 |
+
$demo_data = self::get_astra_single_demo( $demo_api_uri );
|
374 |
+
|
375 |
+
// Import Enabled Extensions.
|
376 |
+
$this->import_astra_enabled_extension( $demo_data['astra-enabled-extensions'] );
|
377 |
+
|
378 |
+
// Import Widgets data.
|
379 |
+
$this->import_widgets( $demo_data['astra-site-widgets-data'] );
|
380 |
+
|
381 |
+
// Import Customizer Settings.
|
382 |
+
$this->import_customizer_settings( $demo_data['astra-site-customizer-data'] );
|
383 |
+
|
384 |
+
// Import XML.
|
385 |
+
$this->import_wxr( $demo_data['astra-site-wxr-path'] );
|
386 |
+
|
387 |
+
// Import WordPress site options.
|
388 |
+
$this->import_site_options( $demo_data['astra-site-options-data'] );
|
389 |
+
|
390 |
+
// Import Custom 404 extension options.
|
391 |
+
$this->import_custom_404_extension_options( $demo_data['astra-custom-404'] );
|
392 |
+
}
|
393 |
+
|
394 |
+
/**
|
395 |
+
* Import widgets and assign to correct sidebars.
|
396 |
+
*
|
397 |
+
* @since 1.0.0
|
398 |
+
*
|
399 |
+
* @param (Object) $data Widgets data.
|
400 |
+
*/
|
401 |
+
private function import_widgets( $data ) {
|
402 |
+
|
403 |
+
// bail if wiegets data is not available.
|
404 |
+
if ( null == $data ) {
|
405 |
+
return;
|
406 |
+
}
|
407 |
+
|
408 |
+
$widgets_importer = Astra_Widget_Importer::instance();
|
409 |
+
$widgets_importer->import_widgets_data( $data );
|
410 |
+
}
|
411 |
+
|
412 |
+
/**
|
413 |
+
* Import Customizer data.
|
414 |
+
*
|
415 |
+
* @since 1.0.0
|
416 |
+
*
|
417 |
+
* @param (Array) $customizer_data Customizer data for the demo to be imported.
|
418 |
+
*/
|
419 |
+
private function import_customizer_settings( $customizer_data ) {
|
420 |
+
$customizer_import = Astra_Customizer_Import::instance();
|
421 |
+
$customizer_data = $customizer_import->import( $customizer_data );
|
422 |
+
}
|
423 |
+
|
424 |
+
/**
|
425 |
+
* Download and import the XML from the demo.
|
426 |
+
*
|
427 |
+
* @since 1.0.0
|
428 |
+
*
|
429 |
+
* @param (String) $wxr_url URL of the xml export of the demo to be imported.
|
430 |
+
*/
|
431 |
+
private function import_wxr( $wxr_url ) {
|
432 |
+
$wxr_importer = Astra_WXR_Importer::instance();
|
433 |
+
$xml_path = $wxr_importer->download_xml( $wxr_url );
|
434 |
+
$wxr_importer->import_xml( $xml_path['file'] );
|
435 |
+
}
|
436 |
+
|
437 |
+
/**
|
438 |
+
* Import site options - Front Page, Menus, Blog page etc.
|
439 |
+
*
|
440 |
+
* @since 1.0.0
|
441 |
+
*
|
442 |
+
* @param (Array) $options Array of required site options from the demo.
|
443 |
+
*/
|
444 |
+
private function import_site_options( $options ) {
|
445 |
+
$options_importer = Astra_Site_Options_Import::instance();
|
446 |
+
$options_importer->import_options( $options );
|
447 |
+
}
|
448 |
+
|
449 |
+
/**
|
450 |
+
* Import settings enabled astra extensions from the demo.
|
451 |
+
*
|
452 |
+
* @since 1.0.0
|
453 |
+
*
|
454 |
+
* @param (Array) $saved_extensions Array of enabled extensions.
|
455 |
+
*/
|
456 |
+
private function import_astra_enabled_extension( $saved_extensions ) {
|
457 |
+
if ( is_callable( 'AST_Admin_Helper::update_admin_settings_option' ) ) {
|
458 |
+
AST_Admin_Helper::update_admin_settings_option( '_astra_ext_enabled_extensions', $saved_extensions );
|
459 |
+
}
|
460 |
+
}
|
461 |
+
|
462 |
+
/**
|
463 |
+
* Import custom 404 section.
|
464 |
+
*
|
465 |
+
* @since 1.0.0
|
466 |
+
*
|
467 |
+
* @param (Array) $options_404 404 Extensions settings from the demo.
|
468 |
+
*/
|
469 |
+
private function import_custom_404_extension_options( $options_404 ) {
|
470 |
+
if ( is_callable( 'AST_Admin_Helper::update_admin_settings_option' ) ) {
|
471 |
+
AST_Admin_Helper::update_admin_settings_option( '_astra_ext_custom_404', $options_404 );
|
472 |
+
}
|
473 |
+
}
|
474 |
+
|
475 |
+
/**
|
476 |
+
* Get single demo.
|
477 |
+
*
|
478 |
+
* @since 1.0.0
|
479 |
+
*
|
480 |
+
* @param (String) $demo_api_uri API URL of a demo.
|
481 |
+
*
|
482 |
+
* @return (Array) $astra_demo_data demo data for the demo.
|
483 |
+
*/
|
484 |
+
public static function get_astra_single_demo( $demo_api_uri ) {
|
485 |
+
|
486 |
+
// default values.
|
487 |
+
$remote_args = array();
|
488 |
+
$defaults = array(
|
489 |
+
'id' => '',
|
490 |
+
'astra-site-widgets-data' => '',
|
491 |
+
'astra-site-customizer-data' => '',
|
492 |
+
'astra-site-options-data' => '',
|
493 |
+
'astra-site-wxr-path' => '',
|
494 |
+
'astra-enabled-extensions' => '',
|
495 |
+
'astra-custom-404' => '',
|
496 |
+
'required-plugins' => '',
|
497 |
+
);
|
498 |
+
|
499 |
+
$api_args = array(
|
500 |
+
'timeout' => 15,
|
501 |
+
);
|
502 |
+
|
503 |
+
$response = wp_remote_get( $demo_api_uri, $api_args );
|
504 |
+
|
505 |
+
if ( ! is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) === 200 ) {
|
506 |
+
$result = json_decode( wp_remote_retrieve_body( $response ), true );
|
507 |
+
$remote_args['id'] = $result['id'];
|
508 |
+
$remote_args['astra-site-widgets-data'] = json_decode( $result['astra-site-widgets-data'] );
|
509 |
+
$remote_args['astra-site-customizer-data'] = $result['astra-site-customizer-data'];
|
510 |
+
$remote_args['astra-site-options-data'] = $result['astra-site-options-data'];
|
511 |
+
$remote_args['astra-site-wxr-path'] = $result['astra-site-wxr-path'];
|
512 |
+
$remote_args['astra-enabled-extensions'] = $result['astra-enabled-extensions'];
|
513 |
+
$remote_args['astra-custom-404'] = $result['astra-custom-404'];
|
514 |
+
$remote_args['required-plugins'] = $result['required-plugins'];
|
515 |
+
}
|
516 |
+
|
517 |
+
// Merge remote demo and defaults.
|
518 |
+
return wp_parse_args( $remote_args, $defaults );
|
519 |
+
}
|
520 |
+
|
521 |
+
/**
|
522 |
+
* Get astra demos.
|
523 |
+
*
|
524 |
+
* @since 1.0.0
|
525 |
+
*
|
526 |
+
* @param (Array) $args For selecting the demos (Search terms, pagination etc).
|
527 |
+
* @param (String) $paged Page number.
|
528 |
+
*/
|
529 |
+
public static function get_astra_demos( $args, $paged = '1' ) {
|
530 |
+
|
531 |
+
$url = self::get_api_url( $args, $paged );
|
532 |
+
|
533 |
+
$astra_demos = array();
|
534 |
+
|
535 |
+
$api_args = array(
|
536 |
+
'timeout' => 15,
|
537 |
+
);
|
538 |
+
|
539 |
+
$response = wp_remote_get( $url, $api_args );
|
540 |
+
|
541 |
+
if ( ! is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) === 200 ) {
|
542 |
+
$result = json_decode( wp_remote_retrieve_body( $response ), true );
|
543 |
+
|
544 |
+
// If is array then proceed
|
545 |
+
// Else skip it.
|
546 |
+
if ( is_array( $result ) ) {
|
547 |
+
|
548 |
+
foreach ( $result as $key => $demo ) {
|
549 |
+
|
550 |
+
if ( ! isset( $demo['id'] ) ) {
|
551 |
+
continue;
|
552 |
+
}
|
553 |
+
|
554 |
+
$astra_demos[ $key ]['id'] = isset( $demo['id'] ) ? esc_attr( $demo['id'] ) : '';
|
555 |
+
$astra_demos[ $key ]['slug'] = isset( $demo['slug'] ) ? esc_attr( $demo['slug'] ) : '';
|
556 |
+
$astra_demos[ $key ]['date'] = isset( $demo['date'] ) ? esc_attr( $demo['date'] ) : '';
|
557 |
+
$astra_demos[ $key ]['astra_demo_type'] = isset( $demo['astra-site-type'] ) ? sanitize_key( $demo['astra-site-type'] ) : '';
|
558 |
+
$astra_demos[ $key ]['astra_demo_url'] = isset( $demo['astra-site-url'] ) ? esc_url( $demo['astra-site-url'] ) : '';
|
559 |
+
$astra_demos[ $key ]['title'] = isset( $demo['title']['rendered'] ) ? esc_attr( $demo['title']['rendered'] ) : '';
|
560 |
+
$astra_demos[ $key ]['featured_image_url'] = isset( $demo['featured-image-url'] ) ? esc_url( $demo['featured-image-url'] ) : '';
|
561 |
+
$astra_demos[ $key ]['demo_api'] = isset( $demo['_links']['self'][0]['href'] ) ? esc_url( $demo['_links']['self'][0]['href'] ) : self::get_api_url( new stdClass() ) . $demo['id'];
|
562 |
+
$astra_demos[ $key ]['content'] = isset( $demo['content']['rendered'] ) ? strip_tags( $demo['content']['rendered'] ) : '';
|
563 |
+
$astra_demos[ $key ]['required_plugins'] = isset( $demo['required-plugins'] ) ? json_encode( $demo['required-plugins'] ) : '';
|
564 |
+
}
|
565 |
+
|
566 |
+
// Free up memory by unsetting variables that are not required.
|
567 |
+
unset( $result );
|
568 |
+
unset( $response );
|
569 |
+
}
|
570 |
+
}
|
571 |
+
|
572 |
+
return $astra_demos;
|
573 |
+
|
574 |
+
}
|
575 |
+
|
576 |
+
/**
|
577 |
+
* Get demo categories.
|
578 |
+
*
|
579 |
+
* @since 1.0.0
|
580 |
+
* @return (Array) Array of demo categories.
|
581 |
+
*/
|
582 |
+
public static function get_demo_categories() {
|
583 |
+
$categories = array();
|
584 |
+
|
585 |
+
$api_args = array(
|
586 |
+
'timeout' => 15,
|
587 |
+
);
|
588 |
+
|
589 |
+
$response = wp_remote_get( self::get_taxanomy_api_url(), $api_args );
|
590 |
+
|
591 |
+
if ( ! is_wp_error( $response ) || 200 === wp_remote_retrieve_response_code( $response ) ) {
|
592 |
+
$result = json_decode( wp_remote_retrieve_body( $response ), true );
|
593 |
+
|
594 |
+
if ( array_key_exists( 'code', $result ) && 'rest_no_route' === $result['code'] ) {
|
595 |
+
return $categories;
|
596 |
+
}
|
597 |
+
|
598 |
+
// If is array then proceed
|
599 |
+
// Else skip it.
|
600 |
+
if ( is_array( $result ) ) {
|
601 |
+
|
602 |
+
foreach ( $result as $key => $category ) {
|
603 |
+
if ( 0 == $category['count'] ) {
|
604 |
+
continue;
|
605 |
+
}
|
606 |
+
$categories[ $key ]['id'] = $category['id'];
|
607 |
+
$categories[ $key ]['name'] = $category['name'];
|
608 |
+
$categories[ $key ]['slug'] = $category['slug'];
|
609 |
+
$categories[ $key ]['count'] = $category['count'];
|
610 |
+
$categories[ $key ]['link-category'] = $category['_links']['self'][0]['href'];
|
611 |
+
}
|
612 |
+
|
613 |
+
// Free up memory by unsetting variables that are not required.
|
614 |
+
unset( $result );
|
615 |
+
unset( $response );
|
616 |
+
|
617 |
+
}
|
618 |
+
}
|
619 |
+
|
620 |
+
return $categories;
|
621 |
+
}
|
622 |
+
|
623 |
+
}
|
624 |
+
|
625 |
+
/**
|
626 |
+
* Kicking this off by calling 'set_instance()' method
|
627 |
+
*/
|
628 |
+
Astra_Sites::set_instance();
|
629 |
+
|
630 |
+
endif;
|
631 |
+
|
importers/class-astra-customizer-import.php
ADDED
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Customizer Data importer class.
|
4 |
+
*
|
5 |
+
* @since 1.0.0
|
6 |
+
* @package Astra Addon
|
7 |
+
*/
|
8 |
+
|
9 |
+
defined( 'ABSPATH' ) or exit;
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Customizer Data importer class.
|
13 |
+
*
|
14 |
+
* @since 1.0.0
|
15 |
+
*/
|
16 |
+
class Astra_Customizer_Import {
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Instance of Astra_Customizer_Import
|
20 |
+
*
|
21 |
+
* @since 1.0.0
|
22 |
+
* @var Astra_Customizer_Import
|
23 |
+
*/
|
24 |
+
private static $_instance = null;
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Instantiate Astra_Customizer_Import
|
28 |
+
*
|
29 |
+
* @since 1.0.0
|
30 |
+
* @return (Object) Astra_Customizer_Import
|
31 |
+
*/
|
32 |
+
public static function instance() {
|
33 |
+
|
34 |
+
if ( ! isset( self::$_instance ) ) {
|
35 |
+
self::$_instance = new self;
|
36 |
+
}
|
37 |
+
|
38 |
+
return self::$_instance;
|
39 |
+
}
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Import customizer options.
|
43 |
+
*
|
44 |
+
* @since 1.0.0
|
45 |
+
*
|
46 |
+
* @param (Array) $data customizer options from the demo.
|
47 |
+
*/
|
48 |
+
public function import( $data ) {
|
49 |
+
update_option( 'astra-settings', $data );
|
50 |
+
}
|
51 |
+
}
|
importers/class-astra-site-options-import.php
ADDED
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Customizer Site options importer class.
|
4 |
+
*
|
5 |
+
* @since 1.0.0
|
6 |
+
* @package Astra Addon
|
7 |
+
*/
|
8 |
+
|
9 |
+
defined( 'ABSPATH' ) or exit;
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Customizer Site options importer class.
|
13 |
+
*
|
14 |
+
* @since 1.0.0
|
15 |
+
*/
|
16 |
+
class Astra_Site_Options_Import {
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Instance of Astra_Site_Options_Importer
|
20 |
+
*
|
21 |
+
* @since 1.0.0
|
22 |
+
* @var (Object) Astra_Site_Options_Importer
|
23 |
+
*/
|
24 |
+
private static $_instance = null;
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Instanciate Astra_Site_Options_Importer
|
28 |
+
*
|
29 |
+
* @since 1.0.0
|
30 |
+
* @return (Object) Astra_Site_Options_Importer
|
31 |
+
*/
|
32 |
+
public static function instance() {
|
33 |
+
if ( ! isset( self::$_instance ) ) {
|
34 |
+
self::$_instance = new self();
|
35 |
+
}
|
36 |
+
|
37 |
+
return self::$_instance;
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Import site options.
|
42 |
+
*
|
43 |
+
* @since 1.0.0
|
44 |
+
*
|
45 |
+
* @param (Array) $options Array of site options to be imported from the demo.
|
46 |
+
*/
|
47 |
+
public function import_options( $options ) {
|
48 |
+
$show_on_front = $options['show_on_front'];
|
49 |
+
$page_on_front = get_page_by_title( $options['page_on_front'] );
|
50 |
+
$page_for_posts = get_page_by_title( $options['page_for_posts'] );
|
51 |
+
$siteorigin_widgets_active = $options['siteorigin_widgets_active'];
|
52 |
+
|
53 |
+
// Update site options.
|
54 |
+
update_option( 'show_on_front', $show_on_front );
|
55 |
+
update_option( 'page_on_front', $page_on_front->ID );
|
56 |
+
update_option( 'page_for_posts', $page_for_posts->ID );
|
57 |
+
update_option( 'siteorigin_widgets_active', $siteorigin_widgets_active );
|
58 |
+
|
59 |
+
$this->set_nav_menu_locations( $options['nav_menu_locations'] );
|
60 |
+
|
61 |
+
$this->insert_logo( $options['custom_logo'] );
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* In WP nav menu is stored as ( 'menu_location' => 'menu_id' );
|
66 |
+
* In export we send 'menu_slug' like ( 'menu_location' => 'menu_slug' );
|
67 |
+
* In import we set 'menu_id' from menu slug like ( 'menu_location' => 'menu_id' );
|
68 |
+
*
|
69 |
+
* @since 1.0.0
|
70 |
+
* @param array $nav_menu_locations Array of nav menu locations.
|
71 |
+
*/
|
72 |
+
function set_nav_menu_locations( $nav_menu_locations = array() ) {
|
73 |
+
|
74 |
+
$menu_locations = array();
|
75 |
+
|
76 |
+
// Update menu locations.
|
77 |
+
foreach ( $nav_menu_locations as $menu => $value ) {
|
78 |
+
|
79 |
+
$term = get_term_by( 'slug', $value, 'nav_menu' );
|
80 |
+
|
81 |
+
if ( is_object( $term ) ) {
|
82 |
+
$menu_locations[ $menu ] = $term->term_id;
|
83 |
+
}
|
84 |
+
}
|
85 |
+
|
86 |
+
set_theme_mod( 'nav_menu_locations', $menu_locations );
|
87 |
+
}
|
88 |
+
|
89 |
+
|
90 |
+
/**
|
91 |
+
* Insert Logo By URL
|
92 |
+
*
|
93 |
+
* @since 1.0.0
|
94 |
+
* @param string $image_url Logo URL.
|
95 |
+
* @return void
|
96 |
+
*/
|
97 |
+
function insert_logo( $image_url = '' ) {
|
98 |
+
|
99 |
+
// Download Site Logo Image.
|
100 |
+
$response = Astra_Sites_Helper::download_file( $image_url );
|
101 |
+
|
102 |
+
// Is Success?
|
103 |
+
if ( $response['success'] ) {
|
104 |
+
|
105 |
+
// Set attachment data.
|
106 |
+
$attachment = array(
|
107 |
+
'post_mime_type' => $response['data']['type'],
|
108 |
+
'post_title' => sanitize_file_name( basename( $image_url ) ),
|
109 |
+
'post_content' => '',
|
110 |
+
'post_status' => 'inherit',
|
111 |
+
);
|
112 |
+
|
113 |
+
// Create the attachment.
|
114 |
+
$attach_id = wp_insert_attachment( $attachment, $response['data']['file'] );
|
115 |
+
|
116 |
+
set_theme_mod( 'custom_logo', $attach_id );
|
117 |
+
}
|
118 |
+
|
119 |
+
}
|
120 |
+
}
|
importers/class-astra-sites-helper.php
ADDED
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Astra Site Helper
|
4 |
+
*
|
5 |
+
* @since 1.0.0
|
6 |
+
* @package Astra Sites
|
7 |
+
*/
|
8 |
+
|
9 |
+
if ( ! class_exists( 'Astra_Sites_Helper' ) ) :
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Astra_Sites_Helper
|
13 |
+
*
|
14 |
+
* @since 1.0.0
|
15 |
+
*/
|
16 |
+
class Astra_Sites_Helper {
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Instance
|
20 |
+
*
|
21 |
+
* @access private
|
22 |
+
* @var object Instance
|
23 |
+
* @since 1.0.0
|
24 |
+
*/
|
25 |
+
private static $instance;
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Initiator
|
29 |
+
*
|
30 |
+
* @since 1.0.0
|
31 |
+
* @return object initialized object of class.
|
32 |
+
*/
|
33 |
+
public static function get_instance() {
|
34 |
+
if ( ! isset( self::$instance ) ) {
|
35 |
+
self::$instance = new self;
|
36 |
+
}
|
37 |
+
return self::$instance;
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Constructor
|
42 |
+
*
|
43 |
+
* @since 1.0.0
|
44 |
+
*/
|
45 |
+
public function __construct() {
|
46 |
+
}
|
47 |
+
|
48 |
+
/**
|
49 |
+
* Download File Into Uploads Directory
|
50 |
+
*
|
51 |
+
* @param string $file Download File URL.
|
52 |
+
* @return array Downloaded file data.
|
53 |
+
*/
|
54 |
+
public static function download_file( $file = '' ) {
|
55 |
+
|
56 |
+
// Gives us access to the download_url() and wp_handle_sideload() functions.
|
57 |
+
require_once( ABSPATH . 'wp-admin/includes/file.php' );
|
58 |
+
|
59 |
+
$timeout_seconds = 5;
|
60 |
+
|
61 |
+
// Download file to temp dir.
|
62 |
+
$temp_file = download_url( $file, $timeout_seconds );
|
63 |
+
|
64 |
+
// WP Error.
|
65 |
+
if ( is_wp_error( $temp_file ) ) {
|
66 |
+
return array(
|
67 |
+
'success' => false,
|
68 |
+
'data' => $temp_file->get_error_message(),
|
69 |
+
);
|
70 |
+
}
|
71 |
+
|
72 |
+
// Array based on $_FILE as seen in PHP file uploads.
|
73 |
+
$file_args = array(
|
74 |
+
'name' => basename( $file ),
|
75 |
+
'tmp_name' => $temp_file,
|
76 |
+
'error' => 0,
|
77 |
+
'size' => filesize( $temp_file ),
|
78 |
+
);
|
79 |
+
|
80 |
+
$overrides = array(
|
81 |
+
|
82 |
+
// Tells WordPress to not look for the POST form
|
83 |
+
// fields that would normally be present as
|
84 |
+
// we downloaded the file from a remote server, so there
|
85 |
+
// will be no form fields
|
86 |
+
// Default is true.
|
87 |
+
'test_form' => false,
|
88 |
+
|
89 |
+
// Setting this to false lets WordPress allow empty files, not recommended.
|
90 |
+
// Default is true.
|
91 |
+
'test_size' => true,
|
92 |
+
|
93 |
+
// A properly uploaded file will pass this test. There should be no reason to override this one.
|
94 |
+
'test_upload' => true,
|
95 |
+
|
96 |
+
);
|
97 |
+
|
98 |
+
// Move the temporary file into the uploads directory.
|
99 |
+
$results = wp_handle_sideload( $file_args, $overrides );
|
100 |
+
|
101 |
+
if ( isset( $results['error'] ) ) {
|
102 |
+
return array(
|
103 |
+
'success' => false,
|
104 |
+
'data' => $results,
|
105 |
+
);
|
106 |
+
}
|
107 |
+
|
108 |
+
// Success!
|
109 |
+
return array(
|
110 |
+
'success' => true,
|
111 |
+
'data' => $results,
|
112 |
+
);
|
113 |
+
}
|
114 |
+
|
115 |
+
}
|
116 |
+
|
117 |
+
/**
|
118 |
+
* Kicking this off by calling 'get_instance()' method
|
119 |
+
*/
|
120 |
+
Astra_Sites_Helper::get_instance();
|
121 |
+
|
122 |
+
endif;
|
importers/class-widgets-importer.php
ADDED
@@ -0,0 +1,278 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Widget Data exporter class.
|
4 |
+
*
|
5 |
+
* @package Astra Addon
|
6 |
+
* @see - https://wordpress.org/plugins/widget-importer-exporter/
|
7 |
+
*/
|
8 |
+
|
9 |
+
defined( 'ABSPATH' ) or exit;
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Widget Data exporter class.
|
13 |
+
*
|
14 |
+
* @see - https://wordpress.org/plugins/widget-importer-exporter/
|
15 |
+
*/
|
16 |
+
class Astra_Widget_Importer {
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Instance of Astra_Widget_Importer
|
20 |
+
*
|
21 |
+
* @var Astra_Widget_Importer
|
22 |
+
*/
|
23 |
+
private static $_instance = null;
|
24 |
+
|
25 |
+
public static function instance() {
|
26 |
+
|
27 |
+
if ( ! isset( self::$_instance ) ) {
|
28 |
+
self::$_instance = new self;
|
29 |
+
}
|
30 |
+
|
31 |
+
return self::$_instance;
|
32 |
+
}
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Available widgets
|
36 |
+
*
|
37 |
+
* Gather site's widgets into array with ID base, name, etc.
|
38 |
+
* Used by export and import functions.
|
39 |
+
*
|
40 |
+
* @since 0.4
|
41 |
+
* @global array $wp_registered_widget_updates
|
42 |
+
* @return array Widget information
|
43 |
+
*/
|
44 |
+
function wie_available_widgets() {
|
45 |
+
|
46 |
+
global $wp_registered_widget_controls;
|
47 |
+
|
48 |
+
$widget_controls = $wp_registered_widget_controls;
|
49 |
+
|
50 |
+
$available_widgets = array();
|
51 |
+
|
52 |
+
foreach ( $widget_controls as $widget ) {
|
53 |
+
|
54 |
+
if ( ! empty( $widget['id_base'] ) && ! isset( $available_widgets[ $widget['id_base'] ] ) ) { // no dupes
|
55 |
+
|
56 |
+
$available_widgets[ $widget['id_base'] ]['id_base'] = $widget['id_base'];
|
57 |
+
$available_widgets[ $widget['id_base'] ]['name'] = $widget['name'];
|
58 |
+
|
59 |
+
}
|
60 |
+
}
|
61 |
+
|
62 |
+
return apply_filters( 'wie_available_widgets', $available_widgets );
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Import widget JSON data
|
67 |
+
*
|
68 |
+
* @since 0.4
|
69 |
+
* @global array $wp_registered_sidebars
|
70 |
+
*
|
71 |
+
* @param object $data JSON widget data from .wie file
|
72 |
+
*
|
73 |
+
* @return array Results array
|
74 |
+
*/
|
75 |
+
function import_widgets_data( $data ) {
|
76 |
+
|
77 |
+
global $wp_registered_sidebars;
|
78 |
+
|
79 |
+
// Have valid data?
|
80 |
+
// If no data or could not decode
|
81 |
+
if ( empty( $data ) || ! is_object( $data ) ) {
|
82 |
+
wp_die(
|
83 |
+
esc_html__( 'Import data could not be read. Please try a different file.', 'astra-sites' ),
|
84 |
+
'',
|
85 |
+
array(
|
86 |
+
'back_link' => true,
|
87 |
+
)
|
88 |
+
);
|
89 |
+
}
|
90 |
+
|
91 |
+
// Hook before import
|
92 |
+
do_action( 'wie_before_import' );
|
93 |
+
$data = apply_filters( 'wie_import_data', $data );
|
94 |
+
|
95 |
+
// Get all available widgets site supports
|
96 |
+
$available_widgets = $this->wie_available_widgets();
|
97 |
+
|
98 |
+
// Get all existing widget instances
|
99 |
+
$widget_instances = array();
|
100 |
+
foreach ( $available_widgets as $widget_data ) {
|
101 |
+
$widget_instances[ $widget_data['id_base'] ] = get_option( 'widget_' . $widget_data['id_base'] );
|
102 |
+
}
|
103 |
+
|
104 |
+
// Begin results
|
105 |
+
$results = array();
|
106 |
+
|
107 |
+
// Loop import data's sidebars
|
108 |
+
foreach ( $data as $sidebar_id => $widgets ) {
|
109 |
+
|
110 |
+
// Skip inactive widgets
|
111 |
+
// (should not be in export file)
|
112 |
+
if ( 'wp_inactive_widgets' == $sidebar_id ) {
|
113 |
+
continue;
|
114 |
+
}
|
115 |
+
|
116 |
+
// Check if sidebar is available on this site
|
117 |
+
// Otherwise add widgets to inactive, and say so
|
118 |
+
if ( isset( $wp_registered_sidebars[ $sidebar_id ] ) ) {
|
119 |
+
$sidebar_available = true;
|
120 |
+
$use_sidebar_id = $sidebar_id;
|
121 |
+
$sidebar_message_type = 'success';
|
122 |
+
$sidebar_message = '';
|
123 |
+
} else {
|
124 |
+
$sidebar_available = false;
|
125 |
+
$use_sidebar_id = 'wp_inactive_widgets'; // add to inactive if sidebar does not exist in theme
|
126 |
+
$sidebar_message_type = 'error';
|
127 |
+
$sidebar_message = esc_html__( 'Widget area does not exist in theme (using Inactive)', 'astra-sites' );
|
128 |
+
}
|
129 |
+
|
130 |
+
// Result for sidebar
|
131 |
+
$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
|
132 |
+
$results[ $sidebar_id ]['message_type'] = $sidebar_message_type;
|
133 |
+
$results[ $sidebar_id ]['message'] = $sidebar_message;
|
134 |
+
$results[ $sidebar_id ]['widgets'] = array();
|
135 |
+
|
136 |
+
// Loop widgets
|
137 |
+
foreach ( $widgets as $widget_instance_id => $widget ) {
|
138 |
+
|
139 |
+
$fail = false;
|
140 |
+
|
141 |
+
// Get id_base (remove -# from end) and instance ID number
|
142 |
+
$id_base = preg_replace( '/-[0-9]+$/', '', $widget_instance_id );
|
143 |
+
$instance_id_number = str_replace( $id_base . '-', '', $widget_instance_id );
|
144 |
+
|
145 |
+
// Does site support this widget?
|
146 |
+
if ( ! $fail && ! isset( $available_widgets[ $id_base ] ) ) {
|
147 |
+
$fail = true;
|
148 |
+
$widget_message_type = 'error';
|
149 |
+
$widget_message = esc_html__( 'Site does not support widget', 'astra-sites' ); // explain why widget not imported
|
150 |
+
}
|
151 |
+
|
152 |
+
// Filter to modify settings object before conversion to array and import
|
153 |
+
// Leave this filter here for backwards compatibility with manipulating objects (before conversion to array below)
|
154 |
+
// Ideally the newer wie_widget_settings_array below will be used instead of this
|
155 |
+
$widget = apply_filters( 'wie_widget_settings', $widget ); // object
|
156 |
+
|
157 |
+
// Convert multidimensional objects to multidimensional arrays
|
158 |
+
// Some plugins like Jetpack Widget Visibility store settings as multidimensional arrays
|
159 |
+
// Without this, they are imported as objects and cause fatal error on Widgets page
|
160 |
+
// 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
|
161 |
+
// It is probably much more likely that arrays are used than objects, however
|
162 |
+
$widget = json_decode( wp_json_encode( $widget ), true );
|
163 |
+
|
164 |
+
// Filter to modify settings array
|
165 |
+
// This is preferred over the older wie_widget_settings filter above
|
166 |
+
// Do before identical check because changes may make it identical to end result (such as URL replacements)
|
167 |
+
$widget = apply_filters( 'wie_widget_settings_array', $widget );
|
168 |
+
|
169 |
+
// Does widget with identical settings already exist in same sidebar?
|
170 |
+
if ( ! $fail && isset( $widget_instances[ $id_base ] ) ) {
|
171 |
+
|
172 |
+
// Get existing widgets in this sidebar
|
173 |
+
$sidebars_widgets = get_option( 'sidebars_widgets' );
|
174 |
+
$sidebar_widgets = isset( $sidebars_widgets[ $use_sidebar_id ] ) ? $sidebars_widgets[ $use_sidebar_id ] : array(); // check Inactive if that's where will go
|
175 |
+
|
176 |
+
// Loop widgets with ID base
|
177 |
+
$single_widget_instances = ! empty( $widget_instances[ $id_base ] ) ? $widget_instances[ $id_base ] : array();
|
178 |
+
foreach ( $single_widget_instances as $check_id => $check_widget ) {
|
179 |
+
|
180 |
+
// Is widget in same sidebar and has identical settings?
|
181 |
+
if ( in_array( "$id_base-$check_id", $sidebar_widgets ) && (array) $widget == $check_widget ) {
|
182 |
+
|
183 |
+
$fail = true;
|
184 |
+
$widget_message_type = 'warning';
|
185 |
+
$widget_message = esc_html__( 'Widget already exists', 'astra-sites' ); // explain why widget not imported
|
186 |
+
|
187 |
+
break;
|
188 |
+
|
189 |
+
}
|
190 |
+
}
|
191 |
+
}
|
192 |
+
|
193 |
+
// No failure
|
194 |
+
if ( ! $fail ) {
|
195 |
+
|
196 |
+
// Add widget instance
|
197 |
+
$single_widget_instances = get_option( 'widget_' . $id_base ); // all instances for that widget ID base, get fresh every time
|
198 |
+
$single_widget_instances = ! empty( $single_widget_instances ) ? $single_widget_instances : array(
|
199 |
+
'_multiwidget' => 1,
|
200 |
+
); // start fresh if have to
|
201 |
+
$single_widget_instances[] = $widget; // add it
|
202 |
+
|
203 |
+
// Get the key it was given
|
204 |
+
end( $single_widget_instances );
|
205 |
+
$new_instance_id_number = key( $single_widget_instances );
|
206 |
+
|
207 |
+
// If key is 0, make it 1
|
208 |
+
// 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)
|
209 |
+
if ( '0' === strval( $new_instance_id_number ) ) {
|
210 |
+
$new_instance_id_number = 1;
|
211 |
+
$single_widget_instances[ $new_instance_id_number ] = $single_widget_instances[0];
|
212 |
+
unset( $single_widget_instances[0] );
|
213 |
+
}
|
214 |
+
|
215 |
+
// Move _multiwidget to end of array for uniformity
|
216 |
+
if ( isset( $single_widget_instances['_multiwidget'] ) ) {
|
217 |
+
$multiwidget = $single_widget_instances['_multiwidget'];
|
218 |
+
unset( $single_widget_instances['_multiwidget'] );
|
219 |
+
$single_widget_instances['_multiwidget'] = $multiwidget;
|
220 |
+
}
|
221 |
+
|
222 |
+
// Update option with new widget
|
223 |
+
$result = update_option( 'widget_' . $id_base, $single_widget_instances );
|
224 |
+
|
225 |
+
// Assign widget instance to sidebar
|
226 |
+
$sidebars_widgets = get_option( 'sidebars_widgets' ); // which sidebars have which widgets, get fresh every time
|
227 |
+
|
228 |
+
// Avoid rarely fatal error when the option is an empty string
|
229 |
+
// https://github.com/churchthemes/widget-importer-exporter/pull/11
|
230 |
+
if ( ! $sidebars_widgets ) {
|
231 |
+
$sidebars_widgets = array();
|
232 |
+
}
|
233 |
+
|
234 |
+
$new_instance_id = $id_base . '-' . $new_instance_id_number; // use ID number from new widget instance
|
235 |
+
$sidebars_widgets[ $use_sidebar_id ][] = $new_instance_id; // add new instance to sidebar
|
236 |
+
update_option( 'sidebars_widgets', $sidebars_widgets ); // save the amended data
|
237 |
+
|
238 |
+
// After widget import action
|
239 |
+
$after_widget_import = array(
|
240 |
+
'sidebar' => $use_sidebar_id,
|
241 |
+
'sidebar_old' => $sidebar_id,
|
242 |
+
'widget' => $widget,
|
243 |
+
'widget_type' => $id_base,
|
244 |
+
'widget_id' => $new_instance_id,
|
245 |
+
'widget_id_old' => $widget_instance_id,
|
246 |
+
'widget_id_num' => $new_instance_id_number,
|
247 |
+
'widget_id_num_old' => $instance_id_number,
|
248 |
+
);
|
249 |
+
do_action( 'wie_after_widget_import', $after_widget_import );
|
250 |
+
|
251 |
+
// Success message
|
252 |
+
if ( $sidebar_available ) {
|
253 |
+
$widget_message_type = 'success';
|
254 |
+
$widget_message = esc_html__( 'Imported', 'astra-sites' );
|
255 |
+
} else {
|
256 |
+
$widget_message_type = 'warning';
|
257 |
+
$widget_message = esc_html__( 'Imported to Inactive', 'astra-sites' );
|
258 |
+
}
|
259 |
+
}// End if().
|
260 |
+
|
261 |
+
// Result for widget instance
|
262 |
+
$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)
|
263 |
+
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['title'] = ! empty( $widget['title'] ) ? $widget['title'] : esc_html__( 'No Title', 'astra-sites' ); // show "No Title" if widget instance is untitled
|
264 |
+
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['message_type'] = $widget_message_type;
|
265 |
+
$results[ $sidebar_id ]['widgets'][ $widget_instance_id ]['message'] = $widget_message;
|
266 |
+
|
267 |
+
}// End foreach().
|
268 |
+
}// End foreach().
|
269 |
+
|
270 |
+
// Hook after import
|
271 |
+
do_action( 'wie_after_import' );
|
272 |
+
|
273 |
+
// Return results
|
274 |
+
return apply_filters( 'wie_import_results', $results );
|
275 |
+
|
276 |
+
}
|
277 |
+
|
278 |
+
}
|
importers/wxr-importer/class-astra-wxr-importer.php
ADDED
@@ -0,0 +1,119 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Class Astra WXR Importer
|
4 |
+
*
|
5 |
+
* @since 1.0.0
|
6 |
+
* @package Astra Addon
|
7 |
+
*/
|
8 |
+
|
9 |
+
defined( 'ABSPATH' ) or exit;
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Class Astra WXR Importer
|
13 |
+
*
|
14 |
+
* @since 1.0.0
|
15 |
+
*/
|
16 |
+
class Astra_WXR_Importer {
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Instance of Astra_WXR_Importer
|
20 |
+
*
|
21 |
+
* @since 1.0.0
|
22 |
+
* @var Astra_WXR_Importer
|
23 |
+
*/
|
24 |
+
private static $_instance = null;
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Instantiate Astra_WXR_Importer
|
28 |
+
*
|
29 |
+
* @since 1.0.0
|
30 |
+
* @return (Object) Astra_WXR_Importer.
|
31 |
+
*/
|
32 |
+
public static function instance() {
|
33 |
+
if ( ! isset( self::$_instance ) ) {
|
34 |
+
self::$_instance = new self();
|
35 |
+
}
|
36 |
+
|
37 |
+
return self::$_instance;
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Constructor.
|
42 |
+
*
|
43 |
+
* @since 1.0.0
|
44 |
+
*/
|
45 |
+
private function __construct() {
|
46 |
+
$this->includes();
|
47 |
+
|
48 |
+
add_filter( 'upload_mimes', array( $this, 'custom_upload_mimes' ) );
|
49 |
+
}
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Add .xml files as supported format in the uploader.
|
53 |
+
*
|
54 |
+
* @param array $mimes Already supported mime types.
|
55 |
+
*/
|
56 |
+
public function custom_upload_mimes( $mimes ) {
|
57 |
+
$mimes = array_merge(
|
58 |
+
$mimes, array(
|
59 |
+
'xml' => 'application/xml',
|
60 |
+
)
|
61 |
+
);
|
62 |
+
|
63 |
+
return $mimes;
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Include required files.
|
68 |
+
*
|
69 |
+
* @since 1.0.0
|
70 |
+
*/
|
71 |
+
private function includes() {
|
72 |
+
if ( ! class_exists( 'WP_Importer' ) ) {
|
73 |
+
defined( 'WP_LOAD_IMPORTERS' ) || define( 'WP_LOAD_IMPORTERS', true );
|
74 |
+
require ABSPATH . '/wp-admin/includes/class-wp-importer.php';
|
75 |
+
}
|
76 |
+
require_once ASTRA_SITES_DIR . 'importers/wxr-importer/class-wxr-importer.php';
|
77 |
+
require_once ASTRA_SITES_DIR . 'importers/wxr-importer/class-logger.php';
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* Start the xml import.
|
82 |
+
*
|
83 |
+
* @since 1.0.0
|
84 |
+
*
|
85 |
+
* @param (String) $path Absolute path to the XML file.
|
86 |
+
*/
|
87 |
+
public function import_xml( $path ) {
|
88 |
+
$options = array(
|
89 |
+
'fetch_attachments' => true,
|
90 |
+
'default_author' => 0,
|
91 |
+
);
|
92 |
+
$logger = new WP_Importer_Logger();
|
93 |
+
$importer = new WXR_Importer( $options );
|
94 |
+
$importer->set_logger( $logger );
|
95 |
+
$result = $importer->import( $path );
|
96 |
+
}
|
97 |
+
|
98 |
+
/**
|
99 |
+
* Download and save XML file to uploads directory.
|
100 |
+
*
|
101 |
+
* @since 1.0.0
|
102 |
+
*
|
103 |
+
* @param (String) $url URL of the xml file.
|
104 |
+
*
|
105 |
+
* @return (Array) Attachment array of the downloaded xml file.
|
106 |
+
*/
|
107 |
+
public function download_xml( $url ) {
|
108 |
+
|
109 |
+
// Download XML file.
|
110 |
+
$response = Astra_Sites_Helper::download_file( $url );
|
111 |
+
|
112 |
+
// Is Success?
|
113 |
+
if ( $response['success'] ) {
|
114 |
+
return $response['data'];
|
115 |
+
}
|
116 |
+
|
117 |
+
}
|
118 |
+
|
119 |
+
}
|
importers/wxr-importer/class-logger.php
ADDED
@@ -0,0 +1,136 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Describes a logger instance
|
5 |
+
*
|
6 |
+
* Based on PSR-3: http://www.php-fig.org/psr/psr-3/
|
7 |
+
*
|
8 |
+
* The message MUST be a string or object implementing __toString().
|
9 |
+
*
|
10 |
+
* The message MAY contain placeholders in the form: {foo} where foo
|
11 |
+
* will be replaced by the context data in key "foo".
|
12 |
+
*
|
13 |
+
* The context array can contain arbitrary data, the only assumption that
|
14 |
+
* can be made by implementors is that if an Exception instance is given
|
15 |
+
* to produce a stack trace, it MUST be in a key named "exception".
|
16 |
+
*
|
17 |
+
* See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
|
18 |
+
* for the full interface specification.
|
19 |
+
*/
|
20 |
+
class WP_Importer_Logger {
|
21 |
+
/**
|
22 |
+
* System is unusable.
|
23 |
+
*
|
24 |
+
* @param string $message
|
25 |
+
* @param array $context
|
26 |
+
* @return null
|
27 |
+
*/
|
28 |
+
public function emergency( $message, array $context = array() ) {
|
29 |
+
return $this->log( 'emergency', $message, $context );
|
30 |
+
}
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Action must be taken immediately.
|
34 |
+
*
|
35 |
+
* Example: Entire website down, database unavailable, etc. This should
|
36 |
+
* trigger the SMS alerts and wake you up.
|
37 |
+
*
|
38 |
+
* @param string $message
|
39 |
+
* @param array $context
|
40 |
+
* @return null
|
41 |
+
*/
|
42 |
+
public function alert( $message, array $context = array() ) {
|
43 |
+
return $this->log( 'alert', $message, $context );
|
44 |
+
}
|
45 |
+
|
46 |
+
/**
|
47 |
+
* Critical conditions.
|
48 |
+
*
|
49 |
+
* Example: Application component unavailable, unexpected exception.
|
50 |
+
*
|
51 |
+
* @param string $message
|
52 |
+
* @param array $context
|
53 |
+
* @return null
|
54 |
+
*/
|
55 |
+
public function critical( $message, array $context = array() ) {
|
56 |
+
return $this->log( 'critical', $message, $context );
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Runtime errors that do not require immediate action but should typically
|
61 |
+
* be logged and monitored.
|
62 |
+
*
|
63 |
+
* @param string $message
|
64 |
+
* @param array $context
|
65 |
+
* @return null
|
66 |
+
*/
|
67 |
+
public function error( $message, array $context = array() ) {
|
68 |
+
return $this->log( 'error', $message, $context );
|
69 |
+
}
|
70 |
+
|
71 |
+
/**
|
72 |
+
* Exceptional occurrences that are not errors.
|
73 |
+
*
|
74 |
+
* Example: Use of deprecated APIs, poor use of an API, undesirable things
|
75 |
+
* that are not necessarily wrong.
|
76 |
+
*
|
77 |
+
* @param string $message
|
78 |
+
* @param array $context
|
79 |
+
* @return null
|
80 |
+
*/
|
81 |
+
public function warning( $message, array $context = array() ) {
|
82 |
+
return $this->log( 'warning', $message, $context );
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Normal but significant events.
|
87 |
+
*
|
88 |
+
* @param string $message
|
89 |
+
* @param array $context
|
90 |
+
* @return null
|
91 |
+
*/
|
92 |
+
public function notice( $message, array $context = array() ) {
|
93 |
+
return $this->log( 'notice', $message, $context );
|
94 |
+
}
|
95 |
+
|
96 |
+
/**
|
97 |
+
* Interesting events.
|
98 |
+
*
|
99 |
+
* Example: User logs in, SQL logs.
|
100 |
+
*
|
101 |
+
* @param string $message
|
102 |
+
* @param array $context
|
103 |
+
* @return null
|
104 |
+
*/
|
105 |
+
public function info( $message, array $context = array() ) {
|
106 |
+
return $this->log( 'info', $message, $context );
|
107 |
+
}
|
108 |
+
|
109 |
+
/**
|
110 |
+
* Detailed debug information.
|
111 |
+
*
|
112 |
+
* @param string $message
|
113 |
+
* @param array $context
|
114 |
+
* @return null
|
115 |
+
*/
|
116 |
+
public function debug( $message, array $context = array() ) {
|
117 |
+
return $this->log( 'debug', $message, $context );
|
118 |
+
}
|
119 |
+
|
120 |
+
/**
|
121 |
+
* Logs with an arbitrary level.
|
122 |
+
*
|
123 |
+
* @param mixed $level
|
124 |
+
* @param string $message
|
125 |
+
* @param array $context
|
126 |
+
* @return null
|
127 |
+
*/
|
128 |
+
public function log( $level, $message, array $context = array() ) {
|
129 |
+
$this->messages[] = array(
|
130 |
+
'timestamp' => time(),
|
131 |
+
'level' => $level,
|
132 |
+
'message' => $message,
|
133 |
+
'context' => $context,
|
134 |
+
);
|
135 |
+
}
|
136 |
+
}
|
importers/wxr-importer/class-wxr-importer.php
ADDED
@@ -0,0 +1,2299 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class WXR_Importer extends WP_Importer {
|
4 |
+
/**
|
5 |
+
* Maximum supported WXR version
|
6 |
+
*/
|
7 |
+
const MAX_WXR_VERSION = 1.2;
|
8 |
+
|
9 |
+
/**
|
10 |
+
* Regular expression for checking if a post references an attachment
|
11 |
+
*
|
12 |
+
* Note: This is a quick, weak check just to exclude text-only posts. More
|
13 |
+
* vigorous checking is done later to verify.
|
14 |
+
*/
|
15 |
+
const REGEX_HAS_ATTACHMENT_REFS = '!
|
16 |
+
(
|
17 |
+
# Match anything with an image or attachment class
|
18 |
+
class=[\'"].*?\b(wp-image-\d+|attachment-[\w\-]+)\b
|
19 |
+
|
|
20 |
+
# Match anything that looks like an upload URL
|
21 |
+
src=[\'"][^\'"]*(
|
22 |
+
[0-9]{4}/[0-9]{2}/[^\'"]+\.(jpg|jpeg|png|gif)
|
23 |
+
|
|
24 |
+
content/uploads[^\'"]+
|
25 |
+
)[\'"]
|
26 |
+
)!ix';
|
27 |
+
|
28 |
+
/**
|
29 |
+
* Version of WXR we're importing.
|
30 |
+
*
|
31 |
+
* Defaults to 1.0 for compatibility. Typically overridden by a
|
32 |
+
* `<wp:wxr_version>` tag at the start of the file.
|
33 |
+
*
|
34 |
+
* @var string
|
35 |
+
*/
|
36 |
+
protected $version = '1.0';
|
37 |
+
|
38 |
+
// information to import from WXR file
|
39 |
+
protected $categories = array();
|
40 |
+
protected $tags = array();
|
41 |
+
protected $base_url = '';
|
42 |
+
|
43 |
+
// TODO: REMOVE THESE
|
44 |
+
protected $processed_terms = array();
|
45 |
+
protected $processed_posts = array();
|
46 |
+
protected $processed_menu_items = array();
|
47 |
+
protected $menu_item_orphans = array();
|
48 |
+
protected $missing_menu_items = array();
|
49 |
+
|
50 |
+
// NEW STYLE
|
51 |
+
protected $mapping = array();
|
52 |
+
protected $requires_remapping = array();
|
53 |
+
protected $exists = array();
|
54 |
+
protected $user_slug_override = array();
|
55 |
+
|
56 |
+
protected $url_remap = array();
|
57 |
+
protected $featured_images = array();
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Logger instance.
|
61 |
+
*
|
62 |
+
* @var WP_Importer_Logger
|
63 |
+
*/
|
64 |
+
protected $logger;
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Constructor
|
68 |
+
*
|
69 |
+
* @param array $options {
|
70 |
+
* @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.)
|
71 |
+
* @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.)
|
72 |
+
* @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.)
|
73 |
+
* @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 deduplication and reimporting. Default is false.)
|
74 |
+
* @var bool $fetch_attachments Fetch attachments from the remote server. (True fetches and creates attachment posts, false skips attachments. Default is false.)
|
75 |
+
* @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.)
|
76 |
+
* @var int $default_author User ID to use if author is missing or invalid. (Default is null, which leaves posts unassigned.)
|
77 |
+
* }
|
78 |
+
*/
|
79 |
+
public function __construct( $options = array() ) {
|
80 |
+
// Initialize some important variables
|
81 |
+
$empty_types = array(
|
82 |
+
'post' => array(),
|
83 |
+
'comment' => array(),
|
84 |
+
'term' => array(),
|
85 |
+
'user' => array(),
|
86 |
+
);
|
87 |
+
|
88 |
+
$this->mapping = $empty_types;
|
89 |
+
$this->mapping['user_slug'] = array();
|
90 |
+
$this->mapping['term_id'] = array();
|
91 |
+
$this->requires_remapping = $empty_types;
|
92 |
+
$this->exists = $empty_types;
|
93 |
+
|
94 |
+
$this->options = wp_parse_args( $options, array(
|
95 |
+
'prefill_existing_posts' => true,
|
96 |
+
'prefill_existing_comments' => true,
|
97 |
+
'prefill_existing_terms' => true,
|
98 |
+
'update_attachment_guids' => false,
|
99 |
+
'fetch_attachments' => false,
|
100 |
+
'aggressive_url_search' => false,
|
101 |
+
'default_author' => null,
|
102 |
+
) );
|
103 |
+
}
|
104 |
+
|
105 |
+
public function set_logger( $logger ) {
|
106 |
+
$this->logger = $logger;
|
107 |
+
}
|
108 |
+
|
109 |
+
/**
|
110 |
+
* Get a stream reader for the file.
|
111 |
+
*
|
112 |
+
* @param string $file Path to the XML file.
|
113 |
+
* @return XMLReader|WP_Error Reader instance on success, error otherwise.
|
114 |
+
*/
|
115 |
+
protected function get_reader( $file ) {
|
116 |
+
// Avoid loading external entities for security
|
117 |
+
$old_value = null;
|
118 |
+
if ( function_exists( 'libxml_disable_entity_loader' ) ) {
|
119 |
+
// $old_value = libxml_disable_entity_loader( true );
|
120 |
+
}
|
121 |
+
|
122 |
+
$reader = new XMLReader();
|
123 |
+
$status = $reader->open( $file );
|
124 |
+
|
125 |
+
if ( ! is_null( $old_value ) ) {
|
126 |
+
// libxml_disable_entity_loader( $old_value );
|
127 |
+
}
|
128 |
+
|
129 |
+
if ( ! $status ) {
|
130 |
+
return new WP_Error( 'wxr_importer.cannot_parse', __( 'Could not open the file for parsing', 'wordpress-importer' ) );
|
131 |
+
}
|
132 |
+
|
133 |
+
return $reader;
|
134 |
+
}
|
135 |
+
|
136 |
+
/**
|
137 |
+
* The main controller for the actual import stage.
|
138 |
+
*
|
139 |
+
* @param string $file Path to the WXR file for importing
|
140 |
+
*/
|
141 |
+
public function get_preliminary_information( $file ) {
|
142 |
+
// Let's run the actual importer now, woot
|
143 |
+
$reader = $this->get_reader( $file );
|
144 |
+
if ( is_wp_error( $reader ) ) {
|
145 |
+
return $reader;
|
146 |
+
}
|
147 |
+
|
148 |
+
// Set the version to compatibility mode first
|
149 |
+
$this->version = '1.0';
|
150 |
+
|
151 |
+
// Start parsing!
|
152 |
+
$data = new WXR_Import_Info();
|
153 |
+
while ( $reader->read() ) {
|
154 |
+
// Only deal with element opens
|
155 |
+
if ( $reader->nodeType !== XMLReader::ELEMENT ) {
|
156 |
+
continue;
|
157 |
+
}
|
158 |
+
|
159 |
+
switch ( $reader->name ) {
|
160 |
+
case 'wp:wxr_version':
|
161 |
+
// Upgrade to the correct version
|
162 |
+
$this->version = $reader->readString();
|
163 |
+
|
164 |
+
if ( version_compare( $this->version, self::MAX_WXR_VERSION, '>' ) ) {
|
165 |
+
$this->logger->warning( sprintf(
|
166 |
+
__( 'This WXR file (version %1$s) is newer than the importer (version %2$s) and may not be supported. Please consider updating.', 'wordpress-importer' ),
|
167 |
+
$this->version,
|
168 |
+
self::MAX_WXR_VERSION
|
169 |
+
) );
|
170 |
+
}
|
171 |
+
|
172 |
+
// Handled everything in this node, move on to the next
|
173 |
+
$reader->next();
|
174 |
+
break;
|
175 |
+
|
176 |
+
case 'generator':
|
177 |
+
$data->generator = $reader->readString();
|
178 |
+
$reader->next();
|
179 |
+
break;
|
180 |
+
|
181 |
+
case 'title':
|
182 |
+
$data->title = $reader->readString();
|
183 |
+
$reader->next();
|
184 |
+
break;
|
185 |
+
|
186 |
+
case 'wp:base_site_url':
|
187 |
+
$data->siteurl = $reader->readString();
|
188 |
+
$reader->next();
|
189 |
+
break;
|
190 |
+
|
191 |
+
case 'wp:base_blog_url':
|
192 |
+
$data->home = $reader->readString();
|
193 |
+
$reader->next();
|
194 |
+
break;
|
195 |
+
|
196 |
+
case 'wp:author':
|
197 |
+
$node = $reader->expand();
|
198 |
+
|
199 |
+
$parsed = $this->parse_author_node( $node );
|
200 |
+
if ( is_wp_error( $parsed ) ) {
|
201 |
+
$this->log_error( $parsed );
|
202 |
+
|
203 |
+
// Skip the rest of this post
|
204 |
+
$reader->next();
|
205 |
+
break;
|
206 |
+
}
|
207 |
+
|
208 |
+
$data->users[] = $parsed;
|
209 |
+
|
210 |
+
// Handled everything in this node, move on to the next
|
211 |
+
$reader->next();
|
212 |
+
break;
|
213 |
+
|
214 |
+
case 'item':
|
215 |
+
$node = $reader->expand();
|
216 |
+
$parsed = $this->parse_post_node( $node );
|
217 |
+
if ( is_wp_error( $parsed ) ) {
|
218 |
+
$this->log_error( $parsed );
|
219 |
+
|
220 |
+
// Skip the rest of this post
|
221 |
+
$reader->next();
|
222 |
+
break;
|
223 |
+
}
|
224 |
+
|
225 |
+
if ( $parsed['data']['post_type'] === 'attachment' ) {
|
226 |
+
$data->media_count++;
|
227 |
+
} else {
|
228 |
+
$data->post_count++;
|
229 |
+
}
|
230 |
+
$data->comment_count += count( $parsed['comments'] );
|
231 |
+
|
232 |
+
// Handled everything in this node, move on to the next
|
233 |
+
$reader->next();
|
234 |
+
break;
|
235 |
+
|
236 |
+
case 'wp:category':
|
237 |
+
case 'wp:tag':
|
238 |
+
case 'wp:term':
|
239 |
+
$data->term_count++;
|
240 |
+
|
241 |
+
// Handled everything in this node, move on to the next
|
242 |
+
$reader->next();
|
243 |
+
break;
|
244 |
+
}// End switch().
|
245 |
+
}// End while().
|
246 |
+
|
247 |
+
$data->version = $this->version;
|
248 |
+
|
249 |
+
return $data;
|
250 |
+
}
|
251 |
+
|
252 |
+
/**
|
253 |
+
* The main controller for the actual import stage.
|
254 |
+
*
|
255 |
+
* @param string $file Path to the WXR file for importing
|
256 |
+
*/
|
257 |
+
public function parse_authors( $file ) {
|
258 |
+
// Let's run the actual importer now, woot
|
259 |
+
$reader = $this->get_reader( $file );
|
260 |
+
if ( is_wp_error( $reader ) ) {
|
261 |
+
return $reader;
|
262 |
+
}
|
263 |
+
|
264 |
+
// Set the version to compatibility mode first
|
265 |
+
$this->version = '1.0';
|
266 |
+
|
267 |
+
// Start parsing!
|
268 |
+
$authors = array();
|
269 |
+
while ( $reader->read() ) {
|
270 |
+
// Only deal with element opens
|
271 |
+
if ( $reader->nodeType !== XMLReader::ELEMENT ) {
|
272 |
+
continue;
|
273 |
+
}
|
274 |
+
|
275 |
+
switch ( $reader->name ) {
|
276 |
+
case 'wp:wxr_version':
|
277 |
+
// Upgrade to the correct version
|
278 |
+
$this->version = $reader->readString();
|
279 |
+
|
280 |
+
if ( version_compare( $this->version, self::MAX_WXR_VERSION, '>' ) ) {
|
281 |
+
$this->logger->warning( sprintf(
|
282 |
+
__( 'This WXR file (version %1$s) is newer than the importer (version %2$s) and may not be supported. Please consider updating.', 'wordpress-importer' ),
|
283 |
+
$this->version,
|
284 |
+
self::MAX_WXR_VERSION
|
285 |
+
) );
|
286 |
+
}
|
287 |
+
|
288 |
+
// Handled everything in this node, move on to the next
|
289 |
+
$reader->next();
|
290 |
+
break;
|
291 |
+
|
292 |
+
case 'wp:author':
|
293 |
+
$node = $reader->expand();
|
294 |
+
|
295 |
+
$parsed = $this->parse_author_node( $node );
|
296 |
+
if ( is_wp_error( $parsed ) ) {
|
297 |
+
$this->log_error( $parsed );
|
298 |
+
|
299 |
+
// Skip the rest of this post
|
300 |
+
$reader->next();
|
301 |
+
break;
|
302 |
+
}
|
303 |
+
|
304 |
+
$authors[] = $parsed;
|
305 |
+
|
306 |
+
// Handled everything in this node, move on to the next
|
307 |
+
$reader->next();
|
308 |
+
break;
|
309 |
+
}
|
310 |
+
}// End while().
|
311 |
+
|
312 |
+
return $authors;
|
313 |
+
}
|
314 |
+
|
315 |
+
/**
|
316 |
+
* The main controller for the actual import stage.
|
317 |
+
*
|
318 |
+
* @param string $file Path to the WXR file for importing
|
319 |
+
*/
|
320 |
+
public function import( $file ) {
|
321 |
+
add_filter( 'import_post_meta_key', array( $this, 'is_valid_meta_key' ) );
|
322 |
+
add_filter( 'http_request_timeout', array( &$this, 'bump_request_timeout' ) );
|
323 |
+
|
324 |
+
$result = $this->import_start( $file );
|
325 |
+
if ( is_wp_error( $result ) ) {
|
326 |
+
return $result;
|
327 |
+
}
|
328 |
+
|
329 |
+
// Let's run the actual importer now, woot
|
330 |
+
$reader = $this->get_reader( $file );
|
331 |
+
if ( is_wp_error( $reader ) ) {
|
332 |
+
return $reader;
|
333 |
+
}
|
334 |
+
|
335 |
+
// Set the version to compatibility mode first
|
336 |
+
$this->version = '1.0';
|
337 |
+
|
338 |
+
// Reset other variables
|
339 |
+
$this->base_url = '';
|
340 |
+
|
341 |
+
// Start parsing!
|
342 |
+
while ( $reader->read() ) {
|
343 |
+
// Only deal with element opens
|
344 |
+
if ( $reader->nodeType !== XMLReader::ELEMENT ) {
|
345 |
+
continue;
|
346 |
+
}
|
347 |
+
|
348 |
+
switch ( $reader->name ) {
|
349 |
+
case 'wp:wxr_version':
|
350 |
+
// Upgrade to the correct version
|
351 |
+
$this->version = $reader->readString();
|
352 |
+
|
353 |
+
if ( version_compare( $this->version, self::MAX_WXR_VERSION, '>' ) ) {
|
354 |
+
$this->logger->warning( sprintf(
|
355 |
+
__( 'This WXR file (version %1$s) is newer than the importer (version %2$s) and may not be supported. Please consider updating.', 'wordpress-importer' ),
|
356 |
+
$this->version,
|
357 |
+
self::MAX_WXR_VERSION
|
358 |
+
) );
|
359 |
+
}
|
360 |
+
|
361 |
+
// Handled everything in this node, move on to the next
|
362 |
+
$reader->next();
|
363 |
+
break;
|
364 |
+
|
365 |
+
case 'wp:base_site_url':
|
366 |
+
$this->base_url = $reader->readString();
|
367 |
+
|
368 |
+
// Handled everything in this node, move on to the next
|
369 |
+
$reader->next();
|
370 |
+
break;
|
371 |
+
|
372 |
+
case 'item':
|
373 |
+
$node = $reader->expand();
|
374 |
+
$parsed = $this->parse_post_node( $node );
|
375 |
+
if ( is_wp_error( $parsed ) ) {
|
376 |
+
$this->log_error( $parsed );
|
377 |
+
|
378 |
+
// Skip the rest of this post
|
379 |
+
$reader->next();
|
380 |
+
break;
|
381 |
+
}
|
382 |
+
|
383 |
+
$this->process_post( $parsed['data'], $parsed['meta'], $parsed['comments'], $parsed['terms'] );
|
384 |
+
|
385 |
+
// Handled everything in this node, move on to the next
|
386 |
+
$reader->next();
|
387 |
+
break;
|
388 |
+
|
389 |
+
case 'wp:author':
|
390 |
+
$node = $reader->expand();
|
391 |
+
|
392 |
+
$parsed = $this->parse_author_node( $node );
|
393 |
+
if ( is_wp_error( $parsed ) ) {
|
394 |
+
$this->log_error( $parsed );
|
395 |
+
|
396 |
+
// Skip the rest of this post
|
397 |
+
$reader->next();
|
398 |
+
break;
|
399 |
+
}
|
400 |
+
|
401 |
+
$status = $this->process_author( $parsed['data'], $parsed['meta'] );
|
402 |
+
if ( is_wp_error( $status ) ) {
|
403 |
+
$this->log_error( $status );
|
404 |
+
}
|
405 |
+
|
406 |
+
// Handled everything in this node, move on to the next
|
407 |
+
$reader->next();
|
408 |
+
break;
|
409 |
+
|
410 |
+
case 'wp:category':
|
411 |
+
$node = $reader->expand();
|
412 |
+
|
413 |
+
$parsed = $this->parse_term_node( $node, 'category' );
|
414 |
+
if ( is_wp_error( $parsed ) ) {
|
415 |
+
$this->log_error( $parsed );
|
416 |
+
|
417 |
+
// Skip the rest of this post
|
418 |
+
$reader->next();
|
419 |
+
break;
|
420 |
+
}
|
421 |
+
|
422 |
+
$status = $this->process_term( $parsed['data'], $parsed['meta'] );
|
423 |
+
|
424 |
+
// Handled everything in this node, move on to the next
|
425 |
+
$reader->next();
|
426 |
+
break;
|
427 |
+
|
428 |
+
case 'wp:tag':
|
429 |
+
$node = $reader->expand();
|
430 |
+
|
431 |
+
$parsed = $this->parse_term_node( $node, 'tag' );
|
432 |
+
if ( is_wp_error( $parsed ) ) {
|
433 |
+
$this->log_error( $parsed );
|
434 |
+
|
435 |
+
// Skip the rest of this post
|
436 |
+
$reader->next();
|
437 |
+
break;
|
438 |
+
}
|
439 |
+
|
440 |
+
$status = $this->process_term( $parsed['data'], $parsed['meta'] );
|
441 |
+
|
442 |
+
// Handled everything in this node, move on to the next
|
443 |
+
$reader->next();
|
444 |
+
break;
|
445 |
+
|
446 |
+
case 'wp:term':
|
447 |
+
$node = $reader->expand();
|
448 |
+
|
449 |
+
$parsed = $this->parse_term_node( $node );
|
450 |
+
if ( is_wp_error( $parsed ) ) {
|
451 |
+
$this->log_error( $parsed );
|
452 |
+
|
453 |
+
// Skip the rest of this post
|
454 |
+
$reader->next();
|
455 |
+
break;
|
456 |
+
}
|
457 |
+
|
458 |
+
$status = $this->process_term( $parsed['data'], $parsed['meta'] );
|
459 |
+
|
460 |
+
// Handled everything in this node, move on to the next
|
461 |
+
$reader->next();
|
462 |
+
break;
|
463 |
+
|
464 |
+
default:
|
465 |
+
// Skip this node, probably handled by something already
|
466 |
+
break;
|
467 |
+
}// End switch().
|
468 |
+
}// End while().
|
469 |
+
|
470 |
+
// Now that we've done the main processing, do any required
|
471 |
+
// post-processing and remapping.
|
472 |
+
$this->post_process();
|
473 |
+
|
474 |
+
if ( $this->options['aggressive_url_search'] ) {
|
475 |
+
$this->replace_attachment_urls_in_content();
|
476 |
+
}
|
477 |
+
// $this->remap_featured_images();
|
478 |
+
$this->import_end();
|
479 |
+
}
|
480 |
+
|
481 |
+
/**
|
482 |
+
* Log an error instance to the logger.
|
483 |
+
*
|
484 |
+
* @param WP_Error $error Error instance to log.
|
485 |
+
*/
|
486 |
+
protected function log_error( WP_Error $error ) {
|
487 |
+
$this->logger->warning( $error->get_error_message() );
|
488 |
+
|
489 |
+
// Log the data as debug info too
|
490 |
+
$data = $error->get_error_data();
|
491 |
+
if ( ! empty( $data ) ) {
|
492 |
+
$this->logger->debug( var_export( $data, true ) );
|
493 |
+
}
|
494 |
+
}
|
495 |
+
|
496 |
+
/**
|
497 |
+
* Parses the WXR file and prepares us for the task of processing parsed data
|
498 |
+
*
|
499 |
+
* @param string $file Path to the WXR file for importing
|
500 |
+
*/
|
501 |
+
protected function import_start( $file ) {
|
502 |
+
if ( ! is_file( $file ) ) {
|
503 |
+
return new WP_Error( 'wxr_importer.file_missing', __( 'The file does not exist, please try again.', 'wordpress-importer' ) );
|
504 |
+
}
|
505 |
+
|
506 |
+
// Suspend bunches of stuff in WP core
|
507 |
+
wp_defer_term_counting( true );
|
508 |
+
wp_defer_comment_counting( true );
|
509 |
+
wp_suspend_cache_invalidation( true );
|
510 |
+
|
511 |
+
// Prefill exists calls if told to
|
512 |
+
if ( $this->options['prefill_existing_posts'] ) {
|
513 |
+
$this->prefill_existing_posts();
|
514 |
+
}
|
515 |
+
if ( $this->options['prefill_existing_comments'] ) {
|
516 |
+
$this->prefill_existing_comments();
|
517 |
+
}
|
518 |
+
if ( $this->options['prefill_existing_terms'] ) {
|
519 |
+
$this->prefill_existing_terms();
|
520 |
+
}
|
521 |
+
|
522 |
+
/**
|
523 |
+
* Begin the import.
|
524 |
+
*
|
525 |
+
* Fires before the import process has begun. If you need to suspend
|
526 |
+
* caching or heavy processing on hooks, do so here.
|
527 |
+
*/
|
528 |
+
do_action( 'import_start' );
|
529 |
+
}
|
530 |
+
|
531 |
+
/**
|
532 |
+
* Performs post-import cleanup of files and the cache
|
533 |
+
*/
|
534 |
+
protected function import_end() {
|
535 |
+
// Re-enable stuff in core
|
536 |
+
wp_suspend_cache_invalidation( false );
|
537 |
+
wp_cache_flush();
|
538 |
+
foreach ( get_taxonomies() as $tax ) {
|
539 |
+
delete_option( "{$tax}_children" );
|
540 |
+
_get_term_hierarchy( $tax );
|
541 |
+
}
|
542 |
+
|
543 |
+
wp_defer_term_counting( false );
|
544 |
+
wp_defer_comment_counting( false );
|
545 |
+
|
546 |
+
/**
|
547 |
+
* Complete the import.
|
548 |
+
*
|
549 |
+
* Fires after the import process has finished. If you need to update
|
550 |
+
* your cache or re-enable processing, do so here.
|
551 |
+
*/
|
552 |
+
do_action( 'import_end' );
|
553 |
+
}
|
554 |
+
|
555 |
+
/**
|
556 |
+
* Set the user mapping.
|
557 |
+
*
|
558 |
+
* @param array $mapping List of map arrays (containing `old_slug`, `old_id`, `new_id`)
|
559 |
+
*/
|
560 |
+
public function set_user_mapping( $mapping ) {
|
561 |
+
foreach ( $mapping as $map ) {
|
562 |
+
if ( empty( $map['old_slug'] ) || empty( $map['old_id'] ) || empty( $map['new_id'] ) ) {
|
563 |
+
$this->logger->warning( __( 'Invalid author mapping', 'wordpress-importer' ) );
|
564 |
+
$this->logger->debug( var_export( $map, true ) );
|
565 |
+
continue;
|
566 |
+
}
|
567 |
+
|
568 |
+
$old_slug = $map['old_slug'];
|
569 |
+
$old_id = $map['old_id'];
|
570 |
+
$new_id = $map['new_id'];
|
571 |
+
|
572 |
+
$this->mapping['user'][ $old_id ] = $new_id;
|
573 |
+
$this->mapping['user_slug'][ $old_slug ] = $new_id;
|
574 |
+
}
|
575 |
+
}
|
576 |
+
|
577 |
+
/**
|
578 |
+
* Set the user slug overrides.
|
579 |
+
*
|
580 |
+
* Allows overriding the slug in the import with a custom/renamed version.
|
581 |
+
*
|
582 |
+
* @param string[] $overrides Map of old slug to new slug.
|
583 |
+
*/
|
584 |
+
public function set_user_slug_overrides( $overrides ) {
|
585 |
+
foreach ( $overrides as $original => $renamed ) {
|
586 |
+
$this->user_slug_override[ $original ] = $renamed;
|
587 |
+
}
|
588 |
+
}
|
589 |
+
|
590 |
+
/**
|
591 |
+
* Parse a post node into post data.
|
592 |
+
*
|
593 |
+
* @param DOMElement $node Parent node of post data (typically `item`).
|
594 |
+
* @return array|WP_Error Post data array on success, error otherwise.
|
595 |
+
*/
|
596 |
+
protected function parse_post_node( $node ) {
|
597 |
+
$data = array();
|
598 |
+
$meta = array();
|
599 |
+
$comments = array();
|
600 |
+
$terms = array();
|
601 |
+
|
602 |
+
foreach ( $node->childNodes as $child ) {
|
603 |
+
// We only care about child elements
|
604 |
+
if ( $child->nodeType !== XML_ELEMENT_NODE ) {
|
605 |
+
continue;
|
606 |
+
}
|
607 |
+
|
608 |
+
switch ( $child->tagName ) {
|
609 |
+
case 'wp:post_type':
|
610 |
+
$data['post_type'] = $child->textContent;
|
611 |
+
break;
|
612 |
+
|
613 |
+
case 'title':
|
614 |
+
$data['post_title'] = $child->textContent;
|
615 |
+
break;
|
616 |
+
|
617 |
+
case 'guid':
|
618 |
+
$data['guid'] = $child->textContent;
|
619 |
+
break;
|
620 |
+
|
621 |
+
case 'dc:creator':
|
622 |
+
$data['post_author'] = $child->textContent;
|
623 |
+
break;
|
624 |
+
|
625 |
+
case 'content:encoded':
|
626 |
+
$data['post_content'] = $child->textContent;
|
627 |
+
break;
|
628 |
+
|
629 |
+
case 'excerpt:encoded':
|
630 |
+
$data['post_excerpt'] = $child->textContent;
|
631 |
+
break;
|
632 |
+
|
633 |
+
case 'wp:post_id':
|
634 |
+
$data['post_id'] = $child->textContent;
|
635 |
+
break;
|
636 |
+
|
637 |
+
case 'wp:post_date':
|
638 |
+
$data['post_date'] = $child->textContent;
|
639 |
+
break;
|
640 |
+
|
641 |
+
case 'wp:post_date_gmt':
|
642 |
+
$data['post_date_gmt'] = $child->textContent;
|
643 |
+
break;
|
644 |
+
|
645 |
+
case 'wp:comment_status':
|
646 |
+
$data['comment_status'] = $child->textContent;
|
647 |
+
break;
|
648 |
+
|
649 |
+
case 'wp:ping_status':
|
650 |
+
$data['ping_status'] = $child->textContent;
|
651 |
+
break;
|
652 |
+
|
653 |
+
case 'wp:post_name':
|
654 |
+
$data['post_name'] = $child->textContent;
|
655 |
+
break;
|
656 |
+
|
657 |
+
case 'wp:status':
|
658 |
+
$data['post_status'] = $child->textContent;
|
659 |
+
|
660 |
+
if ( $data['post_status'] === 'auto-draft' ) {
|
661 |
+
// Bail now
|
662 |
+
return new WP_Error(
|
663 |
+
'wxr_importer.post.cannot_import_draft',
|
664 |
+
__( 'Cannot import auto-draft posts' ),
|
665 |
+
$data
|
666 |
+
);
|
667 |
+
}
|
668 |
+
break;
|
669 |
+
|
670 |
+
case 'wp:post_parent':
|
671 |
+
$data['post_parent'] = $child->textContent;
|
672 |
+
break;
|
673 |
+
|
674 |
+
case 'wp:menu_order':
|
675 |
+
$data['menu_order'] = $child->textContent;
|
676 |
+
break;
|
677 |
+
|
678 |
+
case 'wp:post_password':
|
679 |
+
$data['post_password'] = $child->textContent;
|
680 |
+
break;
|
681 |
+
|
682 |
+
case 'wp:is_sticky':
|
683 |
+
$data['is_sticky'] = $child->textContent;
|
684 |
+
break;
|
685 |
+
|
686 |
+
case 'wp:attachment_url':
|
687 |
+
$data['attachment_url'] = $child->textContent;
|
688 |
+
break;
|
689 |
+
|
690 |
+
case 'wp:postmeta':
|
691 |
+
$meta_item = $this->parse_meta_node( $child );
|
692 |
+
if ( ! empty( $meta_item ) ) {
|
693 |
+
$meta[] = $meta_item;
|
694 |
+
}
|
695 |
+
break;
|
696 |
+
|
697 |
+
case 'wp:comment':
|
698 |
+
$comment_item = $this->parse_comment_node( $child );
|
699 |
+
if ( ! empty( $comment_item ) ) {
|
700 |
+
$comments[] = $comment_item;
|
701 |
+
}
|
702 |
+
break;
|
703 |
+
|
704 |
+
case 'category':
|
705 |
+
$term_item = $this->parse_category_node( $child );
|
706 |
+
if ( ! empty( $term_item ) ) {
|
707 |
+
$terms[] = $term_item;
|
708 |
+
}
|
709 |
+
break;
|
710 |
+
}// End switch().
|
711 |
+
}// End foreach().
|
712 |
+
|
713 |
+
return compact( 'data', 'meta', 'comments', 'terms' );
|
714 |
+
}
|
715 |
+
|
716 |
+
/**
|
717 |
+
* Create new posts based on import information
|
718 |
+
*
|
719 |
+
* Posts marked as having a parent which doesn't exist will become top level items.
|
720 |
+
* Doesn't create a new post if: the post type doesn't exist, the given post ID
|
721 |
+
* is already noted as imported or a post with the same title and date already exists.
|
722 |
+
* Note that new/updated terms, comments and meta are imported for the last of the above.
|
723 |
+
*/
|
724 |
+
protected function process_post( $data, $meta, $comments, $terms ) {
|
725 |
+
/**
|
726 |
+
* Pre-process post data.
|
727 |
+
*
|
728 |
+
* @param array $data Post data. (Return empty to skip.)
|
729 |
+
* @param array $meta Meta data.
|
730 |
+
* @param array $comments Comments on the post.
|
731 |
+
* @param array $terms Terms on the post.
|
732 |
+
*/
|
733 |
+
$data = apply_filters( 'wxr_importer.pre_process.post', $data, $meta, $comments, $terms );
|
734 |
+
if ( empty( $data ) ) {
|
735 |
+
return false;
|
736 |
+
}
|
737 |
+
|
738 |
+
$original_id = isset( $data['post_id'] ) ? (int) $data['post_id'] : 0;
|
739 |
+
$parent_id = isset( $data['post_parent'] ) ? (int) $data['post_parent'] : 0;
|
740 |
+
$author_id = isset( $data['post_author'] ) ? (int) $data['post_author'] : 0;
|
741 |
+
|
742 |
+
// Have we already processed this?
|
743 |
+
if ( isset( $this->mapping['post'][ $original_id ] ) ) {
|
744 |
+
return;
|
745 |
+
}
|
746 |
+
|
747 |
+
$post_type_object = get_post_type_object( $data['post_type'] );
|
748 |
+
|
749 |
+
// Is this type even valid?
|
750 |
+
if ( ! $post_type_object ) {
|
751 |
+
$this->logger->warning( sprintf(
|
752 |
+
__( 'Failed to import "%1$s": Invalid post type %2$s', 'wordpress-importer' ),
|
753 |
+
$data['post_title'],
|
754 |
+
$data['post_type']
|
755 |
+
) );
|
756 |
+
return false;
|
757 |
+
}
|
758 |
+
|
759 |
+
$post_exists = $this->post_exists( $data );
|
760 |
+
if ( $post_exists ) {
|
761 |
+
$this->logger->info( sprintf(
|
762 |
+
__( '%1$s "%2$s" already exists.', 'wordpress-importer' ),
|
763 |
+
$post_type_object->labels->singular_name,
|
764 |
+
$data['post_title']
|
765 |
+
) );
|
766 |
+
|
767 |
+
/**
|
768 |
+
* Post processing already imported.
|
769 |
+
*
|
770 |
+
* @param array $data Raw data imported for the post.
|
771 |
+
*/
|
772 |
+
do_action( 'wxr_importer.process_already_imported.post', $data );
|
773 |
+
|
774 |
+
// Even though this post already exists, new comments might need importing
|
775 |
+
$this->process_comments( $comments, $original_id, $data, $post_exists );
|
776 |
+
|
777 |
+
return false;
|
778 |
+
}
|
779 |
+
|
780 |
+
// Map the parent post, or mark it as one we need to fix
|
781 |
+
$requires_remapping = false;
|
782 |
+
if ( $parent_id ) {
|
783 |
+
if ( isset( $this->mapping['post'][ $parent_id ] ) ) {
|
784 |
+
$data['post_parent'] = $this->mapping['post'][ $parent_id ];
|
785 |
+
} else {
|
786 |
+
$meta[] = array(
|
787 |
+
'key' => '_wxr_import_parent',
|
788 |
+
'value' => $parent_id,
|
789 |
+
);
|
790 |
+
$requires_remapping = true;
|
791 |
+
|
792 |
+
$data['post_parent'] = 0;
|
793 |
+
}
|
794 |
+
}
|
795 |
+
|
796 |
+
// Map the author, or mark it as one we need to fix
|
797 |
+
$author = sanitize_user( $data['post_author'], true );
|
798 |
+
if ( empty( $author ) ) {
|
799 |
+
// Missing or invalid author, use default if available.
|
800 |
+
$data['post_author'] = $this->options['default_author'];
|
801 |
+
} elseif ( isset( $this->mapping['user_slug'][ $author ] ) ) {
|
802 |
+
$data['post_author'] = $this->mapping['user_slug'][ $author ];
|
803 |
+
} else {
|
804 |
+
$meta[] = array(
|
805 |
+
'key' => '_wxr_import_user_slug',
|
806 |
+
'value' => $author,
|
807 |
+
);
|
808 |
+
$requires_remapping = true;
|
809 |
+
|
810 |
+
$data['post_author'] = (int) get_current_user_id();
|
811 |
+
}
|
812 |
+
|
813 |
+
// Does the post look like it contains attachment images?
|
814 |
+
if ( preg_match( self::REGEX_HAS_ATTACHMENT_REFS, $data['post_content'] ) ) {
|
815 |
+
$meta[] = array(
|
816 |
+
'key' => '_wxr_import_has_attachment_refs',
|
817 |
+
'value' => true,
|
818 |
+
);
|
819 |
+
$requires_remapping = true;
|
820 |
+
}
|
821 |
+
|
822 |
+
// Whitelist to just the keys we allow
|
823 |
+
$postdata = array(
|
824 |
+
'import_id' => $data['post_id'],
|
825 |
+
);
|
826 |
+
$allowed = array(
|
827 |
+
'post_author' => true,
|
828 |
+
'post_date' => true,
|
829 |
+
'post_date_gmt' => true,
|
830 |
+
'post_content' => true,
|
831 |
+
'post_excerpt' => true,
|
832 |
+
'post_title' => true,
|
833 |
+
'post_status' => true,
|
834 |
+
'post_name' => true,
|
835 |
+
'comment_status' => true,
|
836 |
+
'ping_status' => true,
|
837 |
+
'guid' => true,
|
838 |
+
'post_parent' => true,
|
839 |
+
'menu_order' => true,
|
840 |
+
'post_type' => true,
|
841 |
+
'post_password' => true,
|
842 |
+
);
|
843 |
+
foreach ( $data as $key => $value ) {
|
844 |
+
if ( ! isset( $allowed[ $key ] ) ) {
|
845 |
+
continue;
|
846 |
+
}
|
847 |
+
|
848 |
+
$postdata[ $key ] = $data[ $key ];
|
849 |
+
}
|
850 |
+
|
851 |
+
$postdata = apply_filters( 'wp_import_post_data_processed', $postdata, $data );
|
852 |
+
|
853 |
+
if ( 'attachment' === $postdata['post_type'] ) {
|
854 |
+
if ( ! $this->options['fetch_attachments'] ) {
|
855 |
+
$this->logger->notice( sprintf(
|
856 |
+
__( 'Skipping attachment "%s", fetching attachments disabled' ),
|
857 |
+
$data['post_title']
|
858 |
+
) );
|
859 |
+
/**
|
860 |
+
* Post processing skipped.
|
861 |
+
*
|
862 |
+
* @param array $data Raw data imported for the post.
|
863 |
+
* @param array $meta Raw meta data, already processed by {@see process_post_meta}.
|
864 |
+
*/
|
865 |
+
do_action( 'wxr_importer.process_skipped.post', $data, $meta );
|
866 |
+
return false;
|
867 |
+
}
|
868 |
+
$remote_url = ! empty( $data['attachment_url'] ) ? $data['attachment_url'] : $data['guid'];
|
869 |
+
$post_id = $this->process_attachment( $postdata, $meta, $remote_url );
|
870 |
+
} else {
|
871 |
+
$post_id = wp_insert_post( $postdata, true );
|
872 |
+
do_action( 'wp_import_insert_post', $post_id, $original_id, $postdata, $data );
|
873 |
+
}
|
874 |
+
|
875 |
+
if ( is_wp_error( $post_id ) ) {
|
876 |
+
$this->logger->error( sprintf(
|
877 |
+
__( 'Failed to import "%1$s" (%2$s)', 'wordpress-importer' ),
|
878 |
+
$data['post_title'],
|
879 |
+
$post_type_object->labels->singular_name
|
880 |
+
) );
|
881 |
+
$this->logger->debug( $post_id->get_error_message() );
|
882 |
+
|
883 |
+
/**
|
884 |
+
* Post processing failed.
|
885 |
+
*
|
886 |
+
* @param WP_Error $post_id Error object.
|
887 |
+
* @param array $data Raw data imported for the post.
|
888 |
+
* @param array $meta Raw meta data, already processed by {@see process_post_meta}.
|
889 |
+
* @param array $comments Raw comment data, already processed by {@see process_comments}.
|
890 |
+
* @param array $terms Raw term data, already processed.
|
891 |
+
*/
|
892 |
+
do_action( 'wxr_importer.process_failed.post', $post_id, $data, $meta, $comments, $terms );
|
893 |
+
return false;
|
894 |
+
}
|
895 |
+
|
896 |
+
// Ensure stickiness is handled correctly too
|
897 |
+
if ( $data['is_sticky'] === '1' ) {
|
898 |
+
stick_post( $post_id );
|
899 |
+
}
|
900 |
+
|
901 |
+
// map pre-import ID to local ID
|
902 |
+
$this->mapping['post'][ $original_id ] = (int) $post_id;
|
903 |
+
if ( $requires_remapping ) {
|
904 |
+
$this->requires_remapping['post'][ $post_id ] = true;
|
905 |
+
}
|
906 |
+
$this->mark_post_exists( $data, $post_id );
|
907 |
+
|
908 |
+
$this->logger->info( sprintf(
|
909 |
+
__( 'Imported "%1$s" (%2$s)', 'wordpress-importer' ),
|
910 |
+
$data['post_title'],
|
911 |
+
$post_type_object->labels->singular_name
|
912 |
+
) );
|
913 |
+
$this->logger->debug( sprintf(
|
914 |
+
__( 'Post %1$d remapped to %2$d', 'wordpress-importer' ),
|
915 |
+
$original_id,
|
916 |
+
$post_id
|
917 |
+
) );
|
918 |
+
|
919 |
+
// Handle the terms too
|
920 |
+
$terms = apply_filters( 'wp_import_post_terms', $terms, $post_id, $data );
|
921 |
+
|
922 |
+
if ( ! empty( $terms ) ) {
|
923 |
+
$term_ids = array();
|
924 |
+
foreach ( $terms as $term ) {
|
925 |
+
$taxonomy = $term['taxonomy'];
|
926 |
+
$key = sha1( $taxonomy . ':' . $term['slug'] );
|
927 |
+
|
928 |
+
if ( isset( $this->mapping['term'][ $key ] ) ) {
|
929 |
+
$term_ids[ $taxonomy ][] = (int) $this->mapping['term'][ $key ];
|
930 |
+
} else {
|
931 |
+
$meta[] = array(
|
932 |
+
'key' => '_wxr_import_term',
|
933 |
+
'value' => $term,
|
934 |
+
);
|
935 |
+
$requires_remapping = true;
|
936 |
+
}
|
937 |
+
}
|
938 |
+
|
939 |
+
foreach ( $term_ids as $tax => $ids ) {
|
940 |
+
$tt_ids = wp_set_post_terms( $post_id, $ids, $tax );
|
941 |
+
do_action( 'wp_import_set_post_terms', $tt_ids, $ids, $tax, $post_id, $data );
|
942 |
+
}
|
943 |
+
}
|
944 |
+
|
945 |
+
$this->process_comments( $comments, $post_id, $data );
|
946 |
+
$this->process_post_meta( $meta, $post_id, $data );
|
947 |
+
|
948 |
+
if ( 'nav_menu_item' === $data['post_type'] ) {
|
949 |
+
$this->process_menu_item_meta( $post_id, $data, $meta );
|
950 |
+
}
|
951 |
+
|
952 |
+
/**
|
953 |
+
* Post processing completed.
|
954 |
+
*
|
955 |
+
* @param int $post_id New post ID.
|
956 |
+
* @param array $data Raw data imported for the post.
|
957 |
+
* @param array $meta Raw meta data, already processed by {@see process_post_meta}.
|
958 |
+
* @param array $comments Raw comment data, already processed by {@see process_comments}.
|
959 |
+
* @param array $terms Raw term data, already processed.
|
960 |
+
*/
|
961 |
+
do_action( 'wxr_importer.processed.post', $post_id, $data, $meta, $comments, $terms );
|
962 |
+
}
|
963 |
+
|
964 |
+
/**
|
965 |
+
* Attempt to create a new menu item from import data
|
966 |
+
*
|
967 |
+
* Fails for draft, orphaned menu items and those without an associated nav_menu
|
968 |
+
* or an invalid nav_menu term. If the post type or term object which the menu item
|
969 |
+
* represents doesn't exist then the menu item will not be imported (waits until the
|
970 |
+
* end of the import to retry again before discarding).
|
971 |
+
*
|
972 |
+
* @param array $item Menu item details from WXR file
|
973 |
+
*/
|
974 |
+
protected function process_menu_item_meta( $post_id, $data, $meta ) {
|
975 |
+
|
976 |
+
$item_type = get_post_meta( $post_id, '_menu_item_type', true );
|
977 |
+
$original_object_id = get_post_meta( $post_id, '_menu_item_object_id', true );
|
978 |
+
$object_id = null;
|
979 |
+
|
980 |
+
$this->logger->debug( sprintf( 'Processing menu item %s', $item_type ) );
|
981 |
+
|
982 |
+
$requires_remapping = false;
|
983 |
+
switch ( $item_type ) {
|
984 |
+
case 'taxonomy':
|
985 |
+
if ( isset( $this->mapping['term_id'][ $original_object_id ] ) ) {
|
986 |
+
$object_id = $this->mapping['term_id'][ $original_object_id ];
|
987 |
+
} else {
|
988 |
+
add_post_meta( $post_id, '_wxr_import_menu_item', wp_slash( $original_object_id ) );
|
989 |
+
$requires_remapping = true;
|
990 |
+
}
|
991 |
+
break;
|
992 |
+
|
993 |
+
case 'post_type':
|
994 |
+
if ( isset( $this->mapping['post'][ $original_object_id ] ) ) {
|
995 |
+
$object_id = $this->mapping['post'][ $original_object_id ];
|
996 |
+
} else {
|
997 |
+
add_post_meta( $post_id, '_wxr_import_menu_item', wp_slash( $original_object_id ) );
|
998 |
+
$requires_remapping = true;
|
999 |
+
}
|
1000 |
+
break;
|
1001 |
+
|
1002 |
+
case 'custom':
|
1003 |
+
// Custom refers to itself, wonderfully easy.
|
1004 |
+
$object_id = $post_id;
|
1005 |
+
break;
|
1006 |
+
|
1007 |
+
default:
|
1008 |
+
// associated object is missing or not imported yet, we'll retry later
|
1009 |
+
$this->missing_menu_items[] = $item;
|
1010 |
+
$this->logger->debug( 'Unknown menu item type' );
|
1011 |
+
break;
|
1012 |
+
}
|
1013 |
+
|
1014 |
+
if ( $requires_remapping ) {
|
1015 |
+
$this->requires_remapping['post'][ $post_id ] = true;
|
1016 |
+
}
|
1017 |
+
|
1018 |
+
if ( empty( $object_id ) ) {
|
1019 |
+
// Nothing needed here.
|
1020 |
+
return;
|
1021 |
+
}
|
1022 |
+
|
1023 |
+
$this->logger->debug( sprintf( 'Menu item %d mapped to %d', $original_object_id, $object_id ) );
|
1024 |
+
update_post_meta( $post_id, '_menu_item_object_id', wp_slash( $object_id ) );
|
1025 |
+
}
|
1026 |
+
|
1027 |
+
/**
|
1028 |
+
* If fetching attachments is enabled then attempt to create a new attachment
|
1029 |
+
*
|
1030 |
+
* @param array $post Attachment post details from WXR
|
1031 |
+
* @param string $url URL to fetch attachment from
|
1032 |
+
* @return int|WP_Error Post ID on success, WP_Error otherwise
|
1033 |
+
*/
|
1034 |
+
protected function process_attachment( $post, $meta, $remote_url ) {
|
1035 |
+
// try to use _wp_attached file for upload folder placement to ensure the same location as the export site
|
1036 |
+
// e.g. location is 2003/05/image.jpg but the attachment post_date is 2010/09, see media_handle_upload()
|
1037 |
+
$post['upload_date'] = $post['post_date'];
|
1038 |
+
foreach ( $meta as $meta_item ) {
|
1039 |
+
if ( $meta_item['key'] !== '_wp_attached_file' ) {
|
1040 |
+
continue;
|
1041 |
+
}
|
1042 |
+
|
1043 |
+
if ( preg_match( '%^[0-9]{4}/[0-9]{2}%', $meta_item['value'], $matches ) ) {
|
1044 |
+
$post['upload_date'] = $matches[0];
|
1045 |
+
}
|
1046 |
+
break;
|
1047 |
+
}
|
1048 |
+
|
1049 |
+
// if the URL is absolute, but does not contain address, then upload it assuming base_site_url
|
1050 |
+
if ( preg_match( '|^/[\w\W]+$|', $remote_url ) ) {
|
1051 |
+
$remote_url = rtrim( $this->base_url, '/' ) . $remote_url;
|
1052 |
+
}
|
1053 |
+
|
1054 |
+
$upload = $this->fetch_remote_file( $remote_url, $post );
|
1055 |
+
if ( is_wp_error( $upload ) ) {
|
1056 |
+
return $upload;
|
1057 |
+
}
|
1058 |
+
|
1059 |
+
$info = wp_check_filetype( $upload['file'] );
|
1060 |
+
if ( ! $info ) {
|
1061 |
+
return new WP_Error( 'attachment_processing_error', __( 'Invalid file type', 'wordpress-importer' ) );
|
1062 |
+
}
|
1063 |
+
|
1064 |
+
$post['post_mime_type'] = $info['type'];
|
1065 |
+
|
1066 |
+
// WP really likes using the GUID for display. Allow updating it.
|
1067 |
+
// See https://core.trac.wordpress.org/ticket/33386
|
1068 |
+
if ( $this->options['update_attachment_guids'] ) {
|
1069 |
+
$post['guid'] = $upload['url'];
|
1070 |
+
}
|
1071 |
+
|
1072 |
+
// as per wp-admin/includes/upload.php
|
1073 |
+
$post_id = wp_insert_attachment( $post, $upload['file'] );
|
1074 |
+
if ( is_wp_error( $post_id ) ) {
|
1075 |
+
return $post_id;
|
1076 |
+
}
|
1077 |
+
|
1078 |
+
$attachment_metadata = wp_generate_attachment_metadata( $post_id, $upload['file'] );
|
1079 |
+
wp_update_attachment_metadata( $post_id, $attachment_metadata );
|
1080 |
+
|
1081 |
+
// Map this image URL later if we need to
|
1082 |
+
$this->url_remap[ $remote_url ] = $upload['url'];
|
1083 |
+
|
1084 |
+
// If we have a HTTPS URL, ensure the HTTP URL gets replaced too
|
1085 |
+
if ( substr( $remote_url, 0, 8 ) === 'https://' ) {
|
1086 |
+
$insecure_url = 'http' . substr( $remote_url, 5 );
|
1087 |
+
$this->url_remap[ $insecure_url ] = $upload['url'];
|
1088 |
+
}
|
1089 |
+
|
1090 |
+
if ( $this->options['aggressive_url_search'] ) {
|
1091 |
+
// remap resized image URLs, works by stripping the extension and remapping the URL stub.
|
1092 |
+
/*
|
1093 |
+
if ( preg_match( '!^image/!', $info['type'] ) ) {
|
1094 |
+
$parts = pathinfo( $remote_url );
|
1095 |
+
$name = basename( $parts['basename'], ".{$parts['extension']}" ); // PATHINFO_FILENAME in PHP 5.2
|
1096 |
+
|
1097 |
+
$parts_new = pathinfo( $upload['url'] );
|
1098 |
+
$name_new = basename( $parts_new['basename'], ".{$parts_new['extension']}" );
|
1099 |
+
|
1100 |
+
$this->url_remap[$parts['dirname'] . '/' . $name] = $parts_new['dirname'] . '/' . $name_new;
|
1101 |
+
}*/
|
1102 |
+
}
|
1103 |
+
|
1104 |
+
return $post_id;
|
1105 |
+
}
|
1106 |
+
|
1107 |
+
/**
|
1108 |
+
* Parse a meta node into meta data.
|
1109 |
+
*
|
1110 |
+
* @param DOMElement $node Parent node of meta data (typically `wp:postmeta` or `wp:commentmeta`).
|
1111 |
+
* @return array|null Meta data array on success, or null on error.
|
1112 |
+
*/
|
1113 |
+
protected function parse_meta_node( $node ) {
|
1114 |
+
foreach ( $node->childNodes as $child ) {
|
1115 |
+
// We only care about child elements
|
1116 |
+
if ( $child->nodeType !== XML_ELEMENT_NODE ) {
|
1117 |
+
continue;
|
1118 |
+
}
|
1119 |
+
|
1120 |
+
switch ( $child->tagName ) {
|
1121 |
+
case 'wp:meta_key':
|
1122 |
+
$key = $child->textContent;
|
1123 |
+
break;
|
1124 |
+
|
1125 |
+
case 'wp:meta_value':
|
1126 |
+
$value = $child->textContent;
|
1127 |
+
break;
|
1128 |
+
}
|
1129 |
+
}
|
1130 |
+
|
1131 |
+
if ( empty( $key ) || empty( $value ) ) {
|
1132 |
+
return null;
|
1133 |
+
}
|
1134 |
+
|
1135 |
+
return compact( 'key', 'value' );
|
1136 |
+
}
|
1137 |
+
|
1138 |
+
/**
|
1139 |
+
* Process and import post meta items.
|
1140 |
+
*
|
1141 |
+
* @param array $meta List of meta data arrays
|
1142 |
+
* @param int $post_id Post to associate with
|
1143 |
+
* @param array $post Post data
|
1144 |
+
* @return int|WP_Error Number of meta items imported on success, error otherwise.
|
1145 |
+
*/
|
1146 |
+
protected function process_post_meta( $meta, $post_id, $post ) {
|
1147 |
+
if ( empty( $meta ) ) {
|
1148 |
+
return true;
|
1149 |
+
}
|
1150 |
+
|
1151 |
+
foreach ( $meta as $meta_item ) {
|
1152 |
+
/**
|
1153 |
+
* Pre-process post meta data.
|
1154 |
+
*
|
1155 |
+
* @param array $meta_item Meta data. (Return empty to skip.)
|
1156 |
+
* @param int $post_id Post the meta is attached to.
|
1157 |
+
*/
|
1158 |
+
$meta_item = apply_filters( 'wxr_importer.pre_process.post_meta', $meta_item, $post_id );
|
1159 |
+
if ( empty( $meta_item ) ) {
|
1160 |
+
return false;
|
1161 |
+
}
|
1162 |
+
|
1163 |
+
$key = apply_filters( 'import_post_meta_key', $meta_item['key'], $post_id, $post );
|
1164 |
+
$value = false;
|
1165 |
+
|
1166 |
+
if ( '_edit_last' === $key ) {
|
1167 |
+
$value = intval( $meta_item['value'] );
|
1168 |
+
if ( ! isset( $this->mapping['user'][ $value ] ) ) {
|
1169 |
+
// Skip!
|
1170 |
+
continue;
|
1171 |
+
}
|
1172 |
+
|
1173 |
+
$value = $this->mapping['user'][ $value ];
|
1174 |
+
}
|
1175 |
+
|
1176 |
+
if ( $key ) {
|
1177 |
+
// export gets meta straight from the DB so could have a serialized string
|
1178 |
+
if ( ! $value ) {
|
1179 |
+
$value = maybe_unserialize( $meta_item['value'] );
|
1180 |
+
}
|
1181 |
+
|
1182 |
+
add_post_meta( $post_id, $key, $value );
|
1183 |
+
do_action( 'import_post_meta', $post_id, $key, $value );
|
1184 |
+
|
1185 |
+
// if the post has a featured image, take note of this in case of remap
|
1186 |
+
if ( '_thumbnail_id' === $key ) {
|
1187 |
+
$this->featured_images[ $post_id ] = (int) $value;
|
1188 |
+
}
|
1189 |
+
}
|
1190 |
+
}// End foreach().
|
1191 |
+
|
1192 |
+
return true;
|
1193 |
+
}
|
1194 |
+
|
1195 |
+
/**
|
1196 |
+
* Parse a comment node into comment data.
|
1197 |
+
*
|
1198 |
+
* @param DOMElement $node Parent node of comment data (typically `wp:comment`).
|
1199 |
+
* @return array Comment data array.
|
1200 |
+
*/
|
1201 |
+
protected function parse_comment_node( $node ) {
|
1202 |
+
$data = array(
|
1203 |
+
'commentmeta' => array(),
|
1204 |
+
);
|
1205 |
+
|
1206 |
+
foreach ( $node->childNodes as $child ) {
|
1207 |
+
// We only care about child elements
|
1208 |
+
if ( $child->nodeType !== XML_ELEMENT_NODE ) {
|
1209 |
+
continue;
|
1210 |
+
}
|
1211 |
+
|
1212 |
+
switch ( $child->tagName ) {
|
1213 |
+
case 'wp:comment_id':
|
1214 |
+
$data['comment_id'] = $child->textContent;
|
1215 |
+
break;
|
1216 |
+
case 'wp:comment_author':
|
1217 |
+
$data['comment_author'] = $child->textContent;
|
1218 |
+
break;
|
1219 |
+
|
1220 |
+
case 'wp:comment_author_email':
|
1221 |
+
$data['comment_author_email'] = $child->textContent;
|
1222 |
+
break;
|
1223 |
+
|
1224 |
+
case 'wp:comment_author_IP':
|
1225 |
+
$data['comment_author_IP'] = $child->textContent;
|
1226 |
+
break;
|
1227 |
+
|
1228 |
+
case 'wp:comment_author_url':
|
1229 |
+
$data['comment_author_url'] = $child->textContent;
|
1230 |
+
break;
|
1231 |
+
|
1232 |
+
case 'wp:comment_user_id':
|
1233 |
+
$data['comment_user_id'] = $child->textContent;
|
1234 |
+
break;
|
1235 |
+
|
1236 |
+
case 'wp:comment_date':
|
1237 |
+
$data['comment_date'] = $child->textContent;
|
1238 |
+
break;
|
1239 |
+
|
1240 |
+
case 'wp:comment_date_gmt':
|
1241 |
+
$data['comment_date_gmt'] = $child->textContent;
|
1242 |
+
break;
|
1243 |
+
|
1244 |
+
case 'wp:comment_content':
|
1245 |
+
$data['comment_content'] = $child->textContent;
|
1246 |
+
break;
|
1247 |
+
|
1248 |
+
case 'wp:comment_approved':
|
1249 |
+
$data['comment_approved'] = $child->textContent;
|
1250 |
+
break;
|
1251 |
+
|
1252 |
+
case 'wp:comment_type':
|
1253 |
+
$data['comment_type'] = $child->textContent;
|
1254 |
+
break;
|
1255 |
+
|
1256 |
+
case 'wp:comment_parent':
|
1257 |
+
$data['comment_parent'] = $child->textContent;
|
1258 |
+
break;
|
1259 |
+
|
1260 |
+
case 'wp:commentmeta':
|
1261 |
+
$meta_item = $this->parse_meta_node( $child );
|
1262 |
+
if ( ! empty( $meta_item ) ) {
|
1263 |
+
$data['commentmeta'][] = $meta_item;
|
1264 |
+
}
|
1265 |
+
break;
|
1266 |
+
}// End switch().
|
1267 |
+
}// End foreach().
|
1268 |
+
|
1269 |
+
return $data;
|
1270 |
+
}
|
1271 |
+
|
1272 |
+
/**
|
1273 |
+
* Process and import comment data.
|
1274 |
+
*
|
1275 |
+
* @param array $comments List of comment data arrays.
|
1276 |
+
* @param int $post_id Post to associate with.
|
1277 |
+
* @param array $post Post data.
|
1278 |
+
* @return int|WP_Error Number of comments imported on success, error otherwise.
|
1279 |
+
*/
|
1280 |
+
protected function process_comments( $comments, $post_id, $post, $post_exists = false ) {
|
1281 |
+
|
1282 |
+
$comments = apply_filters( 'wp_import_post_comments', $comments, $post_id, $post );
|
1283 |
+
if ( empty( $comments ) ) {
|
1284 |
+
return 0;
|
1285 |
+
}
|
1286 |
+
|
1287 |
+
$num_comments = 0;
|
1288 |
+
|
1289 |
+
// Sort by ID to avoid excessive remapping later
|
1290 |
+
usort( $comments, array( $this, 'sort_comments_by_id' ) );
|
1291 |
+
|
1292 |
+
foreach ( $comments as $key => $comment ) {
|
1293 |
+
/**
|
1294 |
+
* Pre-process comment data
|
1295 |
+
*
|
1296 |
+
* @param array $comment Comment data. (Return empty to skip.)
|
1297 |
+
* @param int $post_id Post the comment is attached to.
|
1298 |
+
*/
|
1299 |
+
$comment = apply_filters( 'wxr_importer.pre_process.comment', $comment, $post_id );
|
1300 |
+
if ( empty( $comment ) ) {
|
1301 |
+
return false;
|
1302 |
+
}
|
1303 |
+
|
1304 |
+
$original_id = isset( $comment['comment_id'] ) ? (int) $comment['comment_id'] : 0;
|
1305 |
+
$parent_id = isset( $comment['comment_parent'] ) ? (int) $comment['comment_parent'] : 0;
|
1306 |
+
$author_id = isset( $comment['comment_user_id'] ) ? (int) $comment['comment_user_id'] : 0;
|
1307 |
+
|
1308 |
+
// if this is a new post we can skip the comment_exists() check
|
1309 |
+
// TODO: Check comment_exists for performance
|
1310 |
+
if ( $post_exists ) {
|
1311 |
+
$existing = $this->comment_exists( $comment );
|
1312 |
+
if ( $existing ) {
|
1313 |
+
|
1314 |
+
/**
|
1315 |
+
* Comment processing already imported.
|
1316 |
+
*
|
1317 |
+
* @param array $comment Raw data imported for the comment.
|
1318 |
+
*/
|
1319 |
+
do_action( 'wxr_importer.process_already_imported.comment', $comment );
|
1320 |
+
|
1321 |
+
$this->mapping['comment'][ $original_id ] = $existing;
|
1322 |
+
continue;
|
1323 |
+
}
|
1324 |
+
}
|
1325 |
+
|
1326 |
+
// Remove meta from the main array
|
1327 |
+
$meta = isset( $comment['commentmeta'] ) ? $comment['commentmeta'] : array();
|
1328 |
+
unset( $comment['commentmeta'] );
|
1329 |
+
|
1330 |
+
// Map the parent comment, or mark it as one we need to fix
|
1331 |
+
$requires_remapping = false;
|
1332 |
+
if ( $parent_id ) {
|
1333 |
+
if ( isset( $this->mapping['comment'][ $parent_id ] ) ) {
|
1334 |
+
$comment['comment_parent'] = $this->mapping['comment'][ $parent_id ];
|
1335 |
+
} else {
|
1336 |
+
// Prepare for remapping later
|
1337 |
+
$meta[] = array(
|
1338 |
+
'key' => '_wxr_import_parent',
|
1339 |
+
'value' => $parent_id,
|
1340 |
+
);
|
1341 |
+
$requires_remapping = true;
|
1342 |
+
|
1343 |
+
// Wipe the parent for now
|
1344 |
+
$comment['comment_parent'] = 0;
|
1345 |
+
}
|
1346 |
+
}
|
1347 |
+
|
1348 |
+
// Map the author, or mark it as one we need to fix
|
1349 |
+
if ( $author_id ) {
|
1350 |
+
if ( isset( $this->mapping['user'][ $author_id ] ) ) {
|
1351 |
+
$comment['user_id'] = $this->mapping['user'][ $author_id ];
|
1352 |
+
} else {
|
1353 |
+
// Prepare for remapping later
|
1354 |
+
$meta[] = array(
|
1355 |
+
'key' => '_wxr_import_user',
|
1356 |
+
'value' => $author_id,
|
1357 |
+
);
|
1358 |
+
$requires_remapping = true;
|
1359 |
+
|
1360 |
+
// Wipe the user for now
|
1361 |
+
$comment['user_id'] = 0;
|
1362 |
+
}
|
1363 |
+
}
|
1364 |
+
|
1365 |
+
// Run standard core filters
|
1366 |
+
$comment['comment_post_ID'] = $post_id;
|
1367 |
+
$comment = wp_filter_comment( $comment );
|
1368 |
+
|
1369 |
+
// wp_insert_comment expects slashed data
|
1370 |
+
$comment_id = wp_insert_comment( wp_slash( $comment ) );
|
1371 |
+
$this->mapping['comment'][ $original_id ] = $comment_id;
|
1372 |
+
if ( $requires_remapping ) {
|
1373 |
+
$this->requires_remapping['comment'][ $comment_id ] = true;
|
1374 |
+
}
|
1375 |
+
$this->mark_comment_exists( $comment, $comment_id );
|
1376 |
+
|
1377 |
+
/**
|
1378 |
+
* Comment has been imported.
|
1379 |
+
*
|
1380 |
+
* @param int $comment_id New comment ID
|
1381 |
+
* @param array $comment Comment inserted (`comment_id` item refers to the original ID)
|
1382 |
+
* @param int $post_id Post parent of the comment
|
1383 |
+
* @param array $post Post data
|
1384 |
+
*/
|
1385 |
+
do_action( 'wp_import_insert_comment', $comment_id, $comment, $post_id, $post );
|
1386 |
+
|
1387 |
+
// Process the meta items
|
1388 |
+
foreach ( $meta as $meta_item ) {
|
1389 |
+
$value = maybe_unserialize( $meta_item['value'] );
|
1390 |
+
add_comment_meta( $comment_id, wp_slash( $meta_item['key'] ), wp_slash( $value ) );
|
1391 |
+
}
|
1392 |
+
|
1393 |
+
/**
|
1394 |
+
* Post processing completed.
|
1395 |
+
*
|
1396 |
+
* @param int $post_id New post ID.
|
1397 |
+
* @param array $comment Raw data imported for the comment.
|
1398 |
+
* @param array $meta Raw meta data, already processed by {@see process_post_meta}.
|
1399 |
+
* @param array $post_id Parent post ID.
|
1400 |
+
*/
|
1401 |
+
do_action( 'wxr_importer.processed.comment', $comment_id, $comment, $meta, $post_id );
|
1402 |
+
|
1403 |
+
$num_comments++;
|
1404 |
+
}// End foreach().
|
1405 |
+
|
1406 |
+
return $num_comments;
|
1407 |
+
}
|
1408 |
+
|
1409 |
+
protected function parse_category_node( $node ) {
|
1410 |
+
$data = array(
|
1411 |
+
// Default taxonomy to "category", since this is a `<category>` tag
|
1412 |
+
'taxonomy' => 'category',
|
1413 |
+
);
|
1414 |
+
$meta = array();
|
1415 |
+
|
1416 |
+
if ( $node->hasAttribute( 'domain' ) ) {
|
1417 |
+
$data['taxonomy'] = $node->getAttribute( 'domain' );
|
1418 |
+
}
|
1419 |
+
if ( $node->hasAttribute( 'nicename' ) ) {
|
1420 |
+
$data['slug'] = $node->getAttribute( 'nicename' );
|
1421 |
+
}
|
1422 |
+
|
1423 |
+
$data['name'] = $node->textContent;
|
1424 |
+
|
1425 |
+
if ( empty( $data['slug'] ) ) {
|
1426 |
+
return null;
|
1427 |
+
}
|
1428 |
+
|
1429 |
+
// Just for extra compatibility
|
1430 |
+
if ( $data['taxonomy'] === 'tag' ) {
|
1431 |
+
$data['taxonomy'] = 'post_tag';
|
1432 |
+
}
|
1433 |
+
|
1434 |
+
return $data;
|
1435 |
+
}
|
1436 |
+
|
1437 |
+
/**
|
1438 |
+
* Callback for `usort` to sort comments by ID
|
1439 |
+
*
|
1440 |
+
* @param array $a Comment data for the first comment
|
1441 |
+
* @param array $b Comment data for the second comment
|
1442 |
+
* @return int
|
1443 |
+
*/
|
1444 |
+
public static function sort_comments_by_id( $a, $b ) {
|
1445 |
+
if ( empty( $a['comment_id'] ) ) {
|
1446 |
+
return 1;
|
1447 |
+
}
|
1448 |
+
|
1449 |
+
if ( empty( $b['comment_id'] ) ) {
|
1450 |
+
return -1;
|
1451 |
+
}
|
1452 |
+
|
1453 |
+
return $a['comment_id'] - $b['comment_id'];
|
1454 |
+
}
|
1455 |
+
|
1456 |
+
protected function parse_author_node( $node ) {
|
1457 |
+
$data = array();
|
1458 |
+
$meta = array();
|
1459 |
+
foreach ( $node->childNodes as $child ) {
|
1460 |
+
// We only care about child elements
|
1461 |
+
if ( $child->nodeType !== XML_ELEMENT_NODE ) {
|
1462 |
+
continue;
|
1463 |
+
}
|
1464 |
+
|
1465 |
+
switch ( $child->tagName ) {
|
1466 |
+
case 'wp:author_login':
|
1467 |
+
$data['user_login'] = $child->textContent;
|
1468 |
+
break;
|
1469 |
+
|
1470 |
+
case 'wp:author_id':
|
1471 |
+
$data['ID'] = $child->textContent;
|
1472 |
+
break;
|
1473 |
+
|
1474 |
+
case 'wp:author_email':
|
1475 |
+
$data['user_email'] = $child->textContent;
|
1476 |
+
break;
|
1477 |
+
|
1478 |
+
case 'wp:author_display_name':
|
1479 |
+
$data['display_name'] = $child->textContent;
|
1480 |
+
break;
|
1481 |
+
|
1482 |
+
case 'wp:author_first_name':
|
1483 |
+
$data['first_name'] = $child->textContent;
|
1484 |
+
break;
|
1485 |
+
|
1486 |
+
case 'wp:author_last_name':
|
1487 |
+
$data['last_name'] = $child->textContent;
|
1488 |
+
break;
|
1489 |
+
}
|
1490 |
+
}
|
1491 |
+
|
1492 |
+
return compact( 'data', 'meta' );
|
1493 |
+
}
|
1494 |
+
|
1495 |
+
protected function process_author( $data, $meta ) {
|
1496 |
+
/**
|
1497 |
+
* Pre-process user data.
|
1498 |
+
*
|
1499 |
+
* @param array $data User data. (Return empty to skip.)
|
1500 |
+
* @param array $meta Meta data.
|
1501 |
+
*/
|
1502 |
+
$data = apply_filters( 'wxr_importer.pre_process.user', $data, $meta );
|
1503 |
+
if ( empty( $data ) ) {
|
1504 |
+
return false;
|
1505 |
+
}
|
1506 |
+
|
1507 |
+
// Have we already handled this user?
|
1508 |
+
$original_id = isset( $data['ID'] ) ? $data['ID'] : 0;
|
1509 |
+
$original_slug = $data['user_login'];
|
1510 |
+
|
1511 |
+
if ( isset( $this->mapping['user'][ $original_id ] ) ) {
|
1512 |
+
$existing = $this->mapping['user'][ $original_id ];
|
1513 |
+
|
1514 |
+
// Note the slug mapping if we need to too
|
1515 |
+
if ( ! isset( $this->mapping['user_slug'][ $original_slug ] ) ) {
|
1516 |
+
$this->mapping['user_slug'][ $original_slug ] = $existing;
|
1517 |
+
}
|
1518 |
+
|
1519 |
+
return false;
|
1520 |
+
}
|
1521 |
+
|
1522 |
+
if ( isset( $this->mapping['user_slug'][ $original_slug ] ) ) {
|
1523 |
+
$existing = $this->mapping['user_slug'][ $original_slug ];
|
1524 |
+
|
1525 |
+
// Ensure we note the mapping too
|
1526 |
+
$this->mapping['user'][ $original_id ] = $existing;
|
1527 |
+
|
1528 |
+
return false;
|
1529 |
+
}
|
1530 |
+
|
1531 |
+
// Allow overriding the user's slug
|
1532 |
+
$login = $original_slug;
|
1533 |
+
if ( isset( $this->user_slug_override[ $login ] ) ) {
|
1534 |
+
$login = $this->user_slug_override[ $login ];
|
1535 |
+
}
|
1536 |
+
|
1537 |
+
$userdata = array(
|
1538 |
+
'user_login' => sanitize_user( $login, true ),
|
1539 |
+
'user_pass' => wp_generate_password(),
|
1540 |
+
);
|
1541 |
+
|
1542 |
+
$allowed = array(
|
1543 |
+
'user_email' => true,
|
1544 |
+
'display_name' => true,
|
1545 |
+
'first_name' => true,
|
1546 |
+
'last_name' => true,
|
1547 |
+
);
|
1548 |
+
foreach ( $data as $key => $value ) {
|
1549 |
+
if ( ! isset( $allowed[ $key ] ) ) {
|
1550 |
+
continue;
|
1551 |
+
}
|
1552 |
+
|
1553 |
+
$userdata[ $key ] = $data[ $key ];
|
1554 |
+
}
|
1555 |
+
|
1556 |
+
$user_id = wp_insert_user( wp_slash( $userdata ) );
|
1557 |
+
if ( is_wp_error( $user_id ) ) {
|
1558 |
+
$this->logger->error( sprintf(
|
1559 |
+
__( 'Failed to import user "%s"', 'wordpress-importer' ),
|
1560 |
+
$userdata['user_login']
|
1561 |
+
) );
|
1562 |
+
$this->logger->debug( $user_id->get_error_message() );
|
1563 |
+
|
1564 |
+
/**
|
1565 |
+
* User processing failed.
|
1566 |
+
*
|
1567 |
+
* @param WP_Error $user_id Error object.
|
1568 |
+
* @param array $userdata Raw data imported for the user.
|
1569 |
+
*/
|
1570 |
+
do_action( 'wxr_importer.process_failed.user', $user_id, $userdata );
|
1571 |
+
return false;
|
1572 |
+
}
|
1573 |
+
|
1574 |
+
if ( $original_id ) {
|
1575 |
+
$this->mapping['user'][ $original_id ] = $user_id;
|
1576 |
+
}
|
1577 |
+
$this->mapping['user_slug'][ $original_slug ] = $user_id;
|
1578 |
+
|
1579 |
+
$this->logger->info( sprintf(
|
1580 |
+
__( 'Imported user "%s"', 'wordpress-importer' ),
|
1581 |
+
$userdata['user_login']
|
1582 |
+
) );
|
1583 |
+
$this->logger->debug( sprintf(
|
1584 |
+
__( 'User %1$d remapped to %2$d', 'wordpress-importer' ),
|
1585 |
+
$original_id,
|
1586 |
+
$user_id
|
1587 |
+
) );
|
1588 |
+
|
1589 |
+
// TODO: Implement meta handling once WXR includes it
|
1590 |
+
/**
|
1591 |
+
* User processing completed.
|
1592 |
+
*
|
1593 |
+
* @param int $user_id New user ID.
|
1594 |
+
* @param array $userdata Raw data imported for the user.
|
1595 |
+
*/
|
1596 |
+
do_action( 'wxr_importer.processed.user', $user_id, $userdata );
|
1597 |
+
}
|
1598 |
+
|
1599 |
+
protected function parse_term_node( $node, $type = 'term' ) {
|
1600 |
+
$data = array();
|
1601 |
+
$meta = array();
|
1602 |
+
|
1603 |
+
$tag_name = array(
|
1604 |
+
'id' => 'wp:term_id',
|
1605 |
+
'taxonomy' => 'wp:term_taxonomy',
|
1606 |
+
'slug' => 'wp:term_slug',
|
1607 |
+
'parent' => 'wp:term_parent',
|
1608 |
+
'name' => 'wp:term_name',
|
1609 |
+
'description' => 'wp:term_description',
|
1610 |
+
);
|
1611 |
+
$taxonomy = null;
|
1612 |
+
|
1613 |
+
// Special casing!
|
1614 |
+
switch ( $type ) {
|
1615 |
+
case 'category':
|
1616 |
+
$tag_name['slug'] = 'wp:category_nicename';
|
1617 |
+
$tag_name['parent'] = 'wp:category_parent';
|
1618 |
+
$tag_name['name'] = 'wp:cat_name';
|
1619 |
+
$tag_name['description'] = 'wp:category_description';
|
1620 |
+
$tag_name['taxonomy'] = null;
|
1621 |
+
|
1622 |
+
$data['taxonomy'] = 'category';
|
1623 |
+
break;
|
1624 |
+
|
1625 |
+
case 'tag':
|
1626 |
+
$tag_name['slug'] = 'wp:tag_slug';
|
1627 |
+
$tag_name['parent'] = null;
|
1628 |
+
$tag_name['name'] = 'wp:tag_name';
|
1629 |
+
$tag_name['description'] = 'wp:tag_description';
|
1630 |
+
$tag_name['taxonomy'] = null;
|
1631 |
+
|
1632 |
+
$data['taxonomy'] = 'post_tag';
|
1633 |
+
break;
|
1634 |
+
}
|
1635 |
+
|
1636 |
+
foreach ( $node->childNodes as $child ) {
|
1637 |
+
// We only care about child elements
|
1638 |
+
if ( $child->nodeType !== XML_ELEMENT_NODE ) {
|
1639 |
+
continue;
|
1640 |
+
}
|
1641 |
+
|
1642 |
+
$key = array_search( $child->tagName, $tag_name );
|
1643 |
+
if ( $key ) {
|
1644 |
+
$data[ $key ] = $child->textContent;
|
1645 |
+
}
|
1646 |
+
}
|
1647 |
+
|
1648 |
+
if ( empty( $data['taxonomy'] ) ) {
|
1649 |
+
return null;
|
1650 |
+
}
|
1651 |
+
|
1652 |
+
// Compatibility with WXR 1.0
|
1653 |
+
if ( $data['taxonomy'] === 'tag' ) {
|
1654 |
+
$data['taxonomy'] = 'post_tag';
|
1655 |
+
}
|
1656 |
+
|
1657 |
+
return compact( 'data', 'meta' );
|
1658 |
+
}
|
1659 |
+
|
1660 |
+
protected function process_term( $data, $meta ) {
|
1661 |
+
/**
|
1662 |
+
* Pre-process term data.
|
1663 |
+
*
|
1664 |
+
* @param array $data Term data. (Return empty to skip.)
|
1665 |
+
* @param array $meta Meta data.
|
1666 |
+
*/
|
1667 |
+
$data = apply_filters( 'wxr_importer.pre_process.term', $data, $meta );
|
1668 |
+
if ( empty( $data ) ) {
|
1669 |
+
return false;
|
1670 |
+
}
|
1671 |
+
|
1672 |
+
$original_id = isset( $data['id'] ) ? (int) $data['id'] : 0;
|
1673 |
+
$parent_id = isset( $data['parent'] ) ? (int) $data['parent'] : 0;
|
1674 |
+
|
1675 |
+
$mapping_key = sha1( $data['taxonomy'] . ':' . $data['slug'] );
|
1676 |
+
$existing = $this->term_exists( $data );
|
1677 |
+
if ( $existing ) {
|
1678 |
+
|
1679 |
+
/**
|
1680 |
+
* Term processing already imported.
|
1681 |
+
*
|
1682 |
+
* @param array $data Raw data imported for the term.
|
1683 |
+
*/
|
1684 |
+
do_action( 'wxr_importer.process_already_imported.term', $data );
|
1685 |
+
|
1686 |
+
$this->mapping['term'][ $mapping_key ] = $existing;
|
1687 |
+
$this->mapping['term_id'][ $original_id ] = $existing;
|
1688 |
+
return false;
|
1689 |
+
}
|
1690 |
+
|
1691 |
+
// WP really likes to repeat itself in export files
|
1692 |
+
if ( isset( $this->mapping['term'][ $mapping_key ] ) ) {
|
1693 |
+
return false;
|
1694 |
+
}
|
1695 |
+
|
1696 |
+
$termdata = array();
|
1697 |
+
$allowed = array(
|
1698 |
+
'slug' => true,
|
1699 |
+
'description' => true,
|
1700 |
+
);
|
1701 |
+
|
1702 |
+
// Map the parent comment, or mark it as one we need to fix
|
1703 |
+
// TODO: add parent mapping and remapping
|
1704 |
+
/*
|
1705 |
+
$requires_remapping = false;
|
1706 |
+
if ( $parent_id ) {
|
1707 |
+
if ( isset( $this->mapping['term'][ $parent_id ] ) ) {
|
1708 |
+
$data['parent'] = $this->mapping['term'][ $parent_id ];
|
1709 |
+
} else {
|
1710 |
+
// Prepare for remapping later
|
1711 |
+
$meta[] = array( 'key' => '_wxr_import_parent', 'value' => $parent_id );
|
1712 |
+
$requires_remapping = true;
|
1713 |
+
|
1714 |
+
// Wipe the parent for now
|
1715 |
+
$data['parent'] = 0;
|
1716 |
+
}
|
1717 |
+
}*/
|
1718 |
+
|
1719 |
+
foreach ( $data as $key => $value ) {
|
1720 |
+
if ( ! isset( $allowed[ $key ] ) ) {
|
1721 |
+
continue;
|
1722 |
+
}
|
1723 |
+
|
1724 |
+
$termdata[ $key ] = $data[ $key ];
|
1725 |
+
}
|
1726 |
+
|
1727 |
+
$result = wp_insert_term( $data['name'], $data['taxonomy'], $termdata );
|
1728 |
+
if ( is_wp_error( $result ) ) {
|
1729 |
+
$this->logger->warning( sprintf(
|
1730 |
+
__( 'Failed to import %1$s %2$s', 'wordpress-importer' ),
|
1731 |
+
$data['taxonomy'],
|
1732 |
+
$data['name']
|
1733 |
+
) );
|
1734 |
+
$this->logger->debug( $result->get_error_message() );
|
1735 |
+
do_action( 'wp_import_insert_term_failed', $result, $data );
|
1736 |
+
|
1737 |
+
/**
|
1738 |
+
* Term processing failed.
|
1739 |
+
*
|
1740 |
+
* @param WP_Error $result Error object.
|
1741 |
+
* @param array $data Raw data imported for the term.
|
1742 |
+
* @param array $meta Meta data supplied for the term.
|
1743 |
+
*/
|
1744 |
+
do_action( 'wxr_importer.process_failed.term', $result, $data, $meta );
|
1745 |
+
return false;
|
1746 |
+
}
|
1747 |
+
|
1748 |
+
$term_id = $result['term_id'];
|
1749 |
+
|
1750 |
+
$this->mapping['term'][ $mapping_key ] = $term_id;
|
1751 |
+
$this->mapping['term_id'][ $original_id ] = $term_id;
|
1752 |
+
|
1753 |
+
$this->logger->info( sprintf(
|
1754 |
+
__( 'Imported "%1$s" (%2$s)', 'wordpress-importer' ),
|
1755 |
+
$data['name'],
|
1756 |
+
$data['taxonomy']
|
1757 |
+
) );
|
1758 |
+
$this->logger->debug( sprintf(
|
1759 |
+
__( 'Term %1$d remapped to %2$d', 'wordpress-importer' ),
|
1760 |
+
$original_id,
|
1761 |
+
$term_id
|
1762 |
+
) );
|
1763 |
+
|
1764 |
+
do_action( 'wp_import_insert_term', $term_id, $data );
|
1765 |
+
|
1766 |
+
/**
|
1767 |
+
* Term processing completed.
|
1768 |
+
*
|
1769 |
+
* @param int $term_id New term ID.
|
1770 |
+
* @param array $data Raw data imported for the term.
|
1771 |
+
*/
|
1772 |
+
do_action( 'wxr_importer.processed.term', $term_id, $data );
|
1773 |
+
}
|
1774 |
+
|
1775 |
+
/**
|
1776 |
+
* Attempt to download a remote file attachment
|
1777 |
+
*
|
1778 |
+
* @param string $url URL of item to fetch
|
1779 |
+
* @param array $post Attachment details
|
1780 |
+
* @return array|WP_Error Local file location details on success, WP_Error otherwise
|
1781 |
+
*/
|
1782 |
+
protected function fetch_remote_file( $url, $post ) {
|
1783 |
+
// extract the file name and extension from the url
|
1784 |
+
$file_name = basename( $url );
|
1785 |
+
|
1786 |
+
// get placeholder file in the upload dir with a unique, sanitized filename
|
1787 |
+
$upload = wp_upload_bits( $file_name, 0, '', $post['upload_date'] );
|
1788 |
+
if ( $upload['error'] ) {
|
1789 |
+
return new WP_Error( 'upload_dir_error', $upload['error'] );
|
1790 |
+
}
|
1791 |
+
|
1792 |
+
// fetch the remote url and write it to the placeholder file
|
1793 |
+
$response = wp_remote_get( $url, array(
|
1794 |
+
'stream' => true,
|
1795 |
+
'filename' => $upload['file'],
|
1796 |
+
) );
|
1797 |
+
|
1798 |
+
// request failed
|
1799 |
+
if ( is_wp_error( $response ) ) {
|
1800 |
+
unlink( $upload['file'] );
|
1801 |
+
return $response;
|
1802 |
+
}
|
1803 |
+
|
1804 |
+
$code = (int) wp_remote_retrieve_response_code( $response );
|
1805 |
+
|
1806 |
+
// make sure the fetch was successful
|
1807 |
+
if ( $code !== 200 ) {
|
1808 |
+
unlink( $upload['file'] );
|
1809 |
+
return new WP_Error(
|
1810 |
+
'import_file_error',
|
1811 |
+
sprintf(
|
1812 |
+
__( 'Remote server returned %1$d %2$s for %3$s', 'wordpress-importer' ),
|
1813 |
+
$code,
|
1814 |
+
get_status_header_desc( $code ),
|
1815 |
+
$url
|
1816 |
+
)
|
1817 |
+
);
|
1818 |
+
}
|
1819 |
+
|
1820 |
+
$filesize = filesize( $upload['file'] );
|
1821 |
+
$headers = wp_remote_retrieve_headers( $response );
|
1822 |
+
|
1823 |
+
if ( isset( $headers['content-length'] ) && $filesize !== (int) $headers['content-length'] ) {
|
1824 |
+
unlink( $upload['file'] );
|
1825 |
+
return new WP_Error( 'import_file_error', __( 'Remote file is incorrect size', 'wordpress-importer' ) );
|
1826 |
+
}
|
1827 |
+
|
1828 |
+
if ( 0 === $filesize ) {
|
1829 |
+
unlink( $upload['file'] );
|
1830 |
+
return new WP_Error( 'import_file_error', __( 'Zero size file downloaded', 'wordpress-importer' ) );
|
1831 |
+
}
|
1832 |
+
|
1833 |
+
$max_size = (int) $this->max_attachment_size();
|
1834 |
+
if ( ! empty( $max_size ) && $filesize > $max_size ) {
|
1835 |
+
unlink( $upload['file'] );
|
1836 |
+
$message = sprintf( __( 'Remote file is too large, limit is %s', 'wordpress-importer' ), size_format( $max_size ) );
|
1837 |
+
return new WP_Error( 'import_file_error', $message );
|
1838 |
+
}
|
1839 |
+
|
1840 |
+
return $upload;
|
1841 |
+
}
|
1842 |
+
|
1843 |
+
protected function post_process() {
|
1844 |
+
// Time to tackle any left-over bits
|
1845 |
+
if ( ! empty( $this->requires_remapping['post'] ) ) {
|
1846 |
+
$this->post_process_posts( $this->requires_remapping['post'] );
|
1847 |
+
}
|
1848 |
+
if ( ! empty( $this->requires_remapping['comment'] ) ) {
|
1849 |
+
$this->post_process_comments( $this->requires_remapping['comment'] );
|
1850 |
+
}
|
1851 |
+
}
|
1852 |
+
|
1853 |
+
protected function post_process_posts( $todo ) {
|
1854 |
+
foreach ( $todo as $post_id => $_ ) {
|
1855 |
+
$this->logger->debug( sprintf(
|
1856 |
+
// Note: title intentionally not used to skip extra processing
|
1857 |
+
// for when debug logging is off
|
1858 |
+
__( 'Running post-processing for post %d', 'wordpress-importer' ),
|
1859 |
+
$post_id
|
1860 |
+
) );
|
1861 |
+
|
1862 |
+
$data = array();
|
1863 |
+
|
1864 |
+
$parent_id = get_post_meta( $post_id, '_wxr_import_parent', true );
|
1865 |
+
if ( ! empty( $parent_id ) ) {
|
1866 |
+
// Have we imported the parent now?
|
1867 |
+
if ( isset( $this->mapping['post'][ $parent_id ] ) ) {
|
1868 |
+
$data['post_parent'] = $this->mapping['post'][ $parent_id ];
|
1869 |
+
} else {
|
1870 |
+
$this->logger->warning( sprintf(
|
1871 |
+
__( 'Could not find the post parent for "%1$s" (post #%2$d)', 'wordpress-importer' ),
|
1872 |
+
get_the_title( $post_id ),
|
1873 |
+
$post_id
|
1874 |
+
) );
|
1875 |
+
$this->logger->debug( sprintf(
|
1876 |
+
__( 'Post %1$d was imported with parent %2$d, but could not be found', 'wordpress-importer' ),
|
1877 |
+
$post_id,
|
1878 |
+
$parent_id
|
1879 |
+
) );
|
1880 |
+
}
|
1881 |
+
}
|
1882 |
+
|
1883 |
+
$author_slug = get_post_meta( $post_id, '_wxr_import_user_slug', true );
|
1884 |
+
if ( ! empty( $author_slug ) ) {
|
1885 |
+
// Have we imported the user now?
|
1886 |
+
if ( isset( $this->mapping['user_slug'][ $author_slug ] ) ) {
|
1887 |
+
$data['post_author'] = $this->mapping['user_slug'][ $author_slug ];
|
1888 |
+
} else {
|
1889 |
+
$this->logger->warning( sprintf(
|
1890 |
+
__( 'Could not find the author for "%1$s" (post #%2$d)', 'wordpress-importer' ),
|
1891 |
+
get_the_title( $post_id ),
|
1892 |
+
$post_id
|
1893 |
+
) );
|
1894 |
+
$this->logger->debug( sprintf(
|
1895 |
+
__( 'Post %1$d was imported with author "%2$s", but could not be found', 'wordpress-importer' ),
|
1896 |
+
$post_id,
|
1897 |
+
$author_slug
|
1898 |
+
) );
|
1899 |
+
}
|
1900 |
+
}
|
1901 |
+
|
1902 |
+
$has_attachments = get_post_meta( $post_id, '_wxr_import_has_attachment_refs', true );
|
1903 |
+
if ( ! empty( $has_attachments ) ) {
|
1904 |
+
$post = get_post( $post_id );
|
1905 |
+
$content = $post->post_content;
|
1906 |
+
|
1907 |
+
// Replace all the URLs we've got
|
1908 |
+
$new_content = str_replace( array_keys( $this->url_remap ), $this->url_remap, $content );
|
1909 |
+
if ( $new_content !== $content ) {
|
1910 |
+
$data['post_content'] = $new_content;
|
1911 |
+
}
|
1912 |
+
}
|
1913 |
+
|
1914 |
+
if ( get_post_type( $post_id ) === 'nav_menu_item' ) {
|
1915 |
+
$this->post_process_menu_item( $post_id );
|
1916 |
+
}
|
1917 |
+
|
1918 |
+
// Do we have updates to make?
|
1919 |
+
if ( empty( $data ) ) {
|
1920 |
+
$this->logger->debug( sprintf(
|
1921 |
+
__( 'Post %d was marked for post-processing, but none was required.', 'wordpress-importer' ),
|
1922 |
+
$post_id
|
1923 |
+
) );
|
1924 |
+
continue;
|
1925 |
+
}
|
1926 |
+
|
1927 |
+
// Run the update
|
1928 |
+
$data['ID'] = $post_id;
|
1929 |
+
$result = wp_update_post( $data, true );
|
1930 |
+
if ( is_wp_error( $result ) ) {
|
1931 |
+
$this->logger->warning( sprintf(
|
1932 |
+
__( 'Could not update "%1$s" (post #%2$d) with mapped data', 'wordpress-importer' ),
|
1933 |
+
get_the_title( $post_id ),
|
1934 |
+
$post_id
|
1935 |
+
) );
|
1936 |
+
$this->logger->debug( $result->get_error_message() );
|
1937 |
+
continue;
|
1938 |
+
}
|
1939 |
+
|
1940 |
+
// Clear out our temporary meta keys
|
1941 |
+
delete_post_meta( $post_id, '_wxr_import_parent' );
|
1942 |
+
delete_post_meta( $post_id, '_wxr_import_user_slug' );
|
1943 |
+
delete_post_meta( $post_id, '_wxr_import_has_attachment_refs' );
|
1944 |
+
}// End foreach().
|
1945 |
+
}
|
1946 |
+
|
1947 |
+
protected function post_process_menu_item( $post_id ) {
|
1948 |
+
$menu_object_id = get_post_meta( $post_id, '_wxr_import_menu_item', true );
|
1949 |
+
if ( empty( $menu_object_id ) ) {
|
1950 |
+
// No processing needed!
|
1951 |
+
return;
|
1952 |
+
}
|
1953 |
+
|
1954 |
+
$menu_item_type = get_post_meta( $post_id, '_menu_item_type', true );
|
1955 |
+
switch ( $menu_item_type ) {
|
1956 |
+
case 'taxonomy':
|
1957 |
+
if ( isset( $this->mapping['term_id'][ $menu_object_id ] ) ) {
|
1958 |
+
$menu_object = $this->mapping['term_id'][ $menu_object_id ];
|
1959 |
+
}
|
1960 |
+
break;
|
1961 |
+
|
1962 |
+
case 'post_type':
|
1963 |
+
if ( isset( $this->mapping['post'][ $menu_object_id ] ) ) {
|
1964 |
+
$menu_object = $this->mapping['post'][ $menu_object_id ];
|
1965 |
+
}
|
1966 |
+
break;
|
1967 |
+
|
1968 |
+
default:
|
1969 |
+
// Cannot handle this.
|
1970 |
+
return;
|
1971 |
+
}
|
1972 |
+
|
1973 |
+
if ( ! empty( $menu_object ) ) {
|
1974 |
+
update_post_meta( $post_id, '_menu_item_object_id', wp_slash( $menu_object ) );
|
1975 |
+
} else {
|
1976 |
+
$this->logger->warning( sprintf(
|
1977 |
+
__( 'Could not find the menu object for "%1$s" (post #%2$d)', 'wordpress-importer' ),
|
1978 |
+
get_the_title( $post_id ),
|
1979 |
+
$post_id
|
1980 |
+
) );
|
1981 |
+
$this->logger->debug( sprintf(
|
1982 |
+
__( 'Post %1$d was imported with object "%2$d" of type "%3$s", but could not be found', 'wordpress-importer' ),
|
1983 |
+
$post_id,
|
1984 |
+
$menu_object_id,
|
1985 |
+
$menu_item_type
|
1986 |
+
) );
|
1987 |
+
}
|
1988 |
+
|
1989 |
+
delete_post_meta( $post_id, '_wxr_import_menu_item' );
|
1990 |
+
}
|
1991 |
+
|
1992 |
+
|
1993 |
+
protected function post_process_comments( $todo ) {
|
1994 |
+
foreach ( $todo as $comment_id => $_ ) {
|
1995 |
+
$data = array();
|
1996 |
+
|
1997 |
+
$parent_id = get_comment_meta( $comment_id, '_wxr_import_parent', true );
|
1998 |
+
if ( ! empty( $parent_id ) ) {
|
1999 |
+
// Have we imported the parent now?
|
2000 |
+
if ( isset( $this->mapping['comment'][ $parent_id ] ) ) {
|
2001 |
+
$data['comment_parent'] = $this->mapping['comment'][ $parent_id ];
|
2002 |
+
} else {
|
2003 |
+
$this->logger->warning( sprintf(
|
2004 |
+
__( 'Could not find the comment parent for comment #%d', 'wordpress-importer' ),
|
2005 |
+
$comment_id
|
2006 |
+
) );
|
2007 |
+
$this->logger->debug( sprintf(
|
2008 |
+
__( 'Comment %1$d was imported with parent %2$d, but could not be found', 'wordpress-importer' ),
|
2009 |
+
$comment_id,
|
2010 |
+
$parent_id
|
2011 |
+
) );
|
2012 |
+
}
|
2013 |
+
}
|
2014 |
+
|
2015 |
+
$author_id = get_comment_meta( $comment_id, '_wxr_import_user', true );
|
2016 |
+
if ( ! empty( $author_id ) ) {
|
2017 |
+
// Have we imported the user now?
|
2018 |
+
if ( isset( $this->mapping['user'][ $author_id ] ) ) {
|
2019 |
+
$data['user_id'] = $this->mapping['user'][ $author_id ];
|
2020 |
+
} else {
|
2021 |
+
$this->logger->warning( sprintf(
|
2022 |
+
__( 'Could not find the author for comment #%d', 'wordpress-importer' ),
|
2023 |
+
$comment_id
|
2024 |
+
) );
|
2025 |
+
$this->logger->debug( sprintf(
|
2026 |
+
__( 'Comment %1$d was imported with author %2$d, but could not be found', 'wordpress-importer' ),
|
2027 |
+
$comment_id,
|
2028 |
+
$author_id
|
2029 |
+
) );
|
2030 |
+
}
|
2031 |
+
}
|
2032 |
+
|
2033 |
+
// Do we have updates to make?
|
2034 |
+
if ( empty( $data ) ) {
|
2035 |
+
continue;
|
2036 |
+
}
|
2037 |
+
|
2038 |
+
// Run the update
|
2039 |
+
$data['comment_ID'] = $comment_ID;
|
2040 |
+
$result = wp_update_comment( wp_slash( $data ) );
|
2041 |
+
if ( empty( $result ) ) {
|
2042 |
+
$this->logger->warning( sprintf(
|
2043 |
+
__( 'Could not update comment #%d with mapped data', 'wordpress-importer' ),
|
2044 |
+
$comment_id
|
2045 |
+
) );
|
2046 |
+
continue;
|
2047 |
+
}
|
2048 |
+
|
2049 |
+
// Clear out our temporary meta keys
|
2050 |
+
delete_comment_meta( $comment_id, '_wxr_import_parent' );
|
2051 |
+
delete_comment_meta( $comment_id, '_wxr_import_user' );
|
2052 |
+
}// End foreach().
|
2053 |
+
}
|
2054 |
+
|
2055 |
+
/**
|
2056 |
+
* Use stored mapping information to update old attachment URLs
|
2057 |
+
*/
|
2058 |
+
protected function replace_attachment_urls_in_content() {
|
2059 |
+
global $wpdb;
|
2060 |
+
// make sure we do the longest urls first, in case one is a substring of another
|
2061 |
+
uksort( $this->url_remap, array( $this, 'cmpr_strlen' ) );
|
2062 |
+
|
2063 |
+
foreach ( $this->url_remap as $from_url => $to_url ) {
|
2064 |
+
// remap urls in post_content
|
2065 |
+
$query = $wpdb->prepare( "UPDATE {$wpdb->posts} SET post_content = REPLACE(post_content, %s, %s)", $from_url, $to_url );
|
2066 |
+
$wpdb->query( $query );
|
2067 |
+
|
2068 |
+
// remap enclosure urls
|
2069 |
+
$query = $wpdb->prepare( "UPDATE {$wpdb->postmeta} SET meta_value = REPLACE(meta_value, %s, %s) WHERE meta_key='enclosure'", $from_url, $to_url );
|
2070 |
+
$result = $wpdb->query( $query );
|
2071 |
+
}
|
2072 |
+
}
|
2073 |
+
|
2074 |
+
/**
|
2075 |
+
* Update _thumbnail_id meta to new, imported attachment IDs
|
2076 |
+
*/
|
2077 |
+
function remap_featured_images() {
|
2078 |
+
// cycle through posts that have a featured image
|
2079 |
+
foreach ( $this->featured_images as $post_id => $value ) {
|
2080 |
+
if ( isset( $this->processed_posts[ $value ] ) ) {
|
2081 |
+
$new_id = $this->processed_posts[ $value ];
|
2082 |
+
|
2083 |
+
// only update if there's a difference
|
2084 |
+
if ( $new_id !== $value ) {
|
2085 |
+
update_post_meta( $post_id, '_thumbnail_id', $new_id );
|
2086 |
+
}
|
2087 |
+
}
|
2088 |
+
}
|
2089 |
+
}
|
2090 |
+
|
2091 |
+
/**
|
2092 |
+
* Decide if the given meta key maps to information we will want to import
|
2093 |
+
*
|
2094 |
+
* @param string $key The meta key to check
|
2095 |
+
* @return string|bool The key if we do want to import, false if not
|
2096 |
+
*/
|
2097 |
+
public function is_valid_meta_key( $key ) {
|
2098 |
+
// skip attachment metadata since we'll regenerate it from scratch
|
2099 |
+
// skip _edit_lock as not relevant for import
|
2100 |
+
if ( in_array( $key, array( '_wp_attached_file', '_wp_attachment_metadata', '_edit_lock' ) ) ) {
|
2101 |
+
return false;
|
2102 |
+
}
|
2103 |
+
|
2104 |
+
return $key;
|
2105 |
+
}
|
2106 |
+
|
2107 |
+
/**
|
2108 |
+
* Decide what the maximum file size for downloaded attachments is.
|
2109 |
+
* Default is 0 (unlimited), can be filtered via import_attachment_size_limit
|
2110 |
+
*
|
2111 |
+
* @return int Maximum attachment file size to import
|
2112 |
+
*/
|
2113 |
+
protected function max_attachment_size() {
|
2114 |
+
return apply_filters( 'import_attachment_size_limit', 0 );
|
2115 |
+
}
|
2116 |
+
|
2117 |
+
/**
|
2118 |
+
* Added to http_request_timeout filter to force timeout at 60 seconds during import
|
2119 |
+
*
|
2120 |
+
* @access protected
|
2121 |
+
* @return int 60
|
2122 |
+
*/
|
2123 |
+
function bump_request_timeout( $val ) {
|
2124 |
+
return 60;
|
2125 |
+
}
|
2126 |
+
|
2127 |
+
// return the difference in length between two strings
|
2128 |
+
function cmpr_strlen( $a, $b ) {
|
2129 |
+
return strlen( $b ) - strlen( $a );
|
2130 |
+
}
|
2131 |
+
|
2132 |
+
/**
|
2133 |
+
* Prefill existing post data.
|
2134 |
+
*
|
2135 |
+
* This preloads all GUIDs into memory, allowing us to avoid hitting the
|
2136 |
+
* database when we need to check for existence. With larger imports, this
|
2137 |
+
* becomes prohibitively slow to perform SELECT queries on each.
|
2138 |
+
*
|
2139 |
+
* By preloading all this data into memory, it's a constant-time lookup in
|
2140 |
+
* PHP instead. However, this does use a lot more memory, so for sites doing
|
2141 |
+
* small imports onto a large site, it may be a better tradeoff to use
|
2142 |
+
* on-the-fly checking instead.
|
2143 |
+
*/
|
2144 |
+
protected function prefill_existing_posts() {
|
2145 |
+
global $wpdb;
|
2146 |
+
$posts = $wpdb->get_results( "SELECT ID, guid FROM {$wpdb->posts}" );
|
2147 |
+
|
2148 |
+
foreach ( $posts as $item ) {
|
2149 |
+
$this->exists['post'][ $item->guid ] = $item->ID;
|
2150 |
+
}
|
2151 |
+
}
|
2152 |
+
|
2153 |
+
/**
|
2154 |
+
* Does the post exist?
|
2155 |
+
*
|
2156 |
+
* @param array $data Post data to check against.
|
2157 |
+
* @return int|bool Existing post ID if it exists, false otherwise.
|
2158 |
+
*/
|
2159 |
+
protected function post_exists( $data ) {
|
2160 |
+
// Constant-time lookup if we prefilled
|
2161 |
+
$exists_key = $data['guid'];
|
2162 |
+
|
2163 |
+
if ( $this->options['prefill_existing_posts'] ) {
|
2164 |
+
return isset( $this->exists['post'][ $exists_key ] ) ? $this->exists['post'][ $exists_key ] : false;
|
2165 |
+
}
|
2166 |
+
|
2167 |
+
// No prefilling, but might have already handled it
|
2168 |
+
if ( isset( $this->exists['post'][ $exists_key ] ) ) {
|
2169 |
+
return $this->exists['post'][ $exists_key ];
|
2170 |
+
}
|
2171 |
+
|
2172 |
+
// Still nothing, try post_exists, and cache it
|
2173 |
+
$exists = post_exists( $data['post_title'], $data['post_content'], $data['post_date'] );
|
2174 |
+
$this->exists['post'][ $exists_key ] = $exists;
|
2175 |
+
|
2176 |
+
return $exists;
|
2177 |
+
}
|
2178 |
+
|
2179 |
+
/**
|
2180 |
+
* Mark the post as existing.
|
2181 |
+
*
|
2182 |
+
* @param array $data Post data to mark as existing.
|
2183 |
+
* @param int $post_id Post ID.
|
2184 |
+
*/
|
2185 |
+
protected function mark_post_exists( $data, $post_id ) {
|
2186 |
+
$exists_key = $data['guid'];
|
2187 |
+
$this->exists['post'][ $exists_key ] = $post_id;
|
2188 |
+
}
|
2189 |
+
|
2190 |
+
/**
|
2191 |
+
* Prefill existing comment data.
|
2192 |
+
*
|
2193 |
+
* @see self::prefill_existing_posts() for justification of why this exists.
|
2194 |
+
*/
|
2195 |
+
protected function prefill_existing_comments() {
|
2196 |
+
global $wpdb;
|
2197 |
+
$posts = $wpdb->get_results( "SELECT comment_ID, comment_author, comment_date FROM {$wpdb->comments}" );
|
2198 |
+
|
2199 |
+
foreach ( $posts as $item ) {
|
2200 |
+
$exists_key = sha1( $item->comment_author . ':' . $item->comment_date );
|
2201 |
+
$this->exists['comment'][ $exists_key ] = $item->comment_ID;
|
2202 |
+
}
|
2203 |
+
}
|
2204 |
+
|
2205 |
+
/**
|
2206 |
+
* Does the comment exist?
|
2207 |
+
*
|
2208 |
+
* @param array $data Comment data to check against.
|
2209 |
+
* @return int|bool Existing comment ID if it exists, false otherwise.
|
2210 |
+
*/
|
2211 |
+
protected function comment_exists( $data ) {
|
2212 |
+
$exists_key = sha1( $data['comment_author'] . ':' . $data['comment_date'] );
|
2213 |
+
|
2214 |
+
// Constant-time lookup if we prefilled
|
2215 |
+
if ( $this->options['prefill_existing_comments'] ) {
|
2216 |
+
return isset( $this->exists['comment'][ $exists_key ] ) ? $this->exists['comment'][ $exists_key ] : false;
|
2217 |
+
}
|
2218 |
+
|
2219 |
+
// No prefilling, but might have already handled it
|
2220 |
+
if ( isset( $this->exists['comment'][ $exists_key ] ) ) {
|
2221 |
+
return $this->exists['comment'][ $exists_key ];
|
2222 |
+
}
|
2223 |
+
|
2224 |
+
// Still nothing, try comment_exists, and cache it
|
2225 |
+
$exists = comment_exists( $data['comment_author'], $data['comment_date'] );
|
2226 |
+
$this->exists['comment'][ $exists_key ] = $exists;
|
2227 |
+
|
2228 |
+
return $exists;
|
2229 |
+
}
|
2230 |
+
|
2231 |
+
/**
|
2232 |
+
* Mark the comment as existing.
|
2233 |
+
*
|
2234 |
+
* @param array $data Comment data to mark as existing.
|
2235 |
+
* @param int $comment_id Comment ID.
|
2236 |
+
*/
|
2237 |
+
protected function mark_comment_exists( $data, $comment_id ) {
|
2238 |
+
$exists_key = sha1( $data['comment_author'] . ':' . $data['comment_date'] );
|
2239 |
+
$this->exists['comment'][ $exists_key ] = $comment_id;
|
2240 |
+
}
|
2241 |
+
|
2242 |
+
/**
|
2243 |
+
* Prefill existing term data.
|
2244 |
+
*
|
2245 |
+
* @see self::prefill_existing_posts() for justification of why this exists.
|
2246 |
+
*/
|
2247 |
+
protected function prefill_existing_terms() {
|
2248 |
+
global $wpdb;
|
2249 |
+
$query = "SELECT t.term_id, tt.taxonomy, t.slug FROM {$wpdb->terms} AS t";
|
2250 |
+
$query .= " JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id";
|
2251 |
+
$terms = $wpdb->get_results( $query );
|
2252 |
+
|
2253 |
+
foreach ( $terms as $item ) {
|
2254 |
+
$exists_key = sha1( $item->taxonomy . ':' . $item->slug );
|
2255 |
+
$this->exists['term'][ $exists_key ] = $item->term_id;
|
2256 |
+
}
|
2257 |
+
}
|
2258 |
+
|
2259 |
+
/**
|
2260 |
+
* Does the term exist?
|
2261 |
+
*
|
2262 |
+
* @param array $data Term data to check against.
|
2263 |
+
* @return int|bool Existing term ID if it exists, false otherwise.
|
2264 |
+
*/
|
2265 |
+
protected function term_exists( $data ) {
|
2266 |
+
$exists_key = sha1( $data['taxonomy'] . ':' . $data['slug'] );
|
2267 |
+
|
2268 |
+
// Constant-time lookup if we prefilled
|
2269 |
+
if ( $this->options['prefill_existing_terms'] ) {
|
2270 |
+
return isset( $this->exists['term'][ $exists_key ] ) ? $this->exists['term'][ $exists_key ] : false;
|
2271 |
+
}
|
2272 |
+
|
2273 |
+
// No prefilling, but might have already handled it
|
2274 |
+
if ( isset( $this->exists['term'][ $exists_key ] ) ) {
|
2275 |
+
return $this->exists['term'][ $exists_key ];
|
2276 |
+
}
|
2277 |
+
|
2278 |
+
// Still nothing, try comment_exists, and cache it
|
2279 |
+
$exists = term_exists( $data['slug'], $data['taxonomy'] );
|
2280 |
+
if ( is_array( $exists ) ) {
|
2281 |
+
$exists = $exists['term_id'];
|
2282 |
+
}
|
2283 |
+
|
2284 |
+
$this->exists['term'][ $exists_key ] = $exists;
|
2285 |
+
|
2286 |
+
return $exists;
|
2287 |
+
}
|
2288 |
+
|
2289 |
+
/**
|
2290 |
+
* Mark the term as existing.
|
2291 |
+
*
|
2292 |
+
* @param array $data Term data to mark as existing.
|
2293 |
+
* @param int $term_id Term ID.
|
2294 |
+
*/
|
2295 |
+
protected function mark_term_exists( $data, $term_id ) {
|
2296 |
+
$exists_key = sha1( $data['taxonomy'] . ':' . $data['slug'] );
|
2297 |
+
$this->exists['term'][ $exists_key ] = $term_id;
|
2298 |
+
}
|
2299 |
+
}
|
readme.txt
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
=== Astra Sites ===
|
2 |
+
Contributors: brainstormforce
|
3 |
+
Donate link: https://wpastra.com/pro/
|
4 |
+
Tags: demo
|
5 |
+
Requires at least: 4.4
|
6 |
+
Tested up to: 4.8.1
|
7 |
+
Stable tag: 1.0.0
|
8 |
+
License: GPLv2 or later
|
9 |
+
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
10 |
+
|
11 |
+
Import Astra sites with just one click.
|
12 |
+
|
13 |
+
== Description ==
|
14 |
+
|
15 |
+
Import Astra sites with just one click.
|
16 |
+
|
17 |
+
== Installation ==
|
18 |
+
|
19 |
+
1. Upload the plugin files to the `/wp-content/plugins/astra-sites` directory, or install the plugin through the WordPress plugins screen directly.
|
20 |
+
1. Activate the plugin through the 'Plugins' screen in WordPress
|
21 |
+
1. Use the Appearance->Astra-> Astra Sites to select the page to be displayed as header and footer.
|
22 |
+
|
23 |
+
== Changelog ==
|
24 |
+
|
25 |
+
= 1.0 =
|
26 |
+
* Initial Release
|