Astra Starter Sites - Version 1.2.14

Version Description

Download this release

Release Info

Developer Nikschavan
Plugin Icon Astra Starter Sites
Version 1.2.14
Comparing to
See all releases

Code changes from version 1.2.13 to 1.2.14

Files changed (29) hide show
  1. astra-sites.php +54 -54
  2. inc/assets/css/admin.css +475 -475
  3. inc/assets/js/admin-page.js +1438 -1397
  4. inc/assets/js/astra-sites-api.js +56 -56
  5. inc/assets/js/astra-sites-notices.js +20 -20
  6. inc/assets/js/eventsource.js +673 -673
  7. inc/assets/js/eventsource.min.js +5 -5
  8. inc/assets/js/render-grid.js +591 -591
  9. inc/classes/class-astra-sites-importer.php +407 -334
  10. inc/classes/class-astra-sites.php +471 -468
  11. inc/classes/compatibility/class-astra-sites-compatibility.php +66 -67
  12. inc/importers/batch-processing/class-astra-sites-batch-processing-beaver-builder.php +263 -236
  13. inc/importers/batch-processing/class-astra-sites-batch-processing-brizy.php +126 -0
  14. inc/importers/batch-processing/class-astra-sites-batch-processing-elementor.php +113 -93
  15. inc/importers/batch-processing/class-astra-sites-batch-processing-gutenberg.php +146 -0
  16. inc/importers/batch-processing/class-astra-sites-batch-processing-misc.php +139 -140
  17. inc/importers/batch-processing/class-astra-sites-batch-processing.php +209 -204
  18. inc/importers/batch-processing/helpers/class-wp-async-request.php +164 -164
  19. inc/importers/batch-processing/helpers/class-wp-background-process.php +513 -513
  20. inc/importers/class-astra-site-options-import.php +287 -284
  21. inc/importers/class-astra-sites-helper.php +311 -310
  22. inc/importers/class-widgets-importer.php +278 -278
  23. inc/importers/wxr-importer/class-astra-wxr-importer.php +378 -368
  24. inc/importers/wxr-importer/class-logger.php +142 -142
  25. inc/importers/wxr-importer/class-wp-importer-logger-serversentevents.php +46 -46
  26. inc/importers/wxr-importer/class-wxr-import-info.php +20 -20
  27. inc/importers/wxr-importer/class-wxr-importer.php +2300 -2300
  28. languages/astra-sites.pot +720 -708
  29. readme.txt +285 -282
astra-sites.php CHANGED
@@ -1,54 +1,54 @@
1
- <?php
2
- /**
3
- * Plugin Name: Astra Starter Sites – Elementor, Beaver Builder & Gutenberg Templates
4
- * Plugin URI: http://www.wpastra.com/pro/
5
- * Description: Import free sites build with Astra theme.
6
- * Version: 1.2.13
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
- if ( ! defined( 'ASTRA_SITES_NAME' ) ) {
18
- define( 'ASTRA_SITES_NAME', __( 'Astra Sites', 'astra-sites' ) );
19
- }
20
-
21
- if ( ! defined( 'ASTRA_SITES_VER' ) ) {
22
- define( 'ASTRA_SITES_VER', '1.2.13' );
23
- }
24
-
25
- if ( ! defined( 'ASTRA_SITES_FILE' ) ) {
26
- define( 'ASTRA_SITES_FILE', __FILE__ );
27
- }
28
-
29
- if ( ! defined( 'ASTRA_SITES_BASE' ) ) {
30
- define( 'ASTRA_SITES_BASE', plugin_basename( ASTRA_SITES_FILE ) );
31
- }
32
-
33
- if ( ! defined( 'ASTRA_SITES_DIR' ) ) {
34
- define( 'ASTRA_SITES_DIR', plugin_dir_path( ASTRA_SITES_FILE ) );
35
- }
36
-
37
- if ( ! defined( 'ASTRA_SITES_URI' ) ) {
38
- define( 'ASTRA_SITES_URI', plugins_url( '/', ASTRA_SITES_FILE ) );
39
- }
40
-
41
- if ( ! function_exists( 'astra_sites_setup' ) ) :
42
-
43
- /**
44
- * Astra Sites Setup
45
- *
46
- * @since 1.0.5
47
- */
48
- function astra_sites_setup() {
49
- require_once ASTRA_SITES_DIR . 'inc/classes/class-astra-sites.php';
50
- }
51
-
52
- add_action( 'plugins_loaded', 'astra_sites_setup' );
53
-
54
- endif;
1
+ <?php
2
+ /**
3
+ * Plugin Name: Astra Starter Sites – Elementor, Beaver Builder & Gutenberg Templates
4
+ * Plugin URI: http://www.wpastra.com/pro/
5
+ * Description: Import free sites build with Astra theme.
6
+ * Version: 1.2.14
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
+ if ( ! defined( 'ASTRA_SITES_NAME' ) ) {
18
+ define( 'ASTRA_SITES_NAME', __( 'Astra Sites', 'astra-sites' ) );
19
+ }
20
+
21
+ if ( ! defined( 'ASTRA_SITES_VER' ) ) {
22
+ define( 'ASTRA_SITES_VER', '1.2.14' );
23
+ }
24
+
25
+ if ( ! defined( 'ASTRA_SITES_FILE' ) ) {
26
+ define( 'ASTRA_SITES_FILE', __FILE__ );
27
+ }
28
+
29
+ if ( ! defined( 'ASTRA_SITES_BASE' ) ) {
30
+ define( 'ASTRA_SITES_BASE', plugin_basename( ASTRA_SITES_FILE ) );
31
+ }
32
+
33
+ if ( ! defined( 'ASTRA_SITES_DIR' ) ) {
34
+ define( 'ASTRA_SITES_DIR', plugin_dir_path( ASTRA_SITES_FILE ) );
35
+ }
36
+
37
+ if ( ! defined( 'ASTRA_SITES_URI' ) ) {
38
+ define( 'ASTRA_SITES_URI', plugins_url( '/', ASTRA_SITES_FILE ) );
39
+ }
40
+
41
+ if ( ! function_exists( 'astra_sites_setup' ) ) :
42
+
43
+ /**
44
+ * Astra Sites Setup
45
+ *
46
+ * @since 1.0.5
47
+ */
48
+ function astra_sites_setup() {
49
+ require_once ASTRA_SITES_DIR . 'inc/classes/class-astra-sites.php';
50
+ }
51
+
52
+ add_action( 'plugins_loaded', 'astra_sites_setup' );
53
+
54
+ endif;
inc/assets/css/admin.css CHANGED
@@ -1,476 +1,476 @@
1
- .wrap .status,
2
- .wrap .site-type {
3
- position: absolute;
4
- z-index: 1;
5
- color: #fff;
6
- padding: 0.5em 1em;
7
- top: -0.5em;
8
- text-transform: uppercase;
9
- }
10
- .wrap .status,
11
- .wrap .site-type.premium {
12
- background: #0073aa;
13
- }
14
- .wrap .status {
15
- left: -0.5em;
16
- }
17
- .wrap .site-type.premium {
18
- right: -0.5em;
19
- }
20
-
21
- .wrap .status.publish,
22
- .wrap .site-type.free {
23
- display: none;
24
- }
25
-
26
- .install-theme-info .site-type {
27
- display: none;
28
- }
29
-
30
- .theme {
31
- position: relative;
32
- }
33
- .wrap .astra-sites-preview .site-type.premium {
34
- display: block;
35
- display: none;
36
- position: relative;
37
- margin: 0.5em 0em 1em 0em;
38
- top: 0;
39
- left: 0;
40
- text-align: center;
41
- }
42
-
43
- .theme-details-read-more.open {
44
- margin: 0.5em 0 0 0;
45
- }
46
-
47
- .astra-sites-preview .theme-screenshot {
48
- width: 100%;
49
- }
50
-
51
- .install-theme-info .site-type.premium {
52
- display: none;
53
- }
54
-
55
- /**
56
- * Required Plugins
57
- */
58
- .required-plugins.loading {
59
- text-align: center;
60
- }
61
- .required-plugins button {
62
- float: right;
63
- }
64
- .required-plugins .plugin-card {
65
- float: none;
66
- width: 100%;
67
- border: none;
68
- margin: 0 0 0.8em 0;
69
- display: flex;
70
- justify-content: space-between;
71
- align-items: center;
72
- transition: background ease 0.8s;
73
- }
74
- .required-plugins .plugin-card.plugin-card-update-failed {
75
- flex-wrap: wrap;
76
- }
77
- .required-plugins .spinner {
78
- float: none;
79
- margin: 0;
80
- }
81
-
82
- .expanded .wp-full-overlay-footer {
83
- height: 111px;
84
- }
85
-
86
- .wp-full-overlay-footer .view-site,
87
- .wp-full-overlay-footer .go-pro,
88
- .wp-full-overlay-footer .astra-demo-import {
89
- width: 100%;
90
- text-align: center;
91
- }
92
-
93
- .wp-core-ui .wp-full-overlay-footer .button.button-hero,
94
- .wp-core-ui .wp-full-overlay-footer .button-group.button-hero .button {
95
- padding: 0 10px 1px;
96
- }
97
-
98
- .wp-full-overlay-footer .installing:before {
99
- vertical-align: text-bottom;
100
- }
101
-
102
- .required-plugins-wrap h4 {
103
- margin: 1em 0 0.5em 0;
104
- padding: 0.5em 0;
105
- transition: all ease 0.3s;
106
- }
107
-
108
- /**
109
- * Read more link
110
- */
111
- .wp-core-ui .theme-details-read-more:focus,
112
- .wp-core-ui .theme-details-read-more:hover {
113
- outline: none;
114
- box-shadow: none;
115
- }
116
- .wp-core-ui .theme-details-read-more {
117
- margin: 10px 0;
118
- display: none;
119
- text-decoration: none;
120
- }
121
-
122
- /**
123
- * Go pro.
124
- */
125
- .wp-core-ui .go-pro.button[disabled] {
126
- background-color: #fcb92c !important;
127
- color: white !important;
128
- box-shadow: 1px 0 #eab23a !important;
129
- text-shadow: 1px 0 #6b4e13 !important;
130
- border-color: #e2a932 !important;
131
- cursor: pointer;
132
- }
133
- .wp-core-ui .view-site .dashicons,
134
- .wp-core-ui .go-pro .dashicons {
135
- font-size: 1rem;
136
- vertical-align: middle;
137
- }
138
-
139
- /**
140
- * Errors
141
- */
142
- .plugin-card-update-failed .notice {
143
- margin-top: 1.5em;
144
- }
145
-
146
- .no-themes {
147
- margin-top: 40px;
148
- }
149
-
150
- .no-themes p {
151
- font-size: 15px;
152
- }
153
-
154
- .no-themes .left-margin {
155
- margin-left: 30px;
156
- }
157
-
158
- /**
159
- *
160
- */
161
- .astra-sites-preview .wp-full-overlay-sidebar-content {
162
- bottom: 100px;
163
- }
164
-
165
- .footer-import-button-wrap {
166
- padding: 10px 20px;
167
- }
168
-
169
- .footer-import-button-wrap .button {
170
- margin: 0;
171
- }
172
-
173
- .astra-sites-preview.expanded .wp-full-overlay-footer {
174
- left: initial;
175
- }
176
-
177
- /**
178
- * Menu Page
179
- */
180
- .astra-sites-title {
181
- float: left;
182
- font-size: 23px;
183
- font-weight: 400;
184
- margin: 0 0 6px 0px;
185
- padding: 0;
186
- line-height: 29px;
187
- }
188
-
189
- #astra-sites-menu-page {
190
- margin-top: 10px;
191
- }
192
-
193
- /**
194
- * API Error
195
- */
196
- .astra-api-error {
197
- margin: 0 0 0.5em 0;
198
- }
199
-
200
- /**
201
- * Grid
202
- */
203
- .wp-filter .search-form {
204
- margin-left: 1em;
205
- }
206
- .wp-filter .search-form input[type="search"] {
207
- width: 200px;
208
- font-size: 13px;
209
- padding: 5px 10px;
210
- }
211
- .section-left {
212
- display: inline-block;
213
- }
214
- .section-right {
215
- float: right;
216
- }
217
- .filter-count {
218
- min-width: 3em;
219
- }
220
- .astra-site-preview-on {
221
- overflow: hidden;
222
- }
223
-
224
- .appearance_page_astra-sites .notice {
225
- margin-left: 0;
226
- width: auto;
227
- float: none;
228
- }
229
- .filters-wrap {
230
- display: inline-block;
231
- }
232
- .spinner-wrap {
233
- text-align: center;
234
- }
235
- .spinner-wrap .spinner {
236
- float: none;
237
- }
238
- .hide-me {
239
- display: none !important;
240
- }
241
- #astra-sites-admin {
242
- height: 100vh;
243
- }
244
- .install-theme-info > .notice {
245
- margin: 5px 0 10px 0;
246
- }
247
-
248
- .astra-sites-suggestions:before {
249
- border: 5px dashed #ccc;
250
- position: absolute;
251
- left: 0;
252
- right: 0;
253
- top: 0;
254
- bottom: 0px;
255
- }
256
-
257
- .astra-sites-suggestions {
258
- min-height: 280px;
259
- border: none !important;
260
- }
261
-
262
- .astra-sites-suggestions a {
263
- border: none;
264
- outline: none;
265
- }
266
-
267
- .astra-sites-suggestions .inner {
268
- border: 6px solid #24282e !important;
269
- padding: 27% 10% 50% 10%;
270
- text-align: center;
271
- position: absolute;
272
- left: 0;
273
- right: 0;
274
- top: 0;
275
- background: #33383d;
276
- bottom: 0;
277
- color: #eee;
278
- cursor: auto;
279
- }
280
-
281
- .astra-sites-suggestions .inner a {
282
- color: #00b9eb;
283
- }
284
-
285
- .astra-sites-suggestions p {
286
- font-size: 1rem;
287
- margin: 0;
288
- }
289
-
290
- .astra-notice {
291
- margin: 2em 2em 0em 0em;
292
- }
293
-
294
- .no-themes .description {
295
- display: block;
296
- }
297
-
298
- /**
299
- * Responsive Button UI
300
- */
301
- .astra-sites-preview .wp-full-overlay-footer .devices button.active:before,
302
- .astra-sites-preview .wp-full-overlay-footer .devices button:hover:before {
303
- color: #0073aa;
304
- }
305
- .astra-sites-preview .wp-full-overlay-footer .devices button:before {
306
- color: #c1c1c1;
307
- }
308
- .astra-sites-preview .wp-full-overlay-footer .devices button:hover {
309
- background-color: transparent;
310
- }
311
- .astra-sites-preview .wp-full-overlay-footer .devices button {
312
- border: none;
313
- }
314
- .astra-sites-preview .wp-full-overlay-footer .devices button:focus,
315
- .astra-sites-preview .wp-full-overlay-footer .devices button.active:hover {
316
- border-bottom-color: transparent;
317
- background-color: transparent;
318
- }
319
- .not-click-able {
320
- pointer-events: none !important;
321
- }
322
- body.page-builder-selected .select-page-builder,
323
- body.loading-content .select-page-builder {
324
- display: none;
325
- }
326
- .select-page-builder .up-arrow {
327
- -webkit-transform: rotate(90deg);
328
- -moz-transform: rotate(90deg);
329
- -ms-transform: rotate(90deg);
330
- transform: rotate(90deg);
331
- display: inline-block;
332
- font-size: 1.5em;
333
- color: #797979;
334
- vertical-align: middle;
335
- margin-right: 10px;
336
- -webkit-transition: all linear 0.6s;
337
- -moz-transition: all linear 0.6s;
338
- -ms-transition: all linear 0.6s;
339
- transition: all linear 0.6s;
340
- -webkit-animation-duration: 1s;
341
- animation-duration: 1s;
342
- -webkit-animation-fill-mode: both;
343
- animation-fill-mode: both;
344
- -webkit-animation-timing-function: ease-in-out;
345
- animation-timing-function: ease-in-out;
346
- animation-iteration-count: infinite;
347
- -webkit-animation-iteration-count: infinite;
348
- animation-name: bounce;
349
- -moz-animation-name: bounce;
350
- }
351
- .select-page-builder {
352
- margin-left: 6em;
353
- }
354
-
355
- .select-page-builder img {
356
- max-width: 100%;
357
- }
358
-
359
- .select-page-builder .note-wrap {
360
- position: absolute;
361
- padding: 40px 0;
362
- margin-left: 170px;
363
- right: 0;
364
- left: 0;
365
- }
366
-
367
- .select-page-builder h3 {
368
- margin: 0;
369
- font-size: 2em;
370
- }
371
- .select-page-builder {
372
- margin: -20px 0 0 -5px;
373
- position: absolute;
374
- }
375
- .select-page-builder .note {
376
- margin-left: 1.5em;
377
- }
378
-
379
- @keyframes bounce {
380
- 0%,
381
- 100%,
382
- 20%,
383
- 50%,
384
- 80% {
385
- -webkit-transform: translateY(-0px) rotate(90deg);
386
- -moz-transform: translateY(-0px) rotate(90deg);
387
- -ms-transform: translateY(-0px) rotate(90deg);
388
- transform: translateY(-0px) rotate(90deg);
389
- }
390
- 40% {
391
- -webkit-transform: translateY(-2px) rotate(90deg);
392
- -moz-transform: translateY(-2px) rotate(90deg);
393
- -ms-transform: translateY(-2px) rotate(90deg);
394
- transform: translateY(-2px) rotate(90deg);
395
- }
396
- 60% {
397
- -webkit-transform: translateY(-1px) rotate(90deg);
398
- -moz-transform: translateY(-1px) rotate(90deg);
399
- -ms-transform: translateY(-1px) rotate(90deg);
400
- transform: translateY(-1px) rotate(90deg);
401
- }
402
- }
403
-
404
- /**
405
- * Processing Animation
406
- */
407
- .astra-demo-import.disabled {
408
- pointer-events: none;
409
- }
410
- .astra-demo-import.button.updating-message:before,
411
- .astra-demo-import.button.installing:before {
412
- -webkit-animation: cssAnimation .72s ease infinite;
413
- -moz-animation: cssAnimation .72s ease infinite;
414
- -o-animation: cssAnimation .72s ease infinite;
415
- -ms-animation: cssAnimation .72s ease infinite;
416
- animation: cssAnimation .72s ease infinite;
417
- }
418
-
419
- @-webkit-keyframes cssAnimation {
420
- from {
421
- -webkit-transform: rotate(0);
422
- -moz-transform: rotate(0);
423
- -o-transform: rotate(0);
424
- -ms-transform: rotate(0);
425
- transform: rotate(0);
426
- }
427
- to {
428
- -webkit-transform: rotate(360deg);
429
- -moz-transform: rotate(360deg);
430
- -o-transform: rotate(360deg);
431
- -ms-transform: rotate(360deg);
432
- transform: rotate(360deg);
433
- }
434
- }
435
- @-moz-keyframes cssAnimation {
436
- from {
437
- -webkit-transform: rotate(0);
438
- -moz-transform: rotate(0);
439
- -o-transform: rotate(0);
440
- -ms-transform: rotate(0);
441
- transform: rotate(0);
442
- }
443
- to {
444
- -webkit-transform: rotate(360deg);
445
- -moz-transform: rotate(360deg);
446
- -o-transform: rotate(360deg);
447
- -ms-transform: rotate(360deg);
448
- transform: rotate(360deg);
449
- }
450
- }
451
- @-o-keyframes cssAnimation {
452
- from {
453
- -webkit-transform: rotate(0);
454
- -moz-transform: rotate(0);
455
- -o-transform: rotate(0);
456
- -ms-transform: rotate(0);
457
- transform: rotate(0);
458
- }
459
- to {
460
- -webkit-transform: rotate(360deg);
461
- -moz-transform: rotate(360deg);
462
- -o-transform: rotate(360deg);
463
- -ms-transform: rotate(360deg);
464
- transform: rotate(360deg);
465
- }
466
- }
467
-
468
- #astra-sites-filters {
469
- display: inline-block;
470
- width: 100%;
471
- }
472
-
473
- .astra-site-down {
474
- padding: 1em 2em;
475
- margin-top: 1em;
476
  }
1
+ .wrap .status,
2
+ .wrap .site-type {
3
+ position: absolute;
4
+ z-index: 1;
5
+ color: #fff;
6
+ padding: 0.5em 1em;
7
+ top: -0.5em;
8
+ text-transform: uppercase;
9
+ }
10
+ .wrap .status,
11
+ .wrap .site-type.premium {
12
+ background: #0073aa;
13
+ }
14
+ .wrap .status {
15
+ left: -0.5em;
16
+ }
17
+ .wrap .site-type.premium {
18
+ right: -0.5em;
19
+ }
20
+
21
+ .wrap .status.publish,
22
+ .wrap .site-type.free {
23
+ display: none;
24
+ }
25
+
26
+ .install-theme-info .site-type {
27
+ display: none;
28
+ }
29
+
30
+ .theme {
31
+ position: relative;
32
+ }
33
+ .wrap .astra-sites-preview .site-type.premium {
34
+ display: block;
35
+ display: none;
36
+ position: relative;
37
+ margin: 0.5em 0em 1em 0em;
38
+ top: 0;
39
+ left: 0;
40
+ text-align: center;
41
+ }
42
+
43
+ .theme-details-read-more.open {
44
+ margin: 0.5em 0 0 0;
45
+ }
46
+
47
+ .astra-sites-preview .theme-screenshot {
48
+ width: 100%;
49
+ }
50
+
51
+ .install-theme-info .site-type.premium {
52
+ display: none;
53
+ }
54
+
55
+ /**
56
+ * Required Plugins
57
+ */
58
+ .required-plugins.loading {
59
+ text-align: center;
60
+ }
61
+ .required-plugins button {
62
+ float: right;
63
+ }
64
+ .required-plugins .plugin-card {
65
+ float: none;
66
+ width: 100%;
67
+ border: none;
68
+ margin: 0 0 0.8em 0;
69
+ display: flex;
70
+ justify-content: space-between;
71
+ align-items: center;
72
+ transition: background ease 0.8s;
73
+ }
74
+ .required-plugins .plugin-card.plugin-card-update-failed {
75
+ flex-wrap: wrap;
76
+ }
77
+ .required-plugins .spinner {
78
+ float: none;
79
+ margin: 0;
80
+ }
81
+
82
+ .expanded .wp-full-overlay-footer {
83
+ height: 111px;
84
+ }
85
+
86
+ .wp-full-overlay-footer .view-site,
87
+ .wp-full-overlay-footer .go-pro,
88
+ .wp-full-overlay-footer .astra-demo-import {
89
+ width: 100%;
90
+ text-align: center;
91
+ }
92
+
93
+ .wp-core-ui .wp-full-overlay-footer .button.button-hero,
94
+ .wp-core-ui .wp-full-overlay-footer .button-group.button-hero .button {
95
+ padding: 0 10px 1px;
96
+ }
97
+
98
+ .wp-full-overlay-footer .installing:before {
99
+ vertical-align: text-bottom;
100
+ }
101
+
102
+ .required-plugins-wrap h4 {
103
+ margin: 1em 0 0.5em 0;
104
+ padding: 0.5em 0;
105
+ transition: all ease 0.3s;
106
+ }
107
+
108
+ /**
109
+ * Read more link
110
+ */
111
+ .wp-core-ui .theme-details-read-more:focus,
112
+ .wp-core-ui .theme-details-read-more:hover {
113
+ outline: none;
114
+ box-shadow: none;
115
+ }
116
+ .wp-core-ui .theme-details-read-more {
117
+ margin: 10px 0;
118
+ display: none;
119
+ text-decoration: none;
120
+ }
121
+
122
+ /**
123
+ * Go pro.
124
+ */
125
+ .wp-core-ui .go-pro.button[disabled] {
126
+ background-color: #fcb92c !important;
127
+ color: white !important;
128
+ box-shadow: 1px 0 #eab23a !important;
129
+ text-shadow: 1px 0 #6b4e13 !important;
130
+ border-color: #e2a932 !important;
131
+ cursor: pointer;
132
+ }
133
+ .wp-core-ui .view-site .dashicons,
134
+ .wp-core-ui .go-pro .dashicons {
135
+ font-size: 1rem;
136
+ vertical-align: middle;
137
+ }
138
+
139
+ /**
140
+ * Errors
141
+ */
142
+ .plugin-card-update-failed .notice {
143
+ margin-top: 1.5em;
144
+ }
145
+
146
+ .no-themes {
147
+ margin-top: 40px;
148
+ }
149
+
150
+ .no-themes p {
151
+ font-size: 15px;
152
+ }
153
+
154
+ .no-themes .left-margin {
155
+ margin-left: 30px;
156
+ }
157
+
158
+ /**
159
+ *
160
+ */
161
+ .astra-sites-preview .wp-full-overlay-sidebar-content {
162
+ bottom: 100px;
163
+ }
164
+
165
+ .footer-import-button-wrap {
166
+ padding: 10px 20px;
167
+ }
168
+
169
+ .footer-import-button-wrap .button {
170
+ margin: 0;
171
+ }
172
+
173
+ .astra-sites-preview.expanded .wp-full-overlay-footer {
174
+ left: initial;
175
+ }
176
+
177
+ /**
178
+ * Menu Page
179
+ */
180
+ .astra-sites-title {
181
+ float: left;
182
+ font-size: 23px;
183
+ font-weight: 400;
184
+ margin: 0 0 6px 0px;
185
+ padding: 0;
186
+ line-height: 29px;
187
+ }
188
+
189
+ #astra-sites-menu-page {
190
+ margin-top: 10px;
191
+ }
192
+
193
+ /**
194
+ * API Error
195
+ */
196
+ .astra-api-error {
197
+ margin: 0 0 0.5em 0;
198
+ }
199
+
200
+ /**
201
+ * Grid
202
+ */
203
+ .wp-filter .search-form {
204
+ margin-left: 1em;
205
+ }
206
+ .wp-filter .search-form input[type="search"] {
207
+ width: 200px;
208
+ font-size: 13px;
209
+ padding: 5px 10px;
210
+ }
211
+ .section-left {
212
+ display: inline-block;
213
+ }
214
+ .section-right {
215
+ float: right;
216
+ }
217
+ .filter-count {
218
+ min-width: 3em;
219
+ }
220
+ .astra-site-preview-on {
221
+ overflow: hidden;
222
+ }
223
+
224
+ .appearance_page_astra-sites .notice {
225
+ margin-left: 0;
226
+ width: auto;
227
+ float: none;
228
+ }
229
+ .filters-wrap {
230
+ display: inline-block;
231
+ }
232
+ .spinner-wrap {
233
+ text-align: center;
234
+ }
235
+ .spinner-wrap .spinner {
236
+ float: none;
237
+ }
238
+ .hide-me {
239
+ display: none !important;
240
+ }
241
+ #astra-sites-admin {
242
+ height: 100vh;
243
+ }
244
+ .install-theme-info > .notice {
245
+ margin: 5px 0 10px 0;
246
+ }
247
+
248
+ .astra-sites-suggestions:before {
249
+ border: 5px dashed #ccc;
250
+ position: absolute;
251
+ left: 0;
252
+ right: 0;
253
+ top: 0;
254
+ bottom: 0px;
255
+ }
256
+
257
+ .astra-sites-suggestions {
258
+ min-height: 280px;
259
+ border: none !important;
260
+ }
261
+
262
+ .astra-sites-suggestions a {
263
+ border: none;
264
+ outline: none;
265
+ }
266
+
267
+ .astra-sites-suggestions .inner {
268
+ border: 6px solid #24282e !important;
269
+ padding: 27% 10% 50% 10%;
270
+ text-align: center;
271
+ position: absolute;
272
+ left: 0;
273
+ right: 0;
274
+ top: 0;
275
+ background: #33383d;
276
+ bottom: 0;
277
+ color: #eee;
278
+ cursor: auto;
279
+ }
280
+
281
+ .astra-sites-suggestions .inner a {
282
+ color: #00b9eb;
283
+ }
284
+
285
+ .astra-sites-suggestions p {
286
+ font-size: 1rem;
287
+ margin: 0;
288
+ }
289
+
290
+ .astra-notice {
291
+ margin: 2em 2em 0em 0em;
292
+ }
293
+
294
+ .no-themes .description {
295
+ display: block;
296
+ }
297
+
298
+ /**
299
+ * Responsive Button UI
300
+ */
301
+ .astra-sites-preview .wp-full-overlay-footer .devices button.active:before,
302
+ .astra-sites-preview .wp-full-overlay-footer .devices button:hover:before {
303
+ color: #0073aa;
304
+ }
305
+ .astra-sites-preview .wp-full-overlay-footer .devices button:before {
306
+ color: #c1c1c1;
307
+ }
308
+ .astra-sites-preview .wp-full-overlay-footer .devices button:hover {
309
+ background-color: transparent;
310
+ }
311
+ .astra-sites-preview .wp-full-overlay-footer .devices button {
312
+ border: none;
313
+ }
314
+ .astra-sites-preview .wp-full-overlay-footer .devices button:focus,
315
+ .astra-sites-preview .wp-full-overlay-footer .devices button.active:hover {
316
+ border-bottom-color: transparent;
317
+ background-color: transparent;
318
+ }
319
+ .not-click-able {
320
+ pointer-events: none !important;
321
+ }
322
+ body.page-builder-selected .select-page-builder,
323
+ body.loading-content .select-page-builder {
324
+ display: none;
325
+ }
326
+ .select-page-builder .up-arrow {
327
+ -webkit-transform: rotate(90deg);
328
+ -moz-transform: rotate(90deg);
329
+ -ms-transform: rotate(90deg);
330
+ transform: rotate(90deg);
331
+ display: inline-block;
332
+ font-size: 1.5em;
333
+ color: #797979;
334
+ vertical-align: middle;
335
+ margin-right: 10px;
336
+ -webkit-transition: all linear 0.6s;
337
+ -moz-transition: all linear 0.6s;
338
+ -ms-transition: all linear 0.6s;
339
+ transition: all linear 0.6s;
340
+ -webkit-animation-duration: 1s;
341
+ animation-duration: 1s;
342
+ -webkit-animation-fill-mode: both;
343
+ animation-fill-mode: both;
344
+ -webkit-animation-timing-function: ease-in-out;
345
+ animation-timing-function: ease-in-out;
346
+ animation-iteration-count: infinite;
347
+ -webkit-animation-iteration-count: infinite;
348
+ animation-name: bounce;
349
+ -moz-animation-name: bounce;
350
+ }
351
+ .select-page-builder {
352
+ margin-left: 6em;
353
+ }
354
+
355
+ .select-page-builder img {
356
+ max-width: 100%;
357
+ }
358
+
359
+ .select-page-builder .note-wrap {
360
+ position: absolute;
361
+ padding: 40px 0;
362
+ margin-left: 170px;
363
+ right: 0;
364
+ left: 0;
365
+ }
366
+
367
+ .select-page-builder h3 {
368
+ margin: 0;
369
+ font-size: 2em;
370
+ }
371
+ .select-page-builder {
372
+ margin: -20px 0 0 -5px;
373
+ position: absolute;
374
+ }
375
+ .select-page-builder .note {
376
+ margin-left: 1.5em;
377
+ }
378
+
379
+ @keyframes bounce {
380
+ 0%,
381
+ 100%,
382
+ 20%,
383
+ 50%,
384
+ 80% {
385
+ -webkit-transform: translateY(-0px) rotate(90deg);
386
+ -moz-transform: translateY(-0px) rotate(90deg);
387
+ -ms-transform: translateY(-0px) rotate(90deg);
388
+ transform: translateY(-0px) rotate(90deg);
389
+ }
390
+ 40% {
391
+ -webkit-transform: translateY(-2px) rotate(90deg);
392
+ -moz-transform: translateY(-2px) rotate(90deg);
393
+ -ms-transform: translateY(-2px) rotate(90deg);
394
+ transform: translateY(-2px) rotate(90deg);
395
+ }
396
+ 60% {
397
+ -webkit-transform: translateY(-1px) rotate(90deg);
398
+ -moz-transform: translateY(-1px) rotate(90deg);
399
+ -ms-transform: translateY(-1px) rotate(90deg);
400
+ transform: translateY(-1px) rotate(90deg);
401
+ }
402
+ }
403
+
404
+ /**
405
+ * Processing Animation
406
+ */
407
+ .astra-demo-import.disabled {
408
+ pointer-events: none;
409
+ }
410
+ .astra-demo-import.button.updating-message:before,
411
+ .astra-demo-import.button.installing:before {
412
+ -webkit-animation: cssAnimation .72s ease infinite;
413
+ -moz-animation: cssAnimation .72s ease infinite;
414
+ -o-animation: cssAnimation .72s ease infinite;
415
+ -ms-animation: cssAnimation .72s ease infinite;
416
+ animation: cssAnimation .72s ease infinite;
417
+ }
418
+
419
+ @-webkit-keyframes cssAnimation {
420
+ from {
421
+ -webkit-transform: rotate(0);
422
+ -moz-transform: rotate(0);
423
+ -o-transform: rotate(0);
424
+ -ms-transform: rotate(0);
425
+ transform: rotate(0);
426
+ }
427
+ to {
428
+ -webkit-transform: rotate(360deg);
429
+ -moz-transform: rotate(360deg);
430
+ -o-transform: rotate(360deg);
431
+ -ms-transform: rotate(360deg);
432
+ transform: rotate(360deg);
433
+ }
434
+ }
435
+ @-moz-keyframes cssAnimation {
436
+ from {
437
+ -webkit-transform: rotate(0);
438
+ -moz-transform: rotate(0);
439
+ -o-transform: rotate(0);
440
+ -ms-transform: rotate(0);
441
+ transform: rotate(0);
442
+ }
443
+ to {
444
+ -webkit-transform: rotate(360deg);
445
+ -moz-transform: rotate(360deg);
446
+ -o-transform: rotate(360deg);
447
+ -ms-transform: rotate(360deg);
448
+ transform: rotate(360deg);
449
+ }
450
+ }
451
+ @-o-keyframes cssAnimation {
452
+ from {
453
+ -webkit-transform: rotate(0);
454
+ -moz-transform: rotate(0);
455
+ -o-transform: rotate(0);
456
+ -ms-transform: rotate(0);
457
+ transform: rotate(0);
458
+ }
459
+ to {
460
+ -webkit-transform: rotate(360deg);
461
+ -moz-transform: rotate(360deg);
462
+ -o-transform: rotate(360deg);
463
+ -ms-transform: rotate(360deg);
464
+ transform: rotate(360deg);
465
+ }
466
+ }
467
+
468
+ #astra-sites-filters {
469
+ display: inline-block;
470
+ width: 100%;
471
+ }
472
+
473
+ .astra-site-down {
474
+ padding: 1em 2em;
475
+ margin-top: 1em;
476
  }
inc/assets/js/admin-page.js CHANGED
@@ -1,1398 +1,1439 @@
1
- /**
2
- * AJAX Request Queue
3
- *
4
- * - add()
5
- * - remove()
6
- * - run()
7
- * - stop()
8
- *
9
- * @since 1.0.0
10
- */
11
- var AstraSitesAjaxQueue = (function() {
12
-
13
- var requests = [];
14
-
15
- return {
16
-
17
- /**
18
- * Add AJAX request
19
- *
20
- * @since 1.0.0
21
- */
22
- add: function(opt) {
23
- requests.push(opt);
24
- },
25
-
26
- /**
27
- * Remove AJAX request
28
- *
29
- * @since 1.0.0
30
- */
31
- remove: function(opt) {
32
- if( jQuery.inArray(opt, requests) > -1 )
33
- requests.splice($.inArray(opt, requests), 1);
34
- },
35
-
36
- /**
37
- * Run / Process AJAX request
38
- *
39
- * @since 1.0.0
40
- */
41
- run: function() {
42
- var self = this,
43
- oriSuc;
44
-
45
- if( requests.length ) {
46
- oriSuc = requests[0].complete;
47
-
48
- requests[0].complete = function() {
49
- if( typeof(oriSuc) === 'function' ) oriSuc();
50
- requests.shift();
51
- self.run.apply(self, []);
52
- };
53
-
54
- jQuery.ajax(requests[0]);
55
-
56
- } else {
57
-
58
- self.tid = setTimeout(function() {
59
- self.run.apply(self, []);
60
- }, 1000);
61
- }
62
- },
63
-
64
- /**
65
- * Stop AJAX request
66
- *
67
- * @since 1.0.0
68
- */
69
- stop: function() {
70
-
71
- requests = [];
72
- clearTimeout(this.tid);
73
- }
74
- };
75
-
76
- }());
77
-
78
- (function($){
79
-
80
- var AstraSSEImport = {
81
- complete: {
82
- posts: 0,
83
- media: 0,
84
- users: 0,
85
- comments: 0,
86
- terms: 0,
87
- },
88
-
89
- updateDelta: function (type, delta) {
90
- this.complete[ type ] += delta;
91
-
92
- var self = this;
93
- requestAnimationFrame(function () {
94
- self.render();
95
- });
96
- },
97
- updateProgress: function ( type, complete, total ) {
98
- var text = complete + '/' + total;
99
-
100
- if( 'undefined' !== type && 'undefined' !== text ) {
101
- total = parseInt( total, 10 );
102
- if ( 0 === total || isNaN( total ) ) {
103
- total = 1;
104
- }
105
- var percent = parseInt( complete, 10 ) / total;
106
- var progress = Math.round( percent * 100 ) + '%';
107
- var progress_bar = percent * 100;
108
- }
109
- },
110
- render: function () {
111
- var types = Object.keys( this.complete );
112
- var complete = 0;
113
- var total = 0;
114
-
115
- for (var i = types.length - 1; i >= 0; i--) {
116
- var type = types[i];
117
- this.updateProgress( type, this.complete[ type ], this.data.count[ type ] );
118
-
119
- complete += this.complete[ type ];
120
- total += this.data.count[ type ];
121
- }
122
-
123
- this.updateProgress( 'total', complete, total );
124
- }
125
- };
126
-
127
- AstraSitesAdmin = {
128
-
129
- log_file : '',
130
- customizer_data : '',
131
- wxr_url : '',
132
- options_data : '',
133
- widgets_data : '',
134
-
135
- init: function()
136
- {
137
- this._resetPagedCount();
138
- this._bind();
139
- },
140
-
141
- /**
142
- * Debugging.
143
- *
144
- * @param {mixed} data Mixed data.
145
- */
146
- _log: function( data ) {
147
-
148
- if( astraSitesAdmin.debug ) {
149
-
150
- var date = new Date();
151
- var time = date.toLocaleTimeString();
152
-
153
- if (typeof data == 'object') {
154
- console.log('%c ' + JSON.stringify( data ) + ' ' + time, 'background: #ededed; color: #444');
155
- } else {
156
- console.log('%c ' + data + ' ' + time, 'background: #ededed; color: #444');
157
- }
158
-
159
-
160
- }
161
- },
162
-
163
- /**
164
- * Binds events for the Astra Sites.
165
- *
166
- * @since 1.0.0
167
- * @access private
168
- * @method _bind
169
- */
170
- _bind: function()
171
- {
172
- $( document ).on('click' , '.devices button', AstraSitesAdmin._previewDevice);
173
- $( document ).on('click' , '.theme-browser .theme-screenshot, .theme-browser .more-details, .theme-browser .install-theme-preview', AstraSitesAdmin._preview);
174
- $( document ).on('click' , '.next-theme', AstraSitesAdmin._nextTheme);
175
- $( document ).on('click' , '.previous-theme', AstraSitesAdmin._previousTheme);
176
- $( document ).on('click' , '.collapse-sidebar', AstraSitesAdmin._collapse);
177
- $( document ).on('click' , '.astra-demo-import', AstraSitesAdmin._importDemo);
178
- $( document ).on('click' , '.install-now', AstraSitesAdmin._installNow);
179
- $( document ).on('click' , '.close-full-overlay', AstraSitesAdmin._fullOverlay);
180
- $( document ).on('click' , '.activate-now', AstraSitesAdmin._activateNow);
181
- $( document ).on('wp-plugin-installing' , AstraSitesAdmin._pluginInstalling);
182
- $( document ).on('wp-plugin-install-error' , AstraSitesAdmin._installError);
183
- $( document ).on('wp-plugin-install-success' , AstraSitesAdmin._installSuccess);
184
-
185
- $( document ).on('astra-sites-import-set-site-data-done' , AstraSitesAdmin._importCustomizerSettings );
186
- $( document ).on('astra-sites-import-customizer-settings-done' , AstraSitesAdmin._importPrepareXML );
187
- $( document ).on('astra-sites-import-xml-done' , AstraSitesAdmin._importSiteOptions );
188
- $( document ).on('astra-sites-import-options-done' , AstraSitesAdmin._importWidgets );
189
- $( document ).on('astra-sites-import-widgets-done' , AstraSitesAdmin._importEnd );
190
- },
191
-
192
- /**
193
- * 5. Import Complete.
194
- */
195
- _importEnd: function( event ) {
196
-
197
- $.ajax({
198
- url : astraSitesAdmin.ajaxurl,
199
- type : 'POST',
200
- dataType: 'json',
201
- data : {
202
- action : 'astra-sites-import-end',
203
- },
204
- beforeSend: function() {
205
- $('.button-hero.astra-demo-import').text( astraSitesAdmin.log.importComplete );
206
- }
207
- })
208
- .fail(function( jqXHR ){
209
- AstraSitesAdmin._importFailMessage( jqXHR.status + ' ' + jqXHR.responseText );
210
- AstraSitesAdmin._log( jqXHR.status + ' ' + jqXHR.responseText );
211
- })
212
- .done(function ( data ) {
213
-
214
- // 5. Fail - Import Complete.
215
- if( false === data.success ) {
216
- AstraSitesAdmin._importFailMessage( data.data );
217
- AstraSitesAdmin._log( data.data );
218
- } else {
219
-
220
- $('body').removeClass('importing-site');
221
- $('.previous-theme, .next-theme').removeClass('disabled');
222
-
223
- // 5. Pass - Import Complete.
224
- AstraSitesAdmin._importSuccessMessage();
225
- AstraSitesAdmin._log( astraSitesAdmin.log.success + ' ' + astraSitesAdmin.siteURL );
226
- }
227
- });
228
- },
229
-
230
- /**
231
- * 4. Import Widgets.
232
- */
233
- _importWidgets: function( event ) {
234
-
235
- $.ajax({
236
- url : astraSitesAdmin.ajaxurl,
237
- type : 'POST',
238
- dataType: 'json',
239
- data : {
240
- action : 'astra-sites-import-widgets',
241
- widgets_data : AstraSitesAdmin.widgets_data,
242
- },
243
- beforeSend: function() {
244
- AstraSitesAdmin._log( astraSitesAdmin.log.importWidgets );
245
- $('.button-hero.astra-demo-import').text( astraSitesAdmin.log.importingWidgets );
246
- },
247
- })
248
- .fail(function( jqXHR ){
249
- AstraSitesAdmin._importFailMessage( jqXHR.status + ' ' + jqXHR.responseText );
250
- AstraSitesAdmin._log( jqXHR.status + ' ' + jqXHR.responseText );
251
- })
252
- .done(function ( widgets_data ) {
253
-
254
- // 4. Fail - Import Widgets.
255
- if( false === widgets_data.success ) {
256
- AstraSitesAdmin._importFailMessage( widgets_data.data );
257
- AstraSitesAdmin._log( widgets_data.data );
258
-
259
- } else {
260
-
261
- // 4. Pass - Import Widgets.
262
- AstraSitesAdmin._log( astraSitesAdmin.log.importWidgetsSuccess );
263
- $(document).trigger( 'astra-sites-import-widgets-done' );
264
- }
265
- });
266
- },
267
-
268
- /**
269
- * 3. Import Site Options.
270
- */
271
- _importSiteOptions: function( event ) {
272
-
273
- $.ajax({
274
- url : astraSitesAdmin.ajaxurl,
275
- type : 'POST',
276
- dataType: 'json',
277
- data : {
278
- action : 'astra-sites-import-options',
279
- options_data : AstraSitesAdmin.options_data,
280
- },
281
- beforeSend: function() {
282
- AstraSitesAdmin._log( astraSitesAdmin.log.importOptions );
283
- $('.button-hero.astra-demo-import').text( astraSitesAdmin.log.importingOptions );
284
- },
285
- })
286
- .fail(function( jqXHR ){
287
- AstraSitesAdmin._importFailMessage( jqXHR.status + ' ' + jqXHR.responseText );
288
- AstraSitesAdmin._log( jqXHR.status + ' ' + jqXHR.responseText );
289
- })
290
- .done(function ( options_data ) {
291
-
292
- // 3. Fail - Import Site Options.
293
- if( false === options_data.success ) {
294
- AstraSitesAdmin._log( options_data );
295
- AstraSitesAdmin._importFailMessage( options_data.data );
296
- AstraSitesAdmin._log( options_data.data );
297
-
298
- } else {
299
-
300
- // 3. Pass - Import Site Options.
301
- AstraSitesAdmin._log( astraSitesAdmin.log.importOptionsSuccess );
302
- $(document).trigger( 'astra-sites-import-options-done' );
303
- }
304
- });
305
- },
306
-
307
- /**
308
- * 2. Prepare XML Data.
309
- */
310
- _importPrepareXML: function( event ) {
311
-
312
- $.ajax({
313
- url : astraSitesAdmin.ajaxurl,
314
- type : 'POST',
315
- dataType: 'json',
316
- data : {
317
- action : 'astra-sites-import-prepare-xml',
318
- wxr_url : AstraSitesAdmin.wxr_url,
319
- },
320
- beforeSend: function() {
321
- AstraSitesAdmin._log( astraSitesAdmin.log.importXMLPrepare );
322
- $('.button-hero.astra-demo-import').text( astraSitesAdmin.log.importXMLPreparing );
323
- },
324
- })
325
- .fail(function( jqXHR ){
326
- AstraSitesAdmin._importFailMessage( jqXHR.status + ' ' + jqXHR.responseText );
327
- AstraSitesAdmin._log( jqXHR.status + ' ' + jqXHR.responseText );
328
- })
329
- .done(function ( xml_data ) {
330
-
331
- // 2. Fail - Prepare XML Data.
332
- if( false === xml_data.success ) {
333
- AstraSitesAdmin._log( xml_data );
334
- var error_msg = xml_data.data.error || xml_data.data;
335
- AstraSitesAdmin._importFailMessage( error_msg );
336
- AstraSitesAdmin._log( error_msg );
337
-
338
- } else {
339
-
340
- // 2. Pass - Prepare XML Data.
341
- AstraSitesAdmin._log( astraSitesAdmin.log.importXMLPrepareSuccess );
342
-
343
- // Import XML though Event Source.
344
- AstraSSEImport.data = xml_data.data;
345
- AstraSSEImport.render();
346
-
347
- AstraSitesAdmin._log( astraSitesAdmin.log.importXML );
348
- $('.button-hero.astra-demo-import').text( astraSitesAdmin.log.importingXML );
349
-
350
- var evtSource = new EventSource( AstraSSEImport.data.url );
351
- evtSource.onmessage = function ( message ) {
352
- var data = JSON.parse( message.data );
353
- switch ( data.action ) {
354
- case 'updateDelta':
355
- AstraSSEImport.updateDelta( data.type, data.delta );
356
- break;
357
-
358
- case 'complete':
359
- evtSource.close();
360
-
361
- // 2. Pass - Import XML though "Source Event".
362
- AstraSitesAdmin._log( astraSitesAdmin.log.importXMLSuccess );
363
- AstraSitesAdmin._log( '----- SSE - XML import Complete -----' );
364
-
365
- $(document).trigger( 'astra-sites-import-xml-done' );
366
-
367
- break;
368
- }
369
- };
370
- evtSource.addEventListener( 'log', function ( message ) {
371
- var data = JSON.parse( message.data );
372
- AstraSitesAdmin._log( data.level + ' ' + data.message );
373
- });
374
- }
375
- });
376
- },
377
-
378
- /**
379
- * 1. Import Customizer Options.
380
- */
381
- _importCustomizerSettings: function( event ) {
382
-
383
- $.ajax({
384
- url : astraSitesAdmin.ajaxurl,
385
- type : 'POST',
386
- dataType: 'json',
387
- data : {
388
- action : 'astra-sites-import-customizer-settings',
389
- customizer_data : AstraSitesAdmin.customizer_data,
390
- },
391
- beforeSend: function() {
392
- AstraSitesAdmin._log( astraSitesAdmin.log.importCustomizer );
393
- $('.button-hero.astra-demo-import').text( astraSitesAdmin.log.importingCustomizer );
394
- },
395
- })
396
- .fail(function( jqXHR ){
397
- AstraSitesAdmin._importFailMessage( jqXHR.status + ' ' + jqXHR.responseText );
398
- AstraSitesAdmin._log( jqXHR.status + ' ' + jqXHR.responseText );
399
- })
400
- .done(function ( customizer_data ) {
401
-
402
- // 1. Fail - Import Customizer Options.
403
- if( false === customizer_data.success ) {
404
- AstraSitesAdmin._importFailMessage( customizer_data.data );
405
- AstraSitesAdmin._log( customizer_data.data );
406
- } else {
407
-
408
- // 1. Pass - Import Customizer Options.
409
- AstraSitesAdmin._log( astraSitesAdmin.log.importCustomizerSuccess );
410
-
411
- $(document).trigger( 'astra-sites-import-customizer-settings-done' );
412
- }
413
- });
414
- },
415
-
416
- /**
417
- * Import Success Button.
418
- *
419
- * @param {string} data Error message.
420
- */
421
- _importSuccessMessage: function() {
422
-
423
- $('.astra-demo-import').removeClass('updating-message installing')
424
- .removeAttr('data-import')
425
- .addClass('view-site')
426
- .removeClass('astra-demo-import')
427
- .text( astraSitesAdmin.strings.viewSite )
428
- .attr('target', '_blank')
429
- .append('<i class="dashicons dashicons-external"></i>')
430
- .attr('href', astraSitesAdmin.siteURL );
431
- },
432
-
433
- /**
434
- * Preview Device
435
- */
436
- _previewDevice: function( event ) {
437
- var device = $( event.currentTarget ).data( 'device' );
438
-
439
- $('.theme-install-overlay')
440
- .removeClass( 'preview-desktop preview-tablet preview-mobile' )
441
- .addClass( 'preview-' + device )
442
- .data( 'current-preview-device', device );
443
-
444
- AstraSitesAdmin._tooglePreviewDeviceButtons( device );
445
- },
446
-
447
- /**
448
- * Toggle Preview Buttons
449
- */
450
- _tooglePreviewDeviceButtons: function( newDevice ) {
451
- var $devices = $( '.wp-full-overlay-footer .devices' );
452
-
453
- $devices.find( 'button' )
454
- .removeClass( 'active' )
455
- .attr( 'aria-pressed', false );
456
-
457
- $devices.find( 'button.preview-' + newDevice )
458
- .addClass( 'active' )
459
- .attr( 'aria-pressed', true );
460
- },
461
-
462
- /**
463
- * Import Error Button.
464
- *
465
- * @param {string} data Error message.
466
- */
467
- _importFailMessage: function( message, from ) {
468
-
469
- $('.astra-demo-import')
470
- .addClass('go-pro button-primary')
471
- .removeClass('updating-message installing')
472
- .removeAttr('data-import')
473
- .attr('target', '_blank')
474
- .append('<i class="dashicons dashicons-external"></i>')
475
- .removeClass('astra-demo-import');
476
-
477
- // Add the doc link due to import log file not generated.
478
- if( 'undefined' === from ) {
479
-
480
- $('.wp-full-overlay-header .go-pro').text( astraSitesAdmin.strings.importFailedBtnSmall );
481
- $('.wp-full-overlay-footer .go-pro').text( astraSitesAdmin.strings.importFailedBtnLarge );
482
- $('.go-pro').attr('href', astraSitesAdmin.log.serverConfiguration );
483
-
484
- // Add the import log file link.
485
- } else {
486
-
487
- $('.wp-full-overlay-header .go-pro').text( astraSitesAdmin.strings.importFailBtn );
488
- $('.wp-full-overlay-footer .go-pro').text( astraSitesAdmin.strings.importFailBtnLarge )
489
-
490
- // Add the import log file link.
491
- if( 'undefined' !== AstraSitesAdmin.log_file_url ) {
492
- $('.go-pro').attr('href', AstraSitesAdmin.log_file_url );
493
- } else {
494
- $('.go-pro').attr('href', astraSitesAdmin.log.serverConfiguration );
495
- }
496
- }
497
-
498
- var output = '<div class="astra-api-error notice notice-error notice-alt is-dismissible">';
499
- output += ' <p>'+message+'</p>';
500
- output += ' <button type="button" class="notice-dismiss">';
501
- output += ' <span class="screen-reader-text">'+commonL10n.dismiss+'</span>';
502
- output += ' </button>';
503
- output += '</div>';
504
-
505
- // Fail Notice.
506
- $('.install-theme-info').append( output );
507
-
508
-
509
- // !important to add trigger.
510
- // Which reinitialize the dismiss error message events.
511
- $(document).trigger('wp-updates-notice-added');
512
- },
513
-
514
-
515
- /**
516
- * Install Now
517
- */
518
- _installNow: function(event)
519
- {
520
- event.preventDefault();
521
-
522
- var $button = jQuery( event.target ),
523
- $document = jQuery(document);
524
-
525
- if ( $button.hasClass( 'updating-message' ) || $button.hasClass( 'button-disabled' ) ) {
526
- return;
527
- }
528
-
529
- if ( wp.updates.shouldRequestFilesystemCredentials && ! wp.updates.ajaxLocked ) {
530
- wp.updates.requestFilesystemCredentials( event );
531
-
532
- $document.on( 'credential-modal-cancel', function() {
533
- var $message = $( '.install-now.updating-message' );
534
-
535
- $message
536
- .removeClass( 'updating-message' )
537
- .text( wp.updates.l10n.installNow );
538
-
539
- wp.a11y.speak( wp.updates.l10n.updateCancel, 'polite' );
540
- } );
541
- }
542
-
543
- AstraSitesAdmin._log( astraSitesAdmin.log.installingPlugin + ' ' + $button.data( 'slug' ) );
544
-
545
- wp.updates.installPlugin( {
546
- slug: $button.data( 'slug' )
547
- } );
548
- },
549
-
550
- /**
551
- * Install Success
552
- */
553
- _installSuccess: function( event, response ) {
554
-
555
- event.preventDefault();
556
-
557
- AstraSitesAdmin._log( astraSitesAdmin.log.installed + ' ' + response.slug );
558
-
559
- var $message = jQuery( '.plugin-card-' + response.slug ).find( '.button' );
560
- var $siteOptions = jQuery( '.wp-full-overlay-header').find('.astra-site-options').val();
561
- var $enabledExtensions = jQuery( '.wp-full-overlay-header').find('.astra-enabled-extensions').val();
562
-
563
- // Transform the 'Install' button into an 'Activate' button.
564
- var $init = $message.data('init');
565
-
566
- $message.removeClass( 'install-now installed button-disabled updated-message' )
567
- .addClass('updating-message')
568
- .html( astraSitesAdmin.strings.btnActivating );
569
-
570
- // Reset not installed plugins list.
571
- var pluginsList = astraSitesAdmin.requiredPlugins.notinstalled;
572
- astraSitesAdmin.requiredPlugins.notinstalled = AstraSitesAdmin._removePluginFromQueue( response.slug, pluginsList );
573
-
574
- // WordPress adds "Activate" button after waiting for 1000ms. So we will run our activation after that.
575
- setTimeout( function() {
576
-
577
- $.ajax({
578
- url: astraSitesAdmin.ajaxurl,
579
- type: 'POST',
580
- data: {
581
- 'action' : 'astra-required-plugin-activate',
582
- 'init' : $init,
583
- 'options' : $siteOptions,
584
- 'enabledExtensions' : $enabledExtensions,
585
- },
586
- })
587
- .done(function (result) {
588
-
589
- if( result.success ) {
590
-
591
- var pluginsList = astraSitesAdmin.requiredPlugins.inactive;
592
-
593
- // Reset not installed plugins list.
594
- astraSitesAdmin.requiredPlugins.inactive = AstraSitesAdmin._removePluginFromQueue( response.slug, pluginsList );
595
-
596
- $message.removeClass( 'button-primary install-now activate-now updating-message' )
597
- .attr('disabled', 'disabled')
598
- .addClass('disabled')
599
- .text( astraSitesAdmin.strings.btnActive );
600
-
601
- // Enable Demo Import Button
602
- AstraSitesAdmin._enable_demo_import_button();
603
-
604
- } else {
605
-
606
- $message.removeClass( 'updating-message' );
607
-
608
- }
609
-
610
- });
611
-
612
- }, 1200 );
613
-
614
- },
615
-
616
- /**
617
- * Plugin Installation Error.
618
- */
619
- _installError: function( event, response ) {
620
-
621
- var $card = jQuery( '.plugin-card-' + response.slug );
622
-
623
- AstraSitesAdmin._log( response.errorMessage + ' ' + response.slug );
624
-
625
- $card
626
- .removeClass( 'button-primary' )
627
- .addClass( 'disabled' )
628
- .html( wp.updates.l10n.installFailedShort );
629
-
630
- AstraSitesAdmin._importFailMessage( response.errorMessage );
631
- },
632
-
633
- /**
634
- * Installing Plugin
635
- */
636
- _pluginInstalling: function(event, args) {
637
- event.preventDefault();
638
-
639
- var $card = jQuery( '.plugin-card-' + args.slug );
640
- var $button = $card.find( '.button' );
641
-
642
- AstraSitesAdmin._log( astraSitesAdmin.log.installingPlugin + ' ' + args.slug );
643
-
644
- $card.addClass('updating-message');
645
- $button.addClass('already-started');
646
-
647
- },
648
-
649
- /**
650
- * Render Demo Preview
651
- */
652
- _activateNow: function( eventn ) {
653
-
654
- event.preventDefault();
655
-
656
- var $button = jQuery( event.target ),
657
- $init = $button.data( 'init' ),
658
- $slug = $button.data( 'slug' );
659
-
660
- if ( $button.hasClass( 'updating-message' ) || $button.hasClass( 'button-disabled' ) ) {
661
- return;
662
- }
663
-
664
- AstraSitesAdmin._log( astraSitesAdmin.log.activating + ' ' + $slug );
665
-
666
- $button.addClass('updating-message button-primary')
667
- .html( astraSitesAdmin.strings.btnActivating );
668
-
669
- var $siteOptions = jQuery( '.wp-full-overlay-header').find('.astra-site-options').val();
670
- var $enabledExtensions = jQuery( '.wp-full-overlay-header').find('.astra-enabled-extensions').val();
671
-
672
- $.ajax({
673
- url: astraSitesAdmin.ajaxurl,
674
- type: 'POST',
675
- data: {
676
- 'action' : 'astra-required-plugin-activate',
677
- 'init' : $init,
678
- 'options' : $siteOptions,
679
- 'enabledExtensions' : $enabledExtensions,
680
- },
681
- })
682
- .done(function (result) {
683
-
684
- if( result.success ) {
685
-
686
- AstraSitesAdmin._log( astraSitesAdmin.log.activated + ' ' + $slug );
687
-
688
- var pluginsList = astraSitesAdmin.requiredPlugins.inactive;
689
-
690
- // Reset not installed plugins list.
691
- astraSitesAdmin.requiredPlugins.inactive = AstraSitesAdmin._removePluginFromQueue( $slug, pluginsList );
692
-
693
- $button.removeClass( 'button-primary install-now activate-now updating-message' )
694
- .attr('disabled', 'disabled')
695
- .addClass('disabled')
696
- .text( astraSitesAdmin.strings.btnActive );
697
-
698
- // Enable Demo Import Button
699
- AstraSitesAdmin._enable_demo_import_button();
700
-
701
- }
702
-
703
- })
704
- .fail(function () {
705
- });
706
-
707
- },
708
-
709
- /**
710
- * Full Overlay
711
- */
712
- _fullOverlay: function (event) {
713
- event.preventDefault();
714
-
715
- // Import process is started?
716
- // And Closing the window? Then showing the warning confirm message.
717
- if( $('body').hasClass('importing-site') && ! confirm( astraSitesAdmin.strings.warningBeforeCloseWindow ) ) {
718
- return;
719
- }
720
-
721
- $('body').removeClass('importing-site');
722
- $('.previous-theme, .next-theme').removeClass('disabled');
723
- $('.theme-install-overlay').css('display', 'none');
724
- $('.theme-install-overlay').remove();
725
- $('.theme-preview-on').removeClass('theme-preview-on');
726
- $('html').removeClass('astra-site-preview-on');
727
- },
728
-
729
- /**
730
- * Bulk Plugin Active & Install
731
- */
732
- _bulkPluginInstallActivate: function()
733
- {
734
- if( 0 === astraSitesAdmin.requiredPlugins.length ) {
735
- return;
736
- }
737
-
738
- jQuery('.required-plugins')
739
- .find('.install-now')
740
- .addClass( 'updating-message' )
741
- .removeClass( 'install-now' )
742
- .text( wp.updates.l10n.installing );
743
-
744
- jQuery('.required-plugins')
745
- .find('.activate-now')
746
- .addClass('updating-message')
747
- .removeClass( 'activate-now' )
748
- .html( astraSitesAdmin.strings.btnActivating );
749
-
750
- var not_installed = astraSitesAdmin.requiredPlugins.notinstalled || '';
751
- var activate_plugins = astraSitesAdmin.requiredPlugins.inactive || '';
752
-
753
- // First Install Bulk.
754
- if( not_installed.length > 0 ) {
755
- AstraSitesAdmin._installAllPlugins( not_installed );
756
- }
757
-
758
- // Second Activate Bulk.
759
- if( activate_plugins.length > 0 ) {
760
- AstraSitesAdmin._activateAllPlugins( activate_plugins );
761
- }
762
-
763
- },
764
-
765
- /**
766
- * Activate All Plugins.
767
- */
768
- _activateAllPlugins: function( activate_plugins ) {
769
-
770
- // Activate ALl Plugins.
771
- AstraSitesAjaxQueue.stop();
772
- AstraSitesAjaxQueue.run();
773
-
774
- AstraSitesAdmin._log( astraSitesAdmin.log.bulkActivation );
775
-
776
- $.each( activate_plugins, function(index, single_plugin) {
777
-
778
- var $card = jQuery( '.plugin-card-' + single_plugin.slug ),
779
- $button = $card.find('.button'),
780
- $siteOptions = jQuery( '.wp-full-overlay-header').find('.astra-site-options').val(),
781
- $enabledExtensions = jQuery( '.wp-full-overlay-header').find('.astra-enabled-extensions').val();
782
-
783
- $button.addClass('updating-message');
784
-
785
- AstraSitesAjaxQueue.add({
786
- url: astraSitesAdmin.ajaxurl,
787
- type: 'POST',
788
- data: {
789
- 'action' : 'astra-required-plugin-activate',
790
- 'init' : single_plugin.init,
791
- 'options' : $siteOptions,
792
- 'enabledExtensions' : $enabledExtensions,
793
- },
794
- success: function( result ){
795
-
796
- if( result.success ) {
797
-
798
- AstraSitesAdmin._log( astraSitesAdmin.log.activate + ' ' + single_plugin.slug );
799
-
800
- var $card = jQuery( '.plugin-card-' + single_plugin.slug );
801
- var $button = $card.find( '.button' );
802
- if( ! $button.hasClass('already-started') ) {
803
- var pluginsList = astraSitesAdmin.requiredPlugins.inactive;
804
-
805
- // Reset not installed plugins list.
806
- astraSitesAdmin.requiredPlugins.inactive = AstraSitesAdmin._removePluginFromQueue( single_plugin.slug, pluginsList );
807
- }
808
-
809
- $button.removeClass( 'button-primary install-now activate-now updating-message' )
810
- .attr('disabled', 'disabled')
811
- .addClass('disabled')
812
- .text( astraSitesAdmin.strings.btnActive );
813
-
814
- // Enable Demo Import Button
815
- AstraSitesAdmin._enable_demo_import_button();
816
- } else {
817
- AstraSitesAdmin._log( astraSitesAdmin.log.activationError + ' - ' + single_plugin.slug );
818
- }
819
- }
820
- });
821
- });
822
- },
823
-
824
- /**
825
- * Install All Plugins.
826
- */
827
- _installAllPlugins: function( not_installed ) {
828
-
829
- AstraSitesAdmin._log( astraSitesAdmin.log.bulkInstall );
830
-
831
- $.each( not_installed, function(index, single_plugin) {
832
-
833
- var $card = jQuery( '.plugin-card-' + single_plugin.slug ),
834
- $button = $card.find('.button');
835
-
836
- if( ! $button.hasClass('already-started') ) {
837
-
838
- // Add each plugin activate request in Ajax queue.
839
- // @see wp-admin/js/updates.js
840
- wp.updates.queue.push( {
841
- action: 'install-plugin', // Required action.
842
- data: {
843
- slug: single_plugin.slug
844
- }
845
- } );
846
- }
847
- });
848
-
849
- // Required to set queue.
850
- wp.updates.queueChecker();
851
- },
852
-
853
- /**
854
- * Fires when a nav item is clicked.
855
- *
856
- * @since 1.0
857
- * @access private
858
- * @method _importDemo
859
- */
860
- _importDemo: function()
861
- {
862
- var $this = jQuery(this),
863
- $theme = $this.closest('.astra-sites-preview').find('.wp-full-overlay-header'),
864
- apiURL = $theme.data('demo-api') || '',
865
- plugins = $theme.data('required-plugins');
866
-
867
- var disabled = $this.attr('data-import');
868
-
869
- if ( typeof disabled !== 'undefined' && disabled === 'disabled' || $this.hasClass('disabled') ) {
870
-
871
- $('.astra-demo-import').addClass('updating-message installing')
872
- .text( wp.updates.l10n.installing );
873
-
874
- /**
875
- * Process Bulk Plugin Install & Activate
876
- */
877
- AstraSitesAdmin._bulkPluginInstallActivate();
878
-
879
- return;
880
- }
881
-
882
- // Proceed?
883
- if( ! confirm( astraSitesAdmin.strings.importWarning ) ) {
884
- return;
885
- }
886
-
887
- $('body').addClass('importing-site');
888
- $('.previous-theme, .next-theme').addClass('disabled');
889
-
890
- // Remove all notices before import start.
891
- $('.install-theme-info > .notice').remove();
892
-
893
- $('.astra-demo-import').attr('data-import', 'disabled')
894
- .addClass('updating-message installing')
895
- .text( astraSitesAdmin.strings.importingDemo );
896
-
897
- $this.closest('.theme').focus();
898
-
899
- var $theme = $this.closest('.astra-sites-preview').find('.wp-full-overlay-header');
900
-
901
- var apiURL = $theme.data('demo-api') || '';
902
-
903
- // Site Import by API URL.
904
- if( apiURL ) {
905
- AstraSitesAdmin._importSite( apiURL );
906
- }
907
-
908
- },
909
-
910
- /**
911
- * Start Import Process by API URL.
912
- *
913
- * @param {string} apiURL Site API URL.
914
- */
915
- _importSite: function( apiURL ) {
916
-
917
- AstraSitesAdmin._log( astraSitesAdmin.log.api + ' : ' + apiURL );
918
- AstraSitesAdmin._log( astraSitesAdmin.log.importing );
919
-
920
- $('.button-hero.astra-demo-import').text( astraSitesAdmin.log.gettingData );
921
-
922
- // 1. Request Site Import
923
- $.ajax({
924
- url : astraSitesAdmin.ajaxurl,
925
- type : 'POST',
926
- dataType: 'json',
927
- data : {
928
- 'action' : 'astra-sites-import-set-site-data',
929
- 'api_url' : apiURL,
930
- },
931
- })
932
- .fail(function( jqXHR ){
933
- AstraSitesAdmin._importFailMessage( jqXHR.status + ' ' + jqXHR.responseText );
934
- AstraSitesAdmin._log( jqXHR.status + ' ' + jqXHR.responseText );
935
- })
936
- .done(function ( demo_data ) {
937
-
938
- // 1. Fail - Request Site Import
939
- if( false === demo_data.success ) {
940
-
941
- AstraSitesAdmin._importFailMessage( demo_data.data );
942
-
943
- } else {
944
-
945
- // Set log file URL.
946
- if( 'log_file' in demo_data.data ){
947
- AstraSitesAdmin.log_file_url = decodeURIComponent( demo_data.data.log_file ) || '';
948
- }
949
-
950
- // 1. Pass - Request Site Import
951
- AstraSitesAdmin._log( astraSitesAdmin.log.processingRequest );
952
-
953
- AstraSitesAdmin.customizer_data = JSON.stringify( demo_data.data['astra-site-customizer-data'] ) || '';
954
- AstraSitesAdmin.wxr_url = encodeURI( demo_data.data['astra-site-wxr-path'] ) || '';
955
- AstraSitesAdmin.options_data = JSON.stringify( demo_data.data['astra-site-options-data'] ) || '';
956
- AstraSitesAdmin.widgets_data = JSON.stringify( demo_data.data['astra-site-widgets-data'] ) || '';
957
-
958
- $(document).trigger( 'astra-sites-import-set-site-data-done' );
959
- }
960
-
961
- });
962
-
963
- },
964
-
965
- /**
966
- * Collapse Sidebar.
967
- */
968
- _collapse: function() {
969
- event.preventDefault();
970
-
971
- overlay = jQuery('.wp-full-overlay');
972
-
973
- if (overlay.hasClass('expanded')) {
974
- overlay.removeClass('expanded');
975
- overlay.addClass('collapsed');
976
- return;
977
- }
978
-
979
- if (overlay.hasClass('collapsed')) {
980
- overlay.removeClass('collapsed');
981
- overlay.addClass('expanded');
982
- return;
983
- }
984
- },
985
-
986
- /**
987
- * Previous Theme.
988
- */
989
- _previousTheme: function (event) {
990
- event.preventDefault();
991
-
992
- currentDemo = jQuery('.theme-preview-on');
993
- currentDemo.removeClass('theme-preview-on');
994
- prevDemo = currentDemo.prev('.theme');
995
- prevDemo.addClass('theme-preview-on');
996
-
997
- AstraSitesAdmin._renderDemoPreview(prevDemo);
998
- },
999
-
1000
- /**
1001
- * Next Theme.
1002
- */
1003
- _nextTheme: function (event) {
1004
- event.preventDefault();
1005
- currentDemo = jQuery('.theme-preview-on')
1006
- currentDemo.removeClass('theme-preview-on');
1007
- nextDemo = currentDemo.next('.theme');
1008
- nextDemo.addClass('theme-preview-on');
1009
-
1010
- AstraSitesAdmin._renderDemoPreview( nextDemo );
1011
- },
1012
-
1013
- /**
1014
- * Individual Site Preview
1015
- *
1016
- * On click on image, more link & preview button.
1017
- */
1018
- _preview: function( event ) {
1019
-
1020
- event.preventDefault();
1021
-
1022
- var self = jQuery(this).parents('.theme');
1023
- self.addClass('theme-preview-on');
1024
-
1025
- jQuery('html').addClass('astra-site-preview-on');
1026
-
1027
- AstraSitesAdmin._renderDemoPreview( self );
1028
- },
1029
-
1030
- /**
1031
- * Check Next Previous Buttons.
1032
- */
1033
- _checkNextPrevButtons: function() {
1034
- currentDemo = jQuery('.theme-preview-on');
1035
- nextDemo = currentDemo.nextAll('.theme').length;
1036
- prevDemo = currentDemo.prevAll('.theme').length;
1037
-
1038
- if (nextDemo == 0) {
1039
- jQuery('.next-theme').addClass('disabled');
1040
- } else if (nextDemo != 0) {
1041
- jQuery('.next-theme').removeClass('disabled');
1042
- }
1043
-
1044
- if (prevDemo == 0) {
1045
- jQuery('.previous-theme').addClass('disabled');
1046
- } else if (prevDemo != 0) {
1047
- jQuery('.previous-theme').removeClass('disabled');
1048
- }
1049
-
1050
- return;
1051
- },
1052
-
1053
- /**
1054
- * Render Demo Preview
1055
- */
1056
- _renderDemoPreview: function(anchor) {
1057
-
1058
- var demoId = anchor.data('id') || '',
1059
- apiURL = anchor.data('demo-api') || '',
1060
- demoType = anchor.data('demo-type') || '',
1061
- demoURL = anchor.data('demo-url') || '',
1062
- screenshot = anchor.data('screenshot') || '',
1063
- demo_name = anchor.data('demo-name') || '',
1064
- demo_slug = anchor.data('demo-slug') || '',
1065
- content = anchor.data('content') || '',
1066
- requiredPlugins = anchor.data('required-plugins') || '',
1067
- astraSiteOptions = anchor.find('.astra-site-options').val() || '';
1068
- astraEnabledExtensions = anchor.find('.astra-enabled-extensions').val() || '';
1069
-
1070
- AstraSitesAdmin._log( astraSitesAdmin.log.preview + ' "' + demo_name + '" URL : ' + demoURL );
1071
-
1072
- var template = wp.template('astra-site-preview');
1073
-
1074
- templateData = [{
1075
- id : demoId,
1076
- astra_demo_type : demoType,
1077
- astra_demo_url : demoURL,
1078
- demo_api : apiURL,
1079
- screenshot : screenshot,
1080
- demo_name : demo_name,
1081
- slug : demo_slug,
1082
- content : content,
1083
- required_plugins : JSON.stringify(requiredPlugins),
1084
- astra_site_options : astraSiteOptions,
1085
- astra_enabled_extensions : astraEnabledExtensions,
1086
- }];
1087
-
1088
- // delete any earlier fullscreen preview before we render new one.
1089
- jQuery('.theme-install-overlay').remove();
1090
-
1091
- jQuery('#astra-sites-menu-page').append(template(templateData[0]));
1092
- jQuery('.theme-install-overlay').css('display', 'block');
1093
- AstraSitesAdmin._checkNextPrevButtons();
1094
-
1095
- var desc = jQuery('.theme-details');
1096
- var descHeight = parseInt( desc.outerHeight() );
1097
- var descBtn = jQuery('.theme-details-read-more');
1098
-
1099
- if( $.isArray( requiredPlugins ) ) {
1100
-
1101
- if( descHeight >= 55 ) {
1102
-
1103
- // Show button.
1104
- descBtn.css( 'display', 'inline-block' );
1105
-
1106
- // Set height upto 3 line.
1107
- desc.css( 'height', 57 );
1108
-
1109
- // Button Click.
1110
- descBtn.click(function(event) {
1111
-
1112
- if( descBtn.hasClass('open') ) {
1113
- desc.animate({ height: 57 },
1114
- 300, function() {
1115
- descBtn.removeClass('open');
1116
- descBtn.html( astraSitesAdmin.strings.DescExpand );
1117
- });
1118
- } else {
1119
- desc.animate({ height: descHeight },
1120
- 300, function() {
1121
- descBtn.addClass('open');
1122
- descBtn.html( astraSitesAdmin.strings.DescCollapse );
1123
- });
1124
- }
1125
-
1126
- });
1127
- }
1128
-
1129
- // or
1130
- var $pluginsFilter = jQuery( '#plugin-filter' ),
1131
- data = {
1132
- action : 'astra-required-plugins',
1133
- _ajax_nonce : astraSitesAdmin._ajax_nonce,
1134
- required_plugins : requiredPlugins
1135
- };
1136
-
1137
- // Add disabled class from import button.
1138
- $('.astra-demo-import')
1139
- .addClass('disabled not-click-able')
1140
- .removeAttr('data-import');
1141
-
1142
- $('.required-plugins').addClass('loading').html('<span class="spinner is-active"></span>');
1143
-
1144
- // Required Required.
1145
- $.ajax({
1146
- url : astraSitesAdmin.ajaxurl,
1147
- type : 'POST',
1148
- data : data,
1149
- })
1150
- .fail(function( jqXHR ){
1151
-
1152
- // Remove loader.
1153
- jQuery('.required-plugins').removeClass('loading').html('');
1154
-
1155
- AstraSitesAdmin._importFailMessage( jqXHR.status + ' ' + jqXHR.responseText, 'plugins' );
1156
- AstraSitesAdmin._log( jqXHR.status + ' ' + jqXHR.responseText );
1157
- })
1158
- .done(function ( response ) {
1159
-
1160
- // Release disabled class from import button.
1161
- $('.astra-demo-import')
1162
- .removeClass('disabled not-click-able')
1163
- .attr('data-import', 'disabled');
1164
-
1165
- // Remove loader.
1166
- $('.required-plugins').removeClass('loading').html('');
1167
-
1168
- /**
1169
- * Count remaining plugins.
1170
- * @type number
1171
- */
1172
- var remaining_plugins = 0;
1173
-
1174
- /**
1175
- * Not Installed
1176
- *
1177
- * List of not installed required plugins.
1178
- */
1179
- if ( typeof response.data.notinstalled !== 'undefined' ) {
1180
-
1181
- // Add not have installed plugins count.
1182
- remaining_plugins += parseInt( response.data.notinstalled.length );
1183
-
1184
- jQuery( response.data.notinstalled ).each(function( index, plugin ) {
1185
-
1186
- var output = '<div class="plugin-card ';
1187
- output += ' plugin-card-'+plugin.slug+'"';
1188
- output += ' data-slug="'+plugin.slug+'"';
1189
- output += ' data-init="'+plugin.init+'">';
1190
- output += ' <span class="title">'+plugin.name+'</span>';
1191
- output += ' <button class="button install-now"';
1192
- output += ' data-init="' + plugin.init + '"';
1193
- output += ' data-slug="' + plugin.slug + '"';
1194
- output += ' data-name="' + plugin.name + '">';
1195
- output += wp.updates.l10n.installNow;
1196
- output += ' </button>';
1197
- // output += ' <span class="dashicons-no dashicons"></span>';
1198
- output += '</div>';
1199
-
1200
- jQuery('.required-plugins').append(output);
1201
-
1202
- });
1203
- }
1204
-
1205
- /**
1206
- * Inactive
1207
- *
1208
- * List of not inactive required plugins.
1209
- */
1210
- if ( typeof response.data.inactive !== 'undefined' ) {
1211
-
1212
- // Add inactive plugins count.
1213
- remaining_plugins += parseInt( response.data.inactive.length );
1214
-
1215
- jQuery( response.data.inactive ).each(function( index, plugin ) {
1216
-
1217
- var output = '<div class="plugin-card ';
1218
- output += ' plugin-card-'+plugin.slug+'"';
1219
- output += ' data-slug="'+plugin.slug+'"';
1220
- output += ' data-init="'+plugin.init+'">';
1221
- output += ' <span class="title">'+plugin.name+'</span>';
1222
- output += ' <button class="button activate-now button-primary"';
1223
- output += ' data-init="' + plugin.init + '"';
1224
- output += ' data-slug="' + plugin.slug + '"';
1225
- output += ' data-name="' + plugin.name + '">';
1226
- output += wp.updates.l10n.activatePlugin;
1227
- output += ' </button>';
1228
- // output += ' <span class="dashicons-no dashicons"></span>';
1229
- output += '</div>';
1230
-
1231
- jQuery('.required-plugins').append(output);
1232
-
1233
- });
1234
- }
1235
-
1236
- /**
1237
- * Active
1238
- *
1239
- * List of not active required plugins.
1240
- */
1241
- if ( typeof response.data.active !== 'undefined' ) {
1242
-
1243
- jQuery( response.data.active ).each(function( index, plugin ) {
1244
-
1245
- var output = '<div class="plugin-card ';
1246
- output += ' plugin-card-'+plugin.slug+'"';
1247
- output += ' data-slug="'+plugin.slug+'"';
1248
- output += ' data-init="'+plugin.init+'">';
1249
- output += ' <span class="title">'+plugin.name+'</span>';
1250
- output += ' <button class="button disabled"';
1251
- output += ' data-slug="' + plugin.slug + '"';
1252
- output += ' data-name="' + plugin.name + '">';
1253
- output += astraSitesAdmin.strings.btnActive;
1254
- output += ' </button>';
1255
- // output += ' <span class="dashicons-yes dashicons"></span>';
1256
- output += '</div>';
1257
-
1258
- jQuery('.required-plugins').append(output);
1259
-
1260
- });
1261
- }
1262
-
1263
- /**
1264
- * Enable Demo Import Button
1265
- * @type number
1266
- */
1267
- astraSitesAdmin.requiredPlugins = response.data;
1268
- AstraSitesAdmin._enable_demo_import_button();
1269
-
1270
- });
1271
-
1272
- } else {
1273
-
1274
- // Enable Demo Import Button
1275
- AstraSitesAdmin._enable_demo_import_button( demoType );
1276
- jQuery('.required-plugins-wrap').remove();
1277
- }
1278
-
1279
- return;
1280
- },
1281
-
1282
- /**
1283
- * Enable Demo Import Button.
1284
- */
1285
- _enable_demo_import_button: function( type ) {
1286
-
1287
- type = ( undefined !== type ) ? type : 'free';
1288
-
1289
- $('.install-theme-info .theme-details .site-description').remove();
1290
-
1291
- switch( type ) {
1292
-
1293
- case 'free':
1294
- var all_buttons = parseInt( jQuery( '.plugin-card .button' ).length ) || 0,
1295
- disabled_buttons = parseInt( jQuery( '.plugin-card .button.disabled' ).length ) || 0;
1296
-
1297
- if( all_buttons === disabled_buttons ) {
1298
-
1299
- // XML reader not available notice.
1300
- if( astraSitesAdmin.XMLReaderDisabled ) {
1301
- if( ! $('.install-theme-info .astra-sites-xml-notice').length ) {
1302
- $('.install-theme-info').prepend( astraSitesAdmin.strings.warningXMLReader );
1303
- }
1304
- $('.astra-demo-import')
1305
- .removeClass('installing updating-message')
1306
- .addClass('disabled')
1307
- .text( astraSitesAdmin.strings.importDemo );
1308
- } else {
1309
- $('.astra-demo-import')
1310
- .removeAttr('data-import')
1311
- .removeClass('installing updating-message')
1312
- .addClass('button-primary')
1313
- .text( astraSitesAdmin.strings.importDemo );
1314
- }
1315
- }
1316
-
1317
- break;
1318
-
1319
- case 'upgrade':
1320
- var demo_slug = jQuery('.wp-full-overlay-header').attr('data-demo-slug');
1321
-
1322
- jQuery('.astra-demo-import')
1323
- .addClass('go-pro button-primary')
1324
- .removeClass('astra-demo-import')
1325
- .attr('target', '_blank')
1326
- .attr('href', astraSitesAdmin.getUpgradeURL + demo_slug )
1327
- .text( astraSitesAdmin.getUpgradeText )
1328
- .append('<i class="dashicons dashicons-external"></i>');
1329
-
1330
- break;
1331
-
1332
- default:
1333
- var demo_slug = jQuery('.wp-full-overlay-header').attr('data-demo-slug');
1334
-
1335
- jQuery('.astra-demo-import')
1336
- .addClass('go-pro button-primary')
1337
- .removeClass('astra-demo-import')
1338
- .attr('target', '_blank')
1339
- .attr('href', astraSitesAdmin.getProURL )
1340
- .text( astraSitesAdmin.getProText )
1341
- .append('<i class="dashicons dashicons-external"></i>');
1342
-
1343
- if( false == astraSitesAdmin.isWhiteLabeled ) {
1344
- if( astraSitesAdmin.isPro ) {
1345
- $('.install-theme-info .theme-details').prepend( wp.template('astra-sites-pro-inactive-site-description') );
1346
- } else {
1347
- $('.install-theme-info .theme-details').prepend( wp.template('astra-sites-pro-site-description') );
1348
- }
1349
- }
1350
-
1351
- break;
1352
- }
1353
-
1354
- },
1355
-
1356
- /**
1357
- * Update Page Count.
1358
- */
1359
- _updatedPagedCount: function() {
1360
- paged = parseInt(jQuery('body').attr('data-astra-demo-paged'));
1361
- jQuery('body').attr('data-astra-demo-paged', paged + 1);
1362
- window.setTimeout(function () {
1363
- jQuery('body').data('scrolling', false);
1364
- }, 800);
1365
- },
1366
-
1367
- /**
1368
- * Reset Page Count.
1369
- */
1370
- _resetPagedCount: function() {
1371
-
1372
- $('body').addClass('loading-content');
1373
- $('body').attr('data-astra-demo-last-request', '1');
1374
- $('body').attr('data-astra-demo-paged', '1');
1375
- $('body').attr('data-astra-demo-search', '');
1376
- $('body').attr('data-scrolling', false);
1377
-
1378
- },
1379
-
1380
- /**
1381
- * Remove plugin from the queue.
1382
- */
1383
- _removePluginFromQueue: function( removeItem, pluginsList ) {
1384
- return jQuery.grep(pluginsList, function( value ) {
1385
- return value.slug != removeItem;
1386
- });
1387
- }
1388
-
1389
- };
1390
-
1391
- /**
1392
- * Initialize AstraSitesAdmin
1393
- */
1394
- $(function(){
1395
- AstraSitesAdmin.init();
1396
- });
1397
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1398
  })(jQuery);
1
+ /**
2
+ * AJAX Request Queue
3
+ *
4
+ * - add()
5
+ * - remove()
6
+ * - run()
7
+ * - stop()
8
+ *
9
+ * @since 1.0.0
10
+ */
11
+ var AstraSitesAjaxQueue = (function() {
12
+
13
+ var requests = [];
14
+
15
+ return {
16
+
17
+ /**
18
+ * Add AJAX request
19
+ *
20
+ * @since 1.0.0
21
+ */
22
+ add: function(opt) {
23
+ requests.push(opt);
24
+ },
25
+
26
+ /**
27
+ * Remove AJAX request
28
+ *
29
+ * @since 1.0.0
30
+ */
31
+ remove: function(opt) {
32
+ if( jQuery.inArray(opt, requests) > -1 )
33
+ requests.splice($.inArray(opt, requests), 1);
34
+ },
35
+
36
+ /**
37
+ * Run / Process AJAX request
38
+ *
39
+ * @since 1.0.0
40
+ */
41
+ run: function() {
42
+ var self = this,
43
+ oriSuc;
44
+
45
+ if( requests.length ) {
46
+ oriSuc = requests[0].complete;
47
+
48
+ requests[0].complete = function() {
49
+ if( typeof(oriSuc) === 'function' ) oriSuc();
50
+ requests.shift();
51
+ self.run.apply(self, []);
52
+ };
53
+
54
+ jQuery.ajax(requests[0]);
55
+
56
+ } else {
57
+
58
+ self.tid = setTimeout(function() {
59
+ self.run.apply(self, []);
60
+ }, 1000);
61
+ }
62
+ },
63
+
64
+ /**
65
+ * Stop AJAX request
66
+ *
67
+ * @since 1.0.0
68
+ */
69
+ stop: function() {
70
+
71
+ requests = [];
72
+ clearTimeout(this.tid);
73
+ }
74
+ };
75
+
76
+ }());
77
+
78
+ (function($){
79
+
80
+ var AstraSSEImport = {
81
+ complete: {
82
+ posts: 0,
83
+ media: 0,
84
+ users: 0,
85
+ comments: 0,
86
+ terms: 0,
87
+ },
88
+
89
+ updateDelta: function (type, delta) {
90
+ this.complete[ type ] += delta;
91
+
92
+ var self = this;
93
+ requestAnimationFrame(function () {
94
+ self.render();
95
+ });
96
+ },
97
+ updateProgress: function ( type, complete, total ) {
98
+ var text = complete + '/' + total;
99
+
100
+ if( 'undefined' !== type && 'undefined' !== text ) {
101
+ total = parseInt( total, 10 );
102
+ if ( 0 === total || isNaN( total ) ) {
103
+ total = 1;
104
+ }
105
+ var percent = parseInt( complete, 10 ) / total;
106
+ var progress = Math.round( percent * 100 ) + '%';
107
+ var progress_bar = percent * 100;
108
+ }
109
+ },
110
+ render: function () {
111
+ var types = Object.keys( this.complete );
112
+ var complete = 0;
113
+ var total = 0;
114
+
115
+ for (var i = types.length - 1; i >= 0; i--) {
116
+ var type = types[i];
117
+ this.updateProgress( type, this.complete[ type ], this.data.count[ type ] );
118
+
119
+ complete += this.complete[ type ];
120
+ total += this.data.count[ type ];
121
+ }
122
+
123
+ this.updateProgress( 'total', complete, total );
124
+ }
125
+ };
126
+
127
+ AstraSitesAdmin = {
128
+
129
+ log_file : '',
130
+ customizer_data : '',
131
+ wxr_url : '',
132
+ wpforms_url : '',
133
+ options_data : '',
134
+ widgets_data : '',
135
+
136
+ init: function()
137
+ {
138
+ this._resetPagedCount();
139
+ this._bind();
140
+ },
141
+
142
+ /**
143
+ * Debugging.
144
+ *
145
+ * @param {mixed} data Mixed data.
146
+ */
147
+ _log: function( data ) {
148
+
149
+ if( astraSitesAdmin.debug ) {
150
+
151
+ var date = new Date();
152
+ var time = date.toLocaleTimeString();
153
+
154
+ if (typeof data == 'object') {
155
+ console.log('%c ' + JSON.stringify( data ) + ' ' + time, 'background: #ededed; color: #444');
156
+ } else {
157
+ console.log('%c ' + data + ' ' + time, 'background: #ededed; color: #444');
158
+ }
159
+
160
+
161
+ }
162
+ },
163
+
164
+ /**
165
+ * Binds events for the Astra Sites.
166
+ *
167
+ * @since 1.0.0
168
+ * @access private
169
+ * @method _bind
170
+ */
171
+ _bind: function()
172
+ {
173
+ $( document ).on('click' , '.devices button', AstraSitesAdmin._previewDevice);
174
+ $( document ).on('click' , '.theme-browser .theme-screenshot, .theme-browser .more-details, .theme-browser .install-theme-preview', AstraSitesAdmin._preview);
175
+ $( document ).on('click' , '.next-theme', AstraSitesAdmin._nextTheme);
176
+ $( document ).on('click' , '.previous-theme', AstraSitesAdmin._previousTheme);
177
+ $( document ).on('click' , '.collapse-sidebar', AstraSitesAdmin._collapse);
178
+ $( document ).on('click' , '.astra-demo-import', AstraSitesAdmin._importDemo);
179
+ $( document ).on('click' , '.install-now', AstraSitesAdmin._installNow);
180
+ $( document ).on('click' , '.close-full-overlay', AstraSitesAdmin._fullOverlay);
181
+ $( document ).on('click' , '.activate-now', AstraSitesAdmin._activateNow);
182
+ $( document ).on('wp-plugin-installing' , AstraSitesAdmin._pluginInstalling);
183
+ $( document ).on('wp-plugin-install-error' , AstraSitesAdmin._installError);
184
+ $( document ).on('wp-plugin-install-success' , AstraSitesAdmin._installSuccess);
185
+
186
+ $( document ).on('astra-sites-import-set-site-data-done' , AstraSitesAdmin._importWPForms );
187
+ $( document ).on('astra-sites-import-wpforms-done' , AstraSitesAdmin._importCustomizerSettings );
188
+ $( document ).on('astra-sites-import-customizer-settings-done' , AstraSitesAdmin._importPrepareXML );
189
+ $( document ).on('astra-sites-import-xml-done' , AstraSitesAdmin._importSiteOptions );
190
+ $( document ).on('astra-sites-import-options-done' , AstraSitesAdmin._importWidgets );
191
+ $( document ).on('astra-sites-import-widgets-done' , AstraSitesAdmin._importEnd );
192
+ },
193
+
194
+ /**
195
+ * 5. Import Complete.
196
+ */
197
+ _importEnd: function( event ) {
198
+
199
+ $.ajax({
200
+ url : astraSitesAdmin.ajaxurl,
201
+ type : 'POST',
202
+ dataType: 'json',
203
+ data : {
204
+ action : 'astra-sites-import-end',
205
+ },
206
+ beforeSend: function() {
207
+ $('.button-hero.astra-demo-import').text( astraSitesAdmin.log.importComplete );
208
+ }
209
+ })
210
+ .fail(function( jqXHR ){
211
+ AstraSitesAdmin._importFailMessage( jqXHR.status + ' ' + jqXHR.responseText );
212
+ AstraSitesAdmin._log( jqXHR.status + ' ' + jqXHR.responseText );
213
+ })
214
+ .done(function ( data ) {
215
+
216
+ // 5. Fail - Import Complete.
217
+ if( false === data.success ) {
218
+ AstraSitesAdmin._importFailMessage( data.data );
219
+ AstraSitesAdmin._log( data.data );
220
+ } else {
221
+
222
+ $('body').removeClass('importing-site');
223
+ $('.previous-theme, .next-theme').removeClass('disabled');
224
+
225
+ // 5. Pass - Import Complete.
226
+ AstraSitesAdmin._importSuccessMessage();
227
+ AstraSitesAdmin._log( astraSitesAdmin.log.success + ' ' + astraSitesAdmin.siteURL );
228
+ }
229
+ });
230
+ },
231
+
232
+ /**
233
+ * 4. Import Widgets.
234
+ */
235
+ _importWidgets: function( event ) {
236
+
237
+ $.ajax({
238
+ url : astraSitesAdmin.ajaxurl,
239
+ type : 'POST',
240
+ dataType: 'json',
241
+ data : {
242
+ action : 'astra-sites-import-widgets',
243
+ widgets_data : AstraSitesAdmin.widgets_data,
244
+ },
245
+ beforeSend: function() {
246
+ AstraSitesAdmin._log( astraSitesAdmin.log.importWidgets );
247
+ $('.button-hero.astra-demo-import').text( astraSitesAdmin.log.importingWidgets );
248
+ },
249
+ })
250
+ .fail(function( jqXHR ){
251
+ AstraSitesAdmin._importFailMessage( jqXHR.status + ' ' + jqXHR.responseText );
252
+ AstraSitesAdmin._log( jqXHR.status + ' ' + jqXHR.responseText );
253
+ })
254
+ .done(function ( widgets_data ) {
255
+
256
+ // 4. Fail - Import Widgets.
257
+ if( false === widgets_data.success ) {
258
+ AstraSitesAdmin._importFailMessage( widgets_data.data );
259
+ AstraSitesAdmin._log( widgets_data.data );
260
+
261
+ } else {
262
+
263
+ // 4. Pass - Import Widgets.
264
+ AstraSitesAdmin._log( astraSitesAdmin.log.importWidgetsSuccess );
265
+ $(document).trigger( 'astra-sites-import-widgets-done' );
266
+ }
267
+ });
268
+ },
269
+
270
+ /**
271
+ * 3. Import Site Options.
272
+ */
273
+ _importSiteOptions: function( event ) {
274
+
275
+ $.ajax({
276
+ url : astraSitesAdmin.ajaxurl,
277
+ type : 'POST',
278
+ dataType: 'json',
279
+ data : {
280
+ action : 'astra-sites-import-options',
281
+ options_data : AstraSitesAdmin.options_data,
282
+ },
283
+ beforeSend: function() {
284
+ AstraSitesAdmin._log( astraSitesAdmin.log.importOptions );
285
+ $('.button-hero.astra-demo-import').text( astraSitesAdmin.log.importingOptions );
286
+ },
287
+ })
288
+ .fail(function( jqXHR ){
289
+ AstraSitesAdmin._importFailMessage( jqXHR.status + ' ' + jqXHR.responseText );
290
+ AstraSitesAdmin._log( jqXHR.status + ' ' + jqXHR.responseText );
291
+ })
292
+ .done(function ( options_data ) {
293
+
294
+ // 3. Fail - Import Site Options.
295
+ if( false === options_data.success ) {
296
+ AstraSitesAdmin._log( options_data );
297
+ AstraSitesAdmin._importFailMessage( options_data.data );
298
+ AstraSitesAdmin._log( options_data.data );
299
+
300
+ } else {
301
+
302
+ // 3. Pass - Import Site Options.
303
+ AstraSitesAdmin._log( astraSitesAdmin.log.importOptionsSuccess );
304
+ $(document).trigger( 'astra-sites-import-options-done' );
305
+ }
306
+ });
307
+ },
308
+
309
+ /**
310
+ * 2. Prepare XML Data.
311
+ */
312
+ _importPrepareXML: function( event ) {
313
+
314
+ $.ajax({
315
+ url : astraSitesAdmin.ajaxurl,
316
+ type : 'POST',
317
+ dataType: 'json',
318
+ data : {
319
+ action : 'astra-sites-import-prepare-xml',
320
+ wxr_url : AstraSitesAdmin.wxr_url,
321
+ },
322
+ beforeSend: function() {
323
+ AstraSitesAdmin._log( astraSitesAdmin.log.importXMLPrepare );
324
+ $('.button-hero.astra-demo-import').text( astraSitesAdmin.log.importXMLPreparing );
325
+ },
326
+ })
327
+ .fail(function( jqXHR ){
328
+ AstraSitesAdmin._importFailMessage( jqXHR.status + ' ' + jqXHR.responseText );
329
+ AstraSitesAdmin._log( jqXHR.status + ' ' + jqXHR.responseText );
330
+ })
331
+ .done(function ( xml_data ) {
332
+
333
+ // 2. Fail - Prepare XML Data.
334
+ if( false === xml_data.success ) {
335
+ AstraSitesAdmin._log( xml_data );
336
+ var error_msg = xml_data.data.error || xml_data.data;
337
+ AstraSitesAdmin._importFailMessage( error_msg );
338
+ AstraSitesAdmin._log( error_msg );
339
+
340
+ } else {
341
+
342
+ // 2. Pass - Prepare XML Data.
343
+ AstraSitesAdmin._log( astraSitesAdmin.log.importXMLPrepareSuccess );
344
+
345
+ // Import XML though Event Source.
346
+ AstraSSEImport.data = xml_data.data;
347
+ AstraSSEImport.render();
348
+
349
+ AstraSitesAdmin._log( astraSitesAdmin.log.importXML );
350
+ $('.button-hero.astra-demo-import').text( astraSitesAdmin.log.importingXML );
351
+
352
+ var evtSource = new EventSource( AstraSSEImport.data.url );
353
+ evtSource.onmessage = function ( message ) {
354
+ var data = JSON.parse( message.data );
355
+ switch ( data.action ) {
356
+ case 'updateDelta':
357
+ AstraSSEImport.updateDelta( data.type, data.delta );
358
+ break;
359
+
360
+ case 'complete':
361
+ evtSource.close();
362
+
363
+ // 2. Pass - Import XML though "Source Event".
364
+ AstraSitesAdmin._log( astraSitesAdmin.log.importXMLSuccess );
365
+ AstraSitesAdmin._log( '----- SSE - XML import Complete -----' );
366
+
367
+ $(document).trigger( 'astra-sites-import-xml-done' );
368
+
369
+ break;
370
+ }
371
+ };
372
+ evtSource.addEventListener( 'log', function ( message ) {
373
+ var data = JSON.parse( message.data );
374
+ AstraSitesAdmin._log( data.level + ' ' + data.message );
375
+ });
376
+ }
377
+ });
378
+ },
379
+
380
+ /**
381
+ * 1. Import WPForms Options.
382
+ */
383
+ _importWPForms: function( event ) {
384
+
385
+ $.ajax({
386
+ url : astraSitesAdmin.ajaxurl,
387
+ type : 'POST',
388
+ dataType: 'json',
389
+ data : {
390
+ action : 'astra-sites-import-wpforms',
391
+ wpforms_url : AstraSitesAdmin.wpforms_url,
392
+ },
393
+ beforeSend: function() {
394
+ AstraSitesAdmin._log( astraSitesAdmin.log.importWPForms );
395
+ $('.button-hero.astra-demo-import').text( astraSitesAdmin.log.importingWPForms );
396
+ },
397
+ })
398
+ .fail(function( jqXHR ){
399
+ AstraSitesAdmin._importFailMessage( jqXHR.status + ' ' + jqXHR.responseText );
400
+ AstraSitesAdmin._log( jqXHR.status + ' ' + jqXHR.responseText );
401
+ })
402
+ .done(function ( forms ) {
403
+
404
+ // 1. Fail - Import WPForms Options.
405
+ if( false === forms.success ) {
406
+ AstraSitesAdmin._importFailMessage( forms.data );
407
+ AstraSitesAdmin._log( forms.data );
408
+ } else {
409
+
410
+ // 1. Pass - Import Customizer Options.
411
+ AstraSitesAdmin._log( astraSitesAdmin.log.importWPFormsSuccess );
412
+
413
+ $(document).trigger( 'astra-sites-import-wpforms-done' );
414
+ }
415
+ });
416
+ },
417
+
418
+ /**
419
+ * 1. Import Customizer Options.
420
+ */
421
+ _importCustomizerSettings: function( event ) {
422
+
423
+ $.ajax({
424
+ url : astraSitesAdmin.ajaxurl,
425
+ type : 'POST',
426
+ dataType: 'json',
427
+ data : {
428
+ action : 'astra-sites-import-customizer-settings',
429
+ customizer_data : AstraSitesAdmin.customizer_data,
430
+ },
431
+ beforeSend: function() {
432
+ AstraSitesAdmin._log( astraSitesAdmin.log.importCustomizer );
433
+ $('.button-hero.astra-demo-import').text( astraSitesAdmin.log.importingCustomizer );
434
+ },
435
+ })
436
+ .fail(function( jqXHR ){
437
+ AstraSitesAdmin._importFailMessage( jqXHR.status + ' ' + jqXHR.responseText );
438
+ AstraSitesAdmin._log( jqXHR.status + ' ' + jqXHR.responseText );
439
+ })
440
+ .done(function ( customizer_data ) {
441
+
442
+ // 1. Fail - Import Customizer Options.
443
+ if( false === customizer_data.success ) {
444
+ AstraSitesAdmin._importFailMessage( customizer_data.data );
445
+ AstraSitesAdmin._log( customizer_data.data );
446
+ } else {
447
+
448
+ // 1. Pass - Import Customizer Options.
449
+ AstraSitesAdmin._log( astraSitesAdmin.log.importCustomizerSuccess );
450
+
451
+ $(document).trigger( 'astra-sites-import-customizer-settings-done' );
452
+ }
453
+ });
454
+ },
455
+
456
+ /**
457
+ * Import Success Button.
458
+ *
459
+ * @param {string} data Error message.
460
+ */
461
+ _importSuccessMessage: function() {
462
+
463
+ $('.astra-demo-import').removeClass('updating-message installing')
464
+ .removeAttr('data-import')
465
+ .addClass('view-site')
466
+ .removeClass('astra-demo-import')
467
+ .text( astraSitesAdmin.strings.viewSite )
468
+ .attr('target', '_blank')
469
+ .append('<i class="dashicons dashicons-external"></i>')
470
+ .attr('href', astraSitesAdmin.siteURL );
471
+ },
472
+
473
+ /**
474
+ * Preview Device
475
+ */
476
+ _previewDevice: function( event ) {
477
+ var device = $( event.currentTarget ).data( 'device' );
478
+
479
+ $('.theme-install-overlay')
480
+ .removeClass( 'preview-desktop preview-tablet preview-mobile' )
481
+ .addClass( 'preview-' + device )
482
+ .data( 'current-preview-device', device );
483
+
484
+ AstraSitesAdmin._tooglePreviewDeviceButtons( device );
485
+ },
486
+
487
+ /**
488
+ * Toggle Preview Buttons
489
+ */
490
+ _tooglePreviewDeviceButtons: function( newDevice ) {
491
+ var $devices = $( '.wp-full-overlay-footer .devices' );
492
+
493
+ $devices.find( 'button' )
494
+ .removeClass( 'active' )
495
+ .attr( 'aria-pressed', false );
496
+
497
+ $devices.find( 'button.preview-' + newDevice )
498
+ .addClass( 'active' )
499
+ .attr( 'aria-pressed', true );
500
+ },
501
+
502
+ /**
503
+ * Import Error Button.
504
+ *
505
+ * @param {string} data Error message.
506
+ */
507
+ _importFailMessage: function( message, from ) {
508
+
509
+ $('.astra-demo-import')
510
+ .addClass('go-pro button-primary')
511
+ .removeClass('updating-message installing')
512
+ .removeAttr('data-import')
513
+ .attr('target', '_blank')
514
+ .append('<i class="dashicons dashicons-external"></i>')
515
+ .removeClass('astra-demo-import');
516
+
517
+ // Add the doc link due to import log file not generated.
518
+ if( 'undefined' === from ) {
519
+
520
+ $('.wp-full-overlay-header .go-pro').text( astraSitesAdmin.strings.importFailedBtnSmall );
521
+ $('.wp-full-overlay-footer .go-pro').text( astraSitesAdmin.strings.importFailedBtnLarge );
522
+ $('.go-pro').attr('href', astraSitesAdmin.log.serverConfiguration );
523
+
524
+ // Add the import log file link.
525
+ } else {
526
+
527
+ $('.wp-full-overlay-header .go-pro').text( astraSitesAdmin.strings.importFailBtn );
528
+ $('.wp-full-overlay-footer .go-pro').text( astraSitesAdmin.strings.importFailBtnLarge )
529
+
530
+ // Add the import log file link.
531
+ if( 'undefined' !== AstraSitesAdmin.log_file_url ) {
532
+ $('.go-pro').attr('href', AstraSitesAdmin.log_file_url );
533
+ } else {
534
+ $('.go-pro').attr('href', astraSitesAdmin.log.serverConfiguration );
535
+ }
536
+ }
537
+
538
+ var output = '<div class="astra-api-error notice notice-error notice-alt is-dismissible">';
539
+ output += ' <p>'+message+'</p>';
540
+ output += ' <button type="button" class="notice-dismiss">';
541
+ output += ' <span class="screen-reader-text">'+commonL10n.dismiss+'</span>';
542
+ output += ' </button>';
543
+ output += '</div>';
544
+
545
+ // Fail Notice.
546
+ $('.install-theme-info').append( output );
547
+
548
+
549
+ // !important to add trigger.
550
+ // Which reinitialize the dismiss error message events.
551
+ $(document).trigger('wp-updates-notice-added');
552
+ },
553
+
554
+
555
+ /**
556
+ * Install Now
557
+ */
558
+ _installNow: function(event)
559
+ {
560
+ event.preventDefault();
561
+
562
+ var $button = jQuery( event.target ),
563
+ $document = jQuery(document);
564
+
565
+ if ( $button.hasClass( 'updating-message' ) || $button.hasClass( 'button-disabled' ) ) {
566
+ return;
567
+ }
568
+
569
+ if ( wp.updates.shouldRequestFilesystemCredentials && ! wp.updates.ajaxLocked ) {
570
+ wp.updates.requestFilesystemCredentials( event );
571
+
572
+ $document.on( 'credential-modal-cancel', function() {
573
+ var $message = $( '.install-now.updating-message' );
574
+
575
+ $message
576
+ .removeClass( 'updating-message' )
577
+ .text( wp.updates.l10n.installNow );
578
+
579
+ wp.a11y.speak( wp.updates.l10n.updateCancel, 'polite' );
580
+ } );
581
+ }
582
+
583
+ AstraSitesAdmin._log( astraSitesAdmin.log.installingPlugin + ' ' + $button.data( 'slug' ) );
584
+
585
+ wp.updates.installPlugin( {
586
+ slug: $button.data( 'slug' )
587
+ } );
588
+ },
589
+
590
+ /**
591
+ * Install Success
592
+ */
593
+ _installSuccess: function( event, response ) {
594
+
595
+ event.preventDefault();
596
+
597
+ AstraSitesAdmin._log( astraSitesAdmin.log.installed + ' ' + response.slug );
598
+
599
+ var $message = jQuery( '.plugin-card-' + response.slug ).find( '.button' );
600
+ var $siteOptions = jQuery( '.wp-full-overlay-header').find('.astra-site-options').val();
601
+ var $enabledExtensions = jQuery( '.wp-full-overlay-header').find('.astra-enabled-extensions').val();
602
+
603
+ // Transform the 'Install' button into an 'Activate' button.
604
+ var $init = $message.data('init');
605
+
606
+ $message.removeClass( 'install-now installed button-disabled updated-message' )
607
+ .addClass('updating-message')
608
+ .html( astraSitesAdmin.strings.btnActivating );
609
+
610
+ // Reset not installed plugins list.
611
+ var pluginsList = astraSitesAdmin.requiredPlugins.notinstalled;
612
+ astraSitesAdmin.requiredPlugins.notinstalled = AstraSitesAdmin._removePluginFromQueue( response.slug, pluginsList );
613
+
614
+ // WordPress adds "Activate" button after waiting for 1000ms. So we will run our activation after that.
615
+ setTimeout( function() {
616
+
617
+ $.ajax({
618
+ url: astraSitesAdmin.ajaxurl,
619
+ type: 'POST',
620
+ data: {
621
+ 'action' : 'astra-required-plugin-activate',
622
+ 'init' : $init,
623
+ 'options' : $siteOptions,
624
+ 'enabledExtensions' : $enabledExtensions,
625
+ },
626
+ })
627
+ .done(function (result) {
628
+
629
+ if( result.success ) {
630
+
631
+ var pluginsList = astraSitesAdmin.requiredPlugins.inactive;
632
+
633
+ // Reset not installed plugins list.
634
+ astraSitesAdmin.requiredPlugins.inactive = AstraSitesAdmin._removePluginFromQueue( response.slug, pluginsList );
635
+
636
+ $message.removeClass( 'button-primary install-now activate-now updating-message' )
637
+ .attr('disabled', 'disabled')
638
+ .addClass('disabled')
639
+ .text( astraSitesAdmin.strings.btnActive );
640
+
641
+ // Enable Demo Import Button
642
+ AstraSitesAdmin._enable_demo_import_button();
643
+
644
+ } else {
645
+
646
+ $message.removeClass( 'updating-message' );
647
+
648
+ }
649
+
650
+ });
651
+
652
+ }, 1200 );
653
+
654
+ },
655
+
656
+ /**
657
+ * Plugin Installation Error.
658
+ */
659
+ _installError: function( event, response ) {
660
+
661
+ var $card = jQuery( '.plugin-card-' + response.slug );
662
+
663
+ AstraSitesAdmin._log( response.errorMessage + ' ' + response.slug );
664
+
665
+ $card
666
+ .removeClass( 'button-primary' )
667
+ .addClass( 'disabled' )
668
+ .html( wp.updates.l10n.installFailedShort );
669
+
670
+ AstraSitesAdmin._importFailMessage( response.errorMessage );
671
+ },
672
+
673
+ /**
674
+ * Installing Plugin
675
+ */
676
+ _pluginInstalling: function(event, args) {
677
+ event.preventDefault();
678
+
679
+ var $card = jQuery( '.plugin-card-' + args.slug );
680
+ var $button = $card.find( '.button' );
681
+
682
+ AstraSitesAdmin._log( astraSitesAdmin.log.installingPlugin + ' ' + args.slug );
683
+
684
+ $card.addClass('updating-message');
685
+ $button.addClass('already-started');
686
+
687
+ },
688
+
689
+ /**
690
+ * Render Demo Preview
691
+ */
692
+ _activateNow: function( eventn ) {
693
+
694
+ event.preventDefault();
695
+
696
+ var $button = jQuery( event.target ),
697
+ $init = $button.data( 'init' ),
698
+ $slug = $button.data( 'slug' );
699
+
700
+ if ( $button.hasClass( 'updating-message' ) || $button.hasClass( 'button-disabled' ) ) {
701
+ return;
702
+ }
703
+
704
+ AstraSitesAdmin._log( astraSitesAdmin.log.activating + ' ' + $slug );
705
+
706
+ $button.addClass('updating-message button-primary')
707
+ .html( astraSitesAdmin.strings.btnActivating );
708
+
709
+ var $siteOptions = jQuery( '.wp-full-overlay-header').find('.astra-site-options').val();
710
+ var $enabledExtensions = jQuery( '.wp-full-overlay-header').find('.astra-enabled-extensions').val();
711
+
712
+ $.ajax({
713
+ url: astraSitesAdmin.ajaxurl,
714
+ type: 'POST',
715
+ data: {
716
+ 'action' : 'astra-required-plugin-activate',
717
+ 'init' : $init,
718
+ 'options' : $siteOptions,
719
+ 'enabledExtensions' : $enabledExtensions,
720
+ },
721
+ })
722
+ .done(function (result) {
723
+
724
+ if( result.success ) {
725
+
726
+ AstraSitesAdmin._log( astraSitesAdmin.log.activated + ' ' + $slug );
727
+
728
+ var pluginsList = astraSitesAdmin.requiredPlugins.inactive;
729
+
730
+ // Reset not installed plugins list.
731
+ astraSitesAdmin.requiredPlugins.inactive = AstraSitesAdmin._removePluginFromQueue( $slug, pluginsList );
732
+
733
+ $button.removeClass( 'button-primary install-now activate-now updating-message' )
734
+ .attr('disabled', 'disabled')
735
+ .addClass('disabled')
736
+ .text( astraSitesAdmin.strings.btnActive );
737
+
738
+ // Enable Demo Import Button
739
+ AstraSitesAdmin._enable_demo_import_button();
740
+
741
+ }
742
+
743
+ })
744
+ .fail(function () {
745
+ });
746
+
747
+ },
748
+
749
+ /**
750
+ * Full Overlay
751
+ */
752
+ _fullOverlay: function (event) {
753
+ event.preventDefault();
754
+
755
+ // Import process is started?
756
+ // And Closing the window? Then showing the warning confirm message.
757
+ if( $('body').hasClass('importing-site') && ! confirm( astraSitesAdmin.strings.warningBeforeCloseWindow ) ) {
758
+ return;
759
+ }
760
+
761
+ $('body').removeClass('importing-site');
762
+ $('.previous-theme, .next-theme').removeClass('disabled');
763
+ $('.theme-install-overlay').css('display', 'none');
764
+ $('.theme-install-overlay').remove();
765
+ $('.theme-preview-on').removeClass('theme-preview-on');
766
+ $('html').removeClass('astra-site-preview-on');
767
+ },
768
+
769
+ /**
770
+ * Bulk Plugin Active & Install
771
+ */
772
+ _bulkPluginInstallActivate: function()
773
+ {
774
+ if( 0 === astraSitesAdmin.requiredPlugins.length ) {
775
+ return;
776
+ }
777
+
778
+ jQuery('.required-plugins')
779
+ .find('.install-now')
780
+ .addClass( 'updating-message' )
781
+ .removeClass( 'install-now' )
782
+ .text( wp.updates.l10n.installing );
783
+
784
+ jQuery('.required-plugins')
785
+ .find('.activate-now')
786
+ .addClass('updating-message')
787
+ .removeClass( 'activate-now' )
788
+ .html( astraSitesAdmin.strings.btnActivating );
789
+
790
+ var not_installed = astraSitesAdmin.requiredPlugins.notinstalled || '';
791
+ var activate_plugins = astraSitesAdmin.requiredPlugins.inactive || '';
792
+
793
+ // First Install Bulk.
794
+ if( not_installed.length > 0 ) {
795
+ AstraSitesAdmin._installAllPlugins( not_installed );
796
+ }
797
+
798
+ // Second Activate Bulk.
799
+ if( activate_plugins.length > 0 ) {
800
+ AstraSitesAdmin._activateAllPlugins( activate_plugins );
801
+ }
802
+
803
+ },
804
+
805
+ /**
806
+ * Activate All Plugins.
807
+ */
808
+ _activateAllPlugins: function( activate_plugins ) {
809
+
810
+ // Activate ALl Plugins.
811
+ AstraSitesAjaxQueue.stop();
812
+ AstraSitesAjaxQueue.run();
813
+
814
+ AstraSitesAdmin._log( astraSitesAdmin.log.bulkActivation );
815
+
816
+ $.each( activate_plugins, function(index, single_plugin) {
817
+
818
+ var $card = jQuery( '.plugin-card-' + single_plugin.slug ),
819
+ $button = $card.find('.button'),
820
+ $siteOptions = jQuery( '.wp-full-overlay-header').find('.astra-site-options').val(),
821
+ $enabledExtensions = jQuery( '.wp-full-overlay-header').find('.astra-enabled-extensions').val();
822
+
823
+ $button.addClass('updating-message');
824
+
825
+ AstraSitesAjaxQueue.add({
826
+ url: astraSitesAdmin.ajaxurl,
827
+ type: 'POST',
828
+ data: {
829
+ 'action' : 'astra-required-plugin-activate',
830
+ 'init' : single_plugin.init,
831
+ 'options' : $siteOptions,
832
+ 'enabledExtensions' : $enabledExtensions,
833
+ },
834
+ success: function( result ){
835
+
836
+ if( result.success ) {
837
+
838
+ AstraSitesAdmin._log( astraSitesAdmin.log.activate + ' ' + single_plugin.slug );
839
+
840
+ var $card = jQuery( '.plugin-card-' + single_plugin.slug );
841
+ var $button = $card.find( '.button' );
842
+ if( ! $button.hasClass('already-started') ) {
843
+ var pluginsList = astraSitesAdmin.requiredPlugins.inactive;
844
+
845
+ // Reset not installed plugins list.
846
+ astraSitesAdmin.requiredPlugins.inactive = AstraSitesAdmin._removePluginFromQueue( single_plugin.slug, pluginsList );
847
+ }
848
+
849
+ $button.removeClass( 'button-primary install-now activate-now updating-message' )
850
+ .attr('disabled', 'disabled')
851
+ .addClass('disabled')
852
+ .text( astraSitesAdmin.strings.btnActive );
853
+
854
+ // Enable Demo Import Button
855
+ AstraSitesAdmin._enable_demo_import_button();
856
+ } else {
857
+ AstraSitesAdmin._log( astraSitesAdmin.log.activationError + ' - ' + single_plugin.slug );
858
+ }
859
+ }
860
+ });
861
+ });
862
+ },
863
+
864
+ /**
865
+ * Install All Plugins.
866
+ */
867
+ _installAllPlugins: function( not_installed ) {
868
+
869
+ AstraSitesAdmin._log( astraSitesAdmin.log.bulkInstall );
870
+
871
+ $.each( not_installed, function(index, single_plugin) {
872
+
873
+ var $card = jQuery( '.plugin-card-' + single_plugin.slug ),
874
+ $button = $card.find('.button');
875
+
876
+ if( ! $button.hasClass('already-started') ) {
877
+
878
+ // Add each plugin activate request in Ajax queue.
879
+ // @see wp-admin/js/updates.js
880
+ wp.updates.queue.push( {
881
+ action: 'install-plugin', // Required action.
882
+ data: {
883
+ slug: single_plugin.slug
884
+ }
885
+ } );
886
+ }
887
+ });
888
+
889
+ // Required to set queue.
890
+ wp.updates.queueChecker();
891
+ },
892
+
893
+ /**
894
+ * Fires when a nav item is clicked.
895
+ *
896
+ * @since 1.0
897
+ * @access private
898
+ * @method _importDemo
899
+ */
900
+ _importDemo: function()
901
+ {
902
+ var $this = jQuery(this),
903
+ $theme = $this.closest('.astra-sites-preview').find('.wp-full-overlay-header'),
904
+ apiURL = $theme.data('demo-api') || '',
905
+ plugins = $theme.data('required-plugins');
906
+
907
+ var disabled = $this.attr('data-import');
908
+
909
+ if ( typeof disabled !== 'undefined' && disabled === 'disabled' || $this.hasClass('disabled') ) {
910
+
911
+ $('.astra-demo-import').addClass('updating-message installing')
912
+ .text( wp.updates.l10n.installing );
913
+
914
+ /**
915
+ * Process Bulk Plugin Install & Activate
916
+ */
917
+ AstraSitesAdmin._bulkPluginInstallActivate();
918
+
919
+ return;
920
+ }
921
+
922
+ // Proceed?
923
+ if( ! confirm( astraSitesAdmin.strings.importWarning ) ) {
924
+ return;
925
+ }
926
+
927
+ $('body').addClass('importing-site');
928
+ $('.previous-theme, .next-theme').addClass('disabled');
929
+
930
+ // Remove all notices before import start.
931
+ $('.install-theme-info > .notice').remove();
932
+
933
+ $('.astra-demo-import').attr('data-import', 'disabled')
934
+ .addClass('updating-message installing')
935
+ .text( astraSitesAdmin.strings.importingDemo );
936
+
937
+ $this.closest('.theme').focus();
938
+
939
+ var $theme = $this.closest('.astra-sites-preview').find('.wp-full-overlay-header');
940
+
941
+ var apiURL = $theme.data('demo-api') || '';
942
+
943
+ // Site Import by API URL.
944
+ if( apiURL ) {
945
+ AstraSitesAdmin._importSite( apiURL );
946
+ }
947
+
948
+ },
949
+
950
+ /**
951
+ * Start Import Process by API URL.
952
+ *
953
+ * @param {string} apiURL Site API URL.
954
+ */
955
+ _importSite: function( apiURL ) {
956
+
957
+ AstraSitesAdmin._log( astraSitesAdmin.log.api + ' : ' + apiURL );
958
+ AstraSitesAdmin._log( astraSitesAdmin.log.importing );
959
+
960
+ $('.button-hero.astra-demo-import').text( astraSitesAdmin.log.gettingData );
961
+
962
+ // 1. Request Site Import
963
+ $.ajax({
964
+ url : astraSitesAdmin.ajaxurl,
965
+ type : 'POST',
966
+ dataType: 'json',
967
+ data : {
968
+ 'action' : 'astra-sites-import-set-site-data',
969
+ 'api_url' : apiURL,
970
+ },
971
+ })
972
+ .fail(function( jqXHR ){
973
+ AstraSitesAdmin._importFailMessage( jqXHR.status + ' ' + jqXHR.responseText );
974
+ AstraSitesAdmin._log( jqXHR.status + ' ' + jqXHR.responseText );
975
+ })
976
+ .done(function ( demo_data ) {
977
+
978
+ // 1. Fail - Request Site Import
979
+ if( false === demo_data.success ) {
980
+
981
+ AstraSitesAdmin._importFailMessage( demo_data.data );
982
+
983
+ } else {
984
+
985
+ // Set log file URL.
986
+ if( 'log_file' in demo_data.data ){
987
+ AstraSitesAdmin.log_file_url = decodeURIComponent( demo_data.data.log_file ) || '';
988
+ }
989
+
990
+ // 1. Pass - Request Site Import
991
+ AstraSitesAdmin._log( astraSitesAdmin.log.processingRequest );
992
+
993
+ AstraSitesAdmin.customizer_data = JSON.stringify( demo_data.data['astra-site-customizer-data'] ) || '';
994
+ AstraSitesAdmin.wxr_url = encodeURI( demo_data.data['astra-site-wxr-path'] ) || '';
995
+ AstraSitesAdmin.wpforms_url = encodeURI( demo_data.data['astra-site-wpforms-path'] ) || '';
996
+ AstraSitesAdmin.options_data = JSON.stringify( demo_data.data['astra-site-options-data'] ) || '';
997
+ AstraSitesAdmin.widgets_data = JSON.stringify( demo_data.data['astra-site-widgets-data'] ) || '';
998
+
999
+ $(document).trigger( 'astra-sites-import-set-site-data-done' );
1000
+ }
1001
+
1002
+ });
1003
+
1004
+ },
1005
+
1006
+ /**
1007
+ * Collapse Sidebar.
1008
+ */
1009
+ _collapse: function() {
1010
+ event.preventDefault();
1011
+
1012
+ overlay = jQuery('.wp-full-overlay');
1013
+
1014
+ if (overlay.hasClass('expanded')) {
1015
+ overlay.removeClass('expanded');
1016
+ overlay.addClass('collapsed');
1017
+ return;
1018
+ }
1019
+
1020
+ if (overlay.hasClass('collapsed')) {
1021
+ overlay.removeClass('collapsed');
1022
+ overlay.addClass('expanded');
1023
+ return;
1024
+ }
1025
+ },
1026
+
1027
+ /**
1028
+ * Previous Theme.
1029
+ */
1030
+ _previousTheme: function (event) {
1031
+ event.preventDefault();
1032
+
1033
+ currentDemo = jQuery('.theme-preview-on');
1034
+ currentDemo.removeClass('theme-preview-on');
1035
+ prevDemo = currentDemo.prev('.theme');
1036
+ prevDemo.addClass('theme-preview-on');
1037
+
1038
+ AstraSitesAdmin._renderDemoPreview(prevDemo);
1039
+ },
1040
+
1041
+ /**
1042
+ * Next Theme.
1043
+ */
1044
+ _nextTheme: function (event) {
1045
+ event.preventDefault();
1046
+ currentDemo = jQuery('.theme-preview-on')
1047
+ currentDemo.removeClass('theme-preview-on');
1048
+ nextDemo = currentDemo.next('.theme');
1049
+ nextDemo.addClass('theme-preview-on');
1050
+
1051
+ AstraSitesAdmin._renderDemoPreview( nextDemo );
1052
+ },
1053
+
1054
+ /**
1055
+ * Individual Site Preview
1056
+ *
1057
+ * On click on image, more link & preview button.
1058
+ */
1059
+ _preview: function( event ) {
1060
+
1061
+ event.preventDefault();
1062
+
1063
+ var self = jQuery(this).parents('.theme');
1064
+ self.addClass('theme-preview-on');
1065
+
1066
+ jQuery('html').addClass('astra-site-preview-on');
1067
+
1068
+ AstraSitesAdmin._renderDemoPreview( self );
1069
+ },
1070
+
1071
+ /**
1072
+ * Check Next Previous Buttons.
1073
+ */
1074
+ _checkNextPrevButtons: function() {
1075
+ currentDemo = jQuery('.theme-preview-on');
1076
+ nextDemo = currentDemo.nextAll('.theme').length;
1077
+ prevDemo = currentDemo.prevAll('.theme').length;
1078
+
1079
+ if (nextDemo == 0) {
1080
+ jQuery('.next-theme').addClass('disabled');
1081
+ } else if (nextDemo != 0) {
1082
+ jQuery('.next-theme').removeClass('disabled');
1083
+ }
1084
+
1085
+ if (prevDemo == 0) {
1086
+ jQuery('.previous-theme').addClass('disabled');
1087
+ } else if (prevDemo != 0) {
1088
+ jQuery('.previous-theme').removeClass('disabled');
1089
+ }
1090
+
1091
+ return;
1092
+ },
1093
+
1094
+ /**
1095
+ * Render Demo Preview
1096
+ */
1097
+ _renderDemoPreview: function(anchor) {
1098
+
1099
+ var demoId = anchor.data('id') || '',
1100
+ apiURL = anchor.data('demo-api') || '',
1101
+ demoType = anchor.data('demo-type') || '',
1102
+ demoURL = anchor.data('demo-url') || '',
1103
+ screenshot = anchor.data('screenshot') || '',
1104
+ demo_name = anchor.data('demo-name') || '',
1105
+ demo_slug = anchor.data('demo-slug') || '',
1106
+ content = anchor.data('content') || '',
1107
+ requiredPlugins = anchor.data('required-plugins') || '',
1108
+ astraSiteOptions = anchor.find('.astra-site-options').val() || '';
1109
+ astraEnabledExtensions = anchor.find('.astra-enabled-extensions').val() || '';
1110
+
1111
+ AstraSitesAdmin._log( astraSitesAdmin.log.preview + ' "' + demo_name + '" URL : ' + demoURL );
1112
+
1113
+ var template = wp.template('astra-site-preview');
1114
+
1115
+ templateData = [{
1116
+ id : demoId,
1117
+ astra_demo_type : demoType,
1118
+ astra_demo_url : demoURL,
1119
+ demo_api : apiURL,
1120
+ screenshot : screenshot,
1121
+ demo_name : demo_name,
1122
+ slug : demo_slug,
1123
+ content : content,
1124
+ required_plugins : JSON.stringify(requiredPlugins),
1125
+ astra_site_options : astraSiteOptions,
1126
+ astra_enabled_extensions : astraEnabledExtensions,
1127
+ }];
1128
+
1129
+ // delete any earlier fullscreen preview before we render new one.
1130
+ jQuery('.theme-install-overlay').remove();
1131
+
1132
+ jQuery('#astra-sites-menu-page').append(template(templateData[0]));
1133
+ jQuery('.theme-install-overlay').css('display', 'block');
1134
+ AstraSitesAdmin._checkNextPrevButtons();
1135
+
1136
+ var desc = jQuery('.theme-details');
1137
+ var descHeight = parseInt( desc.outerHeight() );
1138
+ var descBtn = jQuery('.theme-details-read-more');
1139
+
1140
+ if( $.isArray( requiredPlugins ) ) {
1141
+
1142
+ if( descHeight >= 55 ) {
1143
+
1144
+ // Show button.
1145
+ descBtn.css( 'display', 'inline-block' );
1146
+
1147
+ // Set height upto 3 line.
1148
+ desc.css( 'height', 57 );
1149
+
1150
+ // Button Click.
1151
+ descBtn.click(function(event) {
1152
+
1153
+ if( descBtn.hasClass('open') ) {
1154
+ desc.animate({ height: 57 },
1155
+ 300, function() {
1156
+ descBtn.removeClass('open');
1157
+ descBtn.html( astraSitesAdmin.strings.DescExpand );
1158
+ });
1159
+ } else {
1160
+ desc.animate({ height: descHeight },
1161
+ 300, function() {
1162
+ descBtn.addClass('open');
1163
+ descBtn.html( astraSitesAdmin.strings.DescCollapse );
1164
+ });
1165
+ }
1166
+
1167
+ });
1168
+ }
1169
+
1170
+ // or
1171
+ var $pluginsFilter = jQuery( '#plugin-filter' ),
1172
+ data = {
1173
+ action : 'astra-required-plugins',
1174
+ _ajax_nonce : astraSitesAdmin._ajax_nonce,
1175
+ required_plugins : requiredPlugins
1176
+ };
1177
+
1178
+ // Add disabled class from import button.
1179
+ $('.astra-demo-import')
1180
+ .addClass('disabled not-click-able')
1181
+ .removeAttr('data-import');
1182
+
1183
+ $('.required-plugins').addClass('loading').html('<span class="spinner is-active"></span>');
1184
+
1185
+ // Required Required.
1186
+ $.ajax({
1187
+ url : astraSitesAdmin.ajaxurl,
1188
+ type : 'POST',
1189
+ data : data,
1190
+ })
1191
+ .fail(function( jqXHR ){
1192
+
1193
+ // Remove loader.
1194
+ jQuery('.required-plugins').removeClass('loading').html('');
1195
+
1196
+ AstraSitesAdmin._importFailMessage( jqXHR.status + ' ' + jqXHR.responseText, 'plugins' );
1197
+ AstraSitesAdmin._log( jqXHR.status + ' ' + jqXHR.responseText );
1198
+ })
1199
+ .done(function ( response ) {
1200
+
1201
+ // Release disabled class from import button.
1202
+ $('.astra-demo-import')
1203
+ .removeClass('disabled not-click-able')
1204
+ .attr('data-import', 'disabled');
1205
+
1206
+ // Remove loader.
1207
+ $('.required-plugins').removeClass('loading').html('');
1208
+
1209
+ /**
1210
+ * Count remaining plugins.
1211
+ * @type number
1212
+ */
1213
+ var remaining_plugins = 0;
1214
+
1215
+ /**
1216
+ * Not Installed
1217
+ *
1218
+ * List of not installed required plugins.
1219
+ */
1220
+ if ( typeof response.data.notinstalled !== 'undefined' ) {
1221
+
1222
+ // Add not have installed plugins count.
1223
+ remaining_plugins += parseInt( response.data.notinstalled.length );
1224
+
1225
+ jQuery( response.data.notinstalled ).each(function( index, plugin ) {
1226
+
1227
+ var output = '<div class="plugin-card ';
1228
+ output += ' plugin-card-'+plugin.slug+'"';
1229
+ output += ' data-slug="'+plugin.slug+'"';
1230
+ output += ' data-init="'+plugin.init+'">';
1231
+ output += ' <span class="title">'+plugin.name+'</span>';
1232
+ output += ' <button class="button install-now"';
1233
+ output += ' data-init="' + plugin.init + '"';
1234
+ output += ' data-slug="' + plugin.slug + '"';
1235
+ output += ' data-name="' + plugin.name + '">';
1236
+ output += wp.updates.l10n.installNow;
1237
+ output += ' </button>';
1238
+ // output += ' <span class="dashicons-no dashicons"></span>';
1239
+ output += '</div>';
1240
+
1241
+ jQuery('.required-plugins').append(output);
1242
+
1243
+ });
1244
+ }
1245
+
1246
+ /**
1247
+ * Inactive
1248
+ *
1249
+ * List of not inactive required plugins.
1250
+ */
1251
+ if ( typeof response.data.inactive !== 'undefined' ) {
1252
+
1253
+ // Add inactive plugins count.
1254
+ remaining_plugins += parseInt( response.data.inactive.length );
1255
+
1256
+ jQuery( response.data.inactive ).each(function( index, plugin ) {
1257
+
1258
+ var output = '<div class="plugin-card ';
1259
+ output += ' plugin-card-'+plugin.slug+'"';
1260
+ output += ' data-slug="'+plugin.slug+'"';
1261
+ output += ' data-init="'+plugin.init+'">';
1262
+ output += ' <span class="title">'+plugin.name+'</span>';
1263
+ output += ' <button class="button activate-now button-primary"';
1264
+ output += ' data-init="' + plugin.init + '"';
1265
+ output += ' data-slug="' + plugin.slug + '"';
1266
+ output += ' data-name="' + plugin.name + '">';
1267
+ output += wp.updates.l10n.activatePlugin;
1268
+ output += ' </button>';
1269
+ // output += ' <span class="dashicons-no dashicons"></span>';
1270
+ output += '</div>';
1271
+
1272
+ jQuery('.required-plugins').append(output);
1273
+
1274
+ });
1275
+ }
1276
+
1277
+ /**
1278
+ * Active
1279
+ *
1280
+ * List of not active required plugins.
1281
+ */
1282
+ if ( typeof response.data.active !== 'undefined' ) {
1283
+
1284
+ jQuery( response.data.active ).each(function( index, plugin ) {
1285
+
1286
+ var output = '<div class="plugin-card ';
1287
+ output += ' plugin-card-'+plugin.slug+'"';
1288
+ output += ' data-slug="'+plugin.slug+'"';
1289
+ output += ' data-init="'+plugin.init+'">';
1290
+ output += ' <span class="title">'+plugin.name+'</span>';
1291
+ output += ' <button class="button disabled"';
1292
+ output += ' data-slug="' + plugin.slug + '"';
1293
+ output += ' data-name="' + plugin.name + '">';
1294
+ output += astraSitesAdmin.strings.btnActive;
1295
+ output += ' </button>';
1296
+ // output += ' <span class="dashicons-yes dashicons"></span>';
1297
+ output += '</div>';
1298
+
1299
+ jQuery('.required-plugins').append(output);
1300
+
1301
+ });
1302
+ }
1303
+
1304
+ /**
1305
+ * Enable Demo Import Button
1306
+ * @type number
1307
+ */
1308
+ astraSitesAdmin.requiredPlugins = response.data;
1309
+ AstraSitesAdmin._enable_demo_import_button();
1310
+
1311
+ });
1312
+
1313
+ } else {
1314
+
1315
+ // Enable Demo Import Button
1316
+ AstraSitesAdmin._enable_demo_import_button( demoType );
1317
+ jQuery('.required-plugins-wrap').remove();
1318
+ }
1319
+
1320
+ return;
1321
+ },
1322
+
1323
+ /**
1324
+ * Enable Demo Import Button.
1325
+ */
1326
+ _enable_demo_import_button: function( type ) {
1327
+
1328
+ type = ( undefined !== type ) ? type : 'free';
1329
+
1330
+ $('.install-theme-info .theme-details .site-description').remove();
1331
+
1332
+ switch( type ) {
1333
+
1334
+ case 'free':
1335
+ var all_buttons = parseInt( jQuery( '.plugin-card .button' ).length ) || 0,
1336
+ disabled_buttons = parseInt( jQuery( '.plugin-card .button.disabled' ).length ) || 0;
1337
+
1338
+ if( all_buttons === disabled_buttons ) {
1339
+
1340
+ // XML reader not available notice.
1341
+ if( astraSitesAdmin.XMLReaderDisabled ) {
1342
+ if( ! $('.install-theme-info .astra-sites-xml-notice').length ) {
1343
+ $('.install-theme-info').prepend( astraSitesAdmin.strings.warningXMLReader );
1344
+ }
1345
+ $('.astra-demo-import')
1346
+ .removeClass('installing updating-message')
1347
+ .addClass('disabled')
1348
+ .text( astraSitesAdmin.strings.importDemo );
1349
+ } else {
1350
+ $('.astra-demo-import')
1351
+ .removeAttr('data-import')
1352
+ .removeClass('installing updating-message')
1353
+ .addClass('button-primary')
1354
+ .text( astraSitesAdmin.strings.importDemo );
1355
+ }
1356
+ }
1357
+
1358
+ break;
1359
+
1360
+ case 'upgrade':
1361
+ var demo_slug = jQuery('.wp-full-overlay-header').attr('data-demo-slug');
1362
+
1363
+ jQuery('.astra-demo-import')
1364
+ .addClass('go-pro button-primary')
1365
+ .removeClass('astra-demo-import')
1366
+ .attr('target', '_blank')
1367
+ .attr('href', astraSitesAdmin.getUpgradeURL + demo_slug )
1368
+ .text( astraSitesAdmin.getUpgradeText )
1369
+ .append('<i class="dashicons dashicons-external"></i>');
1370
+
1371
+ break;
1372
+
1373
+ default:
1374
+ var demo_slug = jQuery('.wp-full-overlay-header').attr('data-demo-slug');
1375
+
1376
+ jQuery('.astra-demo-import')
1377
+ .addClass('go-pro button-primary')
1378
+ .removeClass('astra-demo-import')
1379
+ .attr('target', '_blank')
1380
+ .attr('href', astraSitesAdmin.getProURL )
1381
+ .text( astraSitesAdmin.getProText )
1382
+ .append('<i class="dashicons dashicons-external"></i>');
1383
+
1384
+ if( false == astraSitesAdmin.isWhiteLabeled ) {
1385
+ if( astraSitesAdmin.isPro ) {
1386
+ $('.install-theme-info .theme-details').prepend( wp.template('astra-sites-pro-inactive-site-description') );
1387
+ } else {
1388
+ $('.install-theme-info .theme-details').prepend( wp.template('astra-sites-pro-site-description') );
1389
+ }
1390
+ }
1391
+
1392
+ break;
1393
+ }
1394
+
1395
+ },
1396
+
1397
+ /**
1398
+ * Update Page Count.
1399
+ */
1400
+ _updatedPagedCount: function() {
1401
+ paged = parseInt(jQuery('body').attr('data-astra-demo-paged'));
1402
+ jQuery('body').attr('data-astra-demo-paged', paged + 1);
1403
+ window.setTimeout(function () {
1404
+ jQuery('body').data('scrolling', false);
1405
+ }, 800);
1406
+ },
1407
+
1408
+ /**
1409
+ * Reset Page Count.
1410
+ */
1411
+ _resetPagedCount: function() {
1412
+
1413
+ $('body').addClass('loading-content');
1414
+ $('body').attr('data-astra-demo-last-request', '1');
1415
+ $('body').attr('data-astra-demo-paged', '1');
1416
+ $('body').attr('data-astra-demo-search', '');
1417
+ $('body').attr('data-scrolling', false);
1418
+
1419
+ },
1420
+
1421
+ /**
1422
+ * Remove plugin from the queue.
1423
+ */
1424
+ _removePluginFromQueue: function( removeItem, pluginsList ) {
1425
+ return jQuery.grep(pluginsList, function( value ) {
1426
+ return value.slug != removeItem;
1427
+ });
1428
+ }
1429
+
1430
+ };
1431
+
1432
+ /**
1433
+ * Initialize AstraSitesAdmin
1434
+ */
1435
+ $(function(){
1436
+ AstraSitesAdmin.init();
1437
+ });
1438
+
1439
  })(jQuery);
inc/assets/js/astra-sites-api.js CHANGED
@@ -1,57 +1,57 @@
1
-
2
- (function($){
3
-
4
- AstraSitesAPI = {
5
-
6
- _api_url : astraSitesApi.ApiURL,
7
-
8
- /**
9
- * API Request
10
- */
11
- _api_request: function( args ) {
12
-
13
- // Set API Request Data.
14
- var data = {
15
- url: AstraSitesAPI._api_url + args.slug,
16
- };
17
-
18
- if( astraRenderGrid.headers ) {
19
- data.headers = astraRenderGrid.headers;
20
- }
21
-
22
- $.ajax( data )
23
- .done(function( items, status, XHR ) {
24
-
25
- if( 'success' === status && XHR.getResponseHeader('x-wp-total') ) {
26
-
27
- var data = {
28
- args : args,
29
- items : items,
30
- items_count : XHR.getResponseHeader('x-wp-total') || 0,
31
- };
32
-
33
- if( 'undefined' !== args.trigger && '' !== args.trigger ) {
34
- $(document).trigger( args.trigger, [data] );
35
- }
36
-
37
- } else {
38
- $(document).trigger( 'astra-sites-api-request-error' );
39
- }
40
-
41
- })
42
- .fail(function( jqXHR, textStatus ) {
43
-
44
- $(document).trigger( 'astra-sites-api-request-fail', [jqXHR, textStatus, args] );
45
-
46
- })
47
- .always(function() {
48
-
49
- $(document).trigger( 'astra-sites-api-request-always' );
50
-
51
- });
52
-
53
- },
54
-
55
- };
56
-
57
  })(jQuery);
1
+
2
+ (function($){
3
+
4
+ AstraSitesAPI = {
5
+
6
+ _api_url : astraSitesApi.ApiURL,
7
+
8
+ /**
9
+ * API Request
10
+ */
11
+ _api_request: function( args ) {
12
+
13
+ // Set API Request Data.
14
+ var data = {
15
+ url: AstraSitesAPI._api_url + args.slug,
16
+ };
17
+
18
+ if( astraRenderGrid.headers ) {
19
+ data.headers = astraRenderGrid.headers;
20
+ }
21
+
22
+ $.ajax( data )
23
+ .done(function( items, status, XHR ) {
24
+
25
+ if( 'success' === status && XHR.getResponseHeader('x-wp-total') ) {
26
+
27
+ var data = {
28
+ args : args,
29
+ items : items,
30
+ items_count : XHR.getResponseHeader('x-wp-total') || 0,
31
+ };
32
+
33
+ if( 'undefined' !== args.trigger && '' !== args.trigger ) {
34
+ $(document).trigger( args.trigger, [data] );
35
+ }
36
+
37
+ } else {
38
+ $(document).trigger( 'astra-sites-api-request-error' );
39
+ }
40
+
41
+ })
42
+ .fail(function( jqXHR, textStatus ) {
43
+
44
+ $(document).trigger( 'astra-sites-api-request-fail', [jqXHR, textStatus, args] );
45
+
46
+ })
47
+ .always(function() {
48
+
49
+ $(document).trigger( 'astra-sites-api-request-always' );
50
+
51
+ });
52
+
53
+ },
54
+
55
+ };
56
+
57
  })(jQuery);
inc/assets/js/astra-sites-notices.js CHANGED
@@ -1,21 +1,21 @@
1
- jQuery(document).ready(function ($) {
2
-
3
- jQuery( '.astra-notice.is-dismissible .notice-dismiss' ).on( 'click', function() {
4
- var $id = jQuery( this ).attr( 'id' ) || '';
5
- var $time = jQuery( this ).attr( 'dismissible-time' ) || '';
6
- var $meta = jQuery( this ).attr( 'dismissible-meta' ) || '';
7
-
8
- jQuery.ajax({
9
- url: ajaxurl,
10
- type: 'POST',
11
- data: {
12
- action : 'astra-notices',
13
- id : $id,
14
- meta : $meta,
15
- time : $time,
16
- },
17
- });
18
-
19
- });
20
-
21
  });
1
+ jQuery(document).ready(function ($) {
2
+
3
+ jQuery( '.astra-notice.is-dismissible .notice-dismiss' ).on( 'click', function() {
4
+ var $id = jQuery( this ).attr( 'id' ) || '';
5
+ var $time = jQuery( this ).attr( 'dismissible-time' ) || '';
6
+ var $meta = jQuery( this ).attr( 'dismissible-meta' ) || '';
7
+
8
+ jQuery.ajax({
9
+ url: ajaxurl,
10
+ type: 'POST',
11
+ data: {
12
+ action : 'astra-notices',
13
+ id : $id,
14
+ meta : $meta,
15
+ time : $time,
16
+ },
17
+ });
18
+
19
+ });
20
+
21
  });
inc/assets/js/eventsource.js CHANGED
@@ -1,673 +1,673 @@
1
- /** @license
2
- * eventsource.js
3
- * Available under MIT License (MIT)
4
- * https://github.com/Yaffle/EventSource/
5
- */
6
-
7
- /*jslint indent: 2, vars: true, plusplus: true */
8
- /*global setTimeout, clearTimeout */
9
-
10
- (function (global) {
11
- "use strict";
12
-
13
- var setTimeout = global.setTimeout;
14
- var clearTimeout = global.clearTimeout;
15
- var XMLHttpRequest = global.XMLHttpRequest;
16
- var XDomainRequest = global.XDomainRequest;
17
- var NativeEventSource = global.EventSource;
18
- var document = global.document;
19
-
20
- if (Object.create == null) {
21
- Object.create = function (C) {
22
- function F(){}
23
- F.prototype = C;
24
- return new F();
25
- };
26
- }
27
-
28
- var k = function () {
29
- };
30
-
31
- function XHRWrapper(xhr) {
32
- this.withCredentials = false;
33
- this.responseType = "";
34
- this.readyState = 0;
35
- this.status = 0;
36
- this.statusText = "";
37
- this.responseText = "";
38
- this.onprogress = k;
39
- this.onreadystatechange = k;
40
- this._contentType = "";
41
- this._xhr = xhr;
42
- this._sendTimeout = 0;
43
- this._abort = k;
44
- }
45
-
46
- XHRWrapper.prototype.open = function (method, url) {
47
- this._abort(true);
48
-
49
- var that = this;
50
- var xhr = this._xhr;
51
- var state = 1;
52
- var timeout = 0;
53
-
54
- this._abort = function (silent) {
55
- if (that._sendTimeout !== 0) {
56
- clearTimeout(that._sendTimeout);
57
- that._sendTimeout = 0;
58
- }
59
- if (state === 1 || state === 2 || state === 3) {
60
- state = 4;
61
- xhr.onload = k;
62
- xhr.onerror = k;
63
- xhr.onabort = k;
64
- xhr.onprogress = k;
65
- xhr.onreadystatechange = k;
66
- // IE 8 - 9: XDomainRequest#abort() does not fire any event
67
- // Opera < 10: XMLHttpRequest#abort() does not fire any event
68
- xhr.abort();
69
- if (timeout !== 0) {
70
- clearTimeout(timeout);
71
- timeout = 0;
72
- }
73
- if (!silent) {
74
- that.readyState = 4;
75
- that.onreadystatechange();
76
- }
77
- }
78
- state = 0;
79
- };
80
-
81
- var onStart = function () {
82
- if (state === 1) {
83
- //state = 2;
84
- var status = 0;
85
- var statusText = "";
86
- var contentType = undefined;
87
- if (!("contentType" in xhr)) {
88
- try {
89
- status = xhr.status;
90
- statusText = xhr.statusText;
91
- contentType = xhr.getResponseHeader("Content-Type");
92
- } catch (error) {
93
- // IE < 10 throws exception for `xhr.status` when xhr.readyState === 2 || xhr.readyState === 3
94
- // Opera < 11 throws exception for `xhr.status` when xhr.readyState === 2
95
- // https://bugs.webkit.org/show_bug.cgi?id=29121
96
- status = 0;
97
- statusText = "";
98
- contentType = undefined;
99
- // Firefox < 14, Chrome ?, Safari ?
100
- // https://bugs.webkit.org/show_bug.cgi?id=29658
101
- // https://bugs.webkit.org/show_bug.cgi?id=77854
102
- }
103
- } else {
104
- status = 200;
105
- statusText = "OK";
106
- contentType = xhr.contentType;
107
- }
108
- if (status !== 0) {
109
- state = 2;
110
- that.readyState = 2;
111
- that.status = status;
112
- that.statusText = statusText;
113
- that._contentType = contentType;
114
- that.onreadystatechange();
115
- }
116
- }
117
- };
118
- var onProgress = function () {
119
- onStart();
120
- if (state === 2 || state === 3) {
121
- state = 3;
122
- var responseText = "";
123
- try {
124
- responseText = xhr.responseText;
125
- } catch (error) {
126
- // IE 8 - 9 with XMLHttpRequest
127
- }
128
- that.readyState = 3;
129
- that.responseText = responseText;
130
- that.onprogress();
131
- }
132
- };
133
- var onFinish = function () {
134
- // Firefox 52 fires "readystatechange" (xhr.readyState === 4) without final "readystatechange" (xhr.readyState === 3)
135
- // IE 8 fires "onload" without "onprogress"
136
- onProgress();
137
- if (state === 1 || state === 2 || state === 3) {
138
- state = 4;
139
- if (timeout !== 0) {
140
- clearTimeout(timeout);
141
- timeout = 0;
142
- }
143
- that.readyState = 4;
144
- that.onreadystatechange();
145
- }
146
- };
147
- var onReadyStateChange = function () {
148
- if (xhr != undefined) { // Opera 12
149
- if (xhr.readyState === 4) {
150
- onFinish();
151
- } else if (xhr.readyState === 3) {
152
- onProgress();
153
- } else if (xhr.readyState === 2) {
154
- onStart();
155
- }
156
- }
157
- };
158
- var onTimeout = function () {
159
- timeout = setTimeout(function () {
160
- onTimeout();
161
- }, 500);
162
- if (xhr.readyState === 3) {
163
- onProgress();
164
- }
165
- };
166
-
167
- // XDomainRequest#abort removes onprogress, onerror, onload
168
- xhr.onload = onFinish;
169
- xhr.onerror = onFinish;
170
- // improper fix to match Firefox behaviour, but it is better than just ignore abort
171
- // see https://bugzilla.mozilla.org/show_bug.cgi?id=768596
172
- // https://bugzilla.mozilla.org/show_bug.cgi?id=880200
173
- // https://code.google.com/p/chromium/issues/detail?id=153570
174
- // IE 8 fires "onload" without "onprogress
175
- xhr.onabort = onFinish;
176
-
177
- // https://bugzilla.mozilla.org/show_bug.cgi?id=736723
178
- if (!("sendAsBinary" in XMLHttpRequest.prototype) && !("mozAnon" in XMLHttpRequest.prototype)) {
179
- xhr.onprogress = onProgress;
180
- }
181
-
182
- // IE 8 - 9 (XMLHTTPRequest)
183
- // Opera < 12
184
- // Firefox < 3.5
185
- // Firefox 3.5 - 3.6 - ? < 9.0
186
- // onprogress is not fired sometimes or delayed
187
- // see also #64
188
- xhr.onreadystatechange = onReadyStateChange;
189
-
190
- if ("contentType" in xhr) {
191
- url += (url.indexOf("?", 0) === -1 ? "?" : "&") + "padding=true";
192
- }
193
- xhr.open(method, url, true);
194
-
195
- if ("readyState" in xhr) {
196
- // workaround for Opera 12 issue with "progress" events
197
- // #91
198
- timeout = setTimeout(function () {
199
- onTimeout();
200
- }, 0);
201
- }
202
- };
203
- XHRWrapper.prototype.abort = function () {
204
- this._abort(false);
205
- };
206
- XHRWrapper.prototype.getResponseHeader = function (name) {
207
- return this._contentType;
208
- };
209
- XHRWrapper.prototype.setRequestHeader = function (name, value) {
210
- var xhr = this._xhr;
211
- if ("setRequestHeader" in xhr) {
212
- xhr.setRequestHeader(name, value);
213
- }
214
- };
215
- XHRWrapper.prototype.send = function () {
216
- // loading indicator in Safari < ? (6), Chrome < 14, Firefox
217
- if (!("ontimeout" in XMLHttpRequest.prototype) &&
218
- document != undefined &&
219
- document.readyState != undefined &&
220
- document.readyState !== "complete") {
221
- var that = this;
222
- that._sendTimeout = setTimeout(function () {
223
- that._sendTimeout = 0;
224
- that.send();
225
- }, 4);
226
- return;
227
- }
228
-
229
- var xhr = this._xhr;
230
- // withCredentials should be set after "open" for Safari and Chrome (< 19 ?)
231
- xhr.withCredentials = this.withCredentials;
232
- xhr.responseType = this.responseType;
233
- try {
234
- // xhr.send(); throws "Not enough arguments" in Firefox 3.0
235
- xhr.send(undefined);
236
- } catch (error1) {
237
- // Safari 5.1.7, Opera 12
238
- throw error1;
239
- }
240
- };
241
-
242
- function XHRTransport(xhr) {
243
- this._xhr = new XHRWrapper(xhr);
244
- }
245
-
246
- XHRTransport.prototype.open = function (onStartCallback, onProgressCallback, onFinishCallback, url, withCredentials, headers) {
247
- var xhr = this._xhr;
248
- xhr.open("GET", url);
249
- var offset = 0;
250
- xhr.onprogress = function () {
251
- var responseText = xhr.responseText;
252
- var chunk = responseText.slice(offset);
253
- offset += chunk.length;
254
- onProgressCallback(chunk);
255
- };
256
- xhr.onreadystatechange = function () {
257
- if (xhr.readyState === 2) {
258
- var status = xhr.status;
259
- var statusText = xhr.statusText;
260
- var contentType = xhr.getResponseHeader("Content-Type");
261
- onStartCallback(status, statusText, contentType);
262
- } else if (xhr.readyState === 4) {
263
- onFinishCallback();
264
- }
265
- };
266
- xhr.withCredentials = withCredentials;
267
- xhr.responseType = "text";
268
- for (var name in headers) {
269
- if (Object.prototype.hasOwnProperty.call(headers, name)) {
270
- xhr.setRequestHeader(name, headers[name]);
271
- }
272
- }
273
- xhr.send();
274
- };
275
-
276
- XHRTransport.prototype.cancel = function () {
277
- var xhr = this._xhr;
278
- xhr.abort();
279
- };
280
-
281
- function EventTarget() {
282
- this._listeners = Object.create(null);
283
- }
284
-
285
- function throwError(e) {
286
- setTimeout(function () {
287
- throw e;
288
- }, 0);
289
- }
290
-
291
- EventTarget.prototype.dispatchEvent = function (event) {
292
- event.target = this;
293
- var typeListeners = this._listeners[event.type];
294
- if (typeListeners != undefined) {
295
- var length = typeListeners.length;
296
- for (var i = 0; i < length; i += 1) {
297
- var listener = typeListeners[i];
298
- try {
299
- if (typeof listener.handleEvent === "function") {
300
- listener.handleEvent(event);
301
- } else {
302
- listener.call(this, event);
303
- }
304
- } catch (e) {
305
- throwError(e);
306
- }
307
- }
308
- }
309
- };
310
- EventTarget.prototype.addEventListener = function (type, listener) {
311
- type = String(type);
312
- var listeners = this._listeners;
313
- var typeListeners = listeners[type];
314
- if (typeListeners == undefined) {
315
- typeListeners = [];
316
- listeners[type] = typeListeners;
317
- }
318
- var found = false;
319
- for (var i = 0; i < typeListeners.length; i += 1) {
320
- if (typeListeners[i] === listener) {
321
- found = true;
322
- }
323
- }
324
- if (!found) {
325
- typeListeners.push(listener);
326
- }
327
- };
328
- EventTarget.prototype.removeEventListener = function (type, listener) {
329
- type = String(type);
330
- var listeners = this._listeners;
331
- var typeListeners = listeners[type];
332
- if (typeListeners != undefined) {
333
- var filtered = [];
334
- for (var i = 0; i < typeListeners.length; i += 1) {
335
- if (typeListeners[i] !== listener) {
336
- filtered.push(typeListeners[i]);
337
- }
338
- }
339
- if (filtered.length === 0) {
340
- delete listeners[type];
341
- } else {
342
- listeners[type] = filtered;
343
- }
344
- }
345
- };
346
-
347
- function Event(type) {
348
- this.type = type;
349
- this.target = undefined;
350
- }
351
-
352
- function MessageEvent(type, options) {
353
- Event.call(this, type);
354
- this.data = options.data;
355
- this.lastEventId = options.lastEventId;
356
- }
357
-
358
- MessageEvent.prototype = Object.create(Event.prototype);
359
-
360
- var WAITING = -1;
361
- var CONNECTING = 0;
362
- var OPEN = 1;
363
- var CLOSED = 2;
364
-
365
- var AFTER_CR = -1;
366
- var FIELD_START = 0;
367
- var FIELD = 1;
368
- var VALUE_START = 2;
369
- var VALUE = 3;
370
-
371
- var contentTypeRegExp = /^text\/event\-stream;?(\s*charset\=utf\-8)?$/i;
372
-
373
- var MINIMUM_DURATION = 1000;
374
- var MAXIMUM_DURATION = 18000000;
375
-
376
- var parseDuration = function (value, def) {
377
- var n = parseInt(value, 10);
378
- if (n !== n) {
379
- n = def;
380
- }
381
- return clampDuration(n);
382
- };
383
- var clampDuration = function (n) {
384
- return Math.min(Math.max(n, MINIMUM_DURATION), MAXIMUM_DURATION);
385
- };
386
-
387
- var fire = function (that, f, event) {
388
- try {
389
- if (typeof f === "function") {
390
- f.call(that, event);
391
- }
392
- } catch (e) {
393
- throwError(e);
394
- }
395
- };
396
-
397
- function EventSourcePolyfill(url, options) {
398
- EventTarget.call(this);
399
-
400
- this.onopen = undefined;
401
- this.onmessage = undefined;
402
- this.onerror = undefined;
403
-
404
- this.url = undefined;
405
- this.readyState = undefined;
406
- this.withCredentials = undefined;
407
-
408
- this._close = undefined;
409
-
410
- start(this, url, options);
411
- }
412
-
413
- function start(es, url, options) {
414
- url = String(url);
415
- var withCredentials = options != undefined && Boolean(options.withCredentials);
416
-
417
- var initialRetry = clampDuration(1000);
418
- var heartbeatTimeout = clampDuration(45000);
419
-
420
- var lastEventId = "";
421
- var retry = initialRetry;
422
- var wasActivity = false;
423
- var headers = options != undefined && options.headers != undefined ? JSON.parse(JSON.stringify(options.headers)) : undefined;
424
- var CurrentTransport = options != undefined && options.Transport != undefined ? options.Transport : (XDomainRequest != undefined ? XDomainRequest : XMLHttpRequest);
425
- var transport = new XHRTransport(new CurrentTransport());
426
- var timeout = 0;
427
- var currentState = WAITING;
428
- var dataBuffer = "";
429
- var lastEventIdBuffer = "";
430
- var eventTypeBuffer = "";
431
-
432
- var textBuffer = "";
433
- var state = FIELD_START;
434
- var fieldStart = 0;
435
- var valueStart = 0;
436
-
437
- var onStart = function (status, statusText, contentType) {
438
- if (currentState === CONNECTING) {
439
- if (status === 200 && contentType != undefined && contentTypeRegExp.test(contentType)) {
440
- currentState = OPEN;
441
- wasActivity = true;
442
- retry = initialRetry;
443
- es.readyState = OPEN;
444
- var event = new Event("open");
445
- es.dispatchEvent(event);
446
- fire(es, es.onopen, event);
447
- } else {
448
- var message = "";
449
- if (status !== 200) {
450
- if (statusText) {
451
- statusText = statusText.replace(/\s+/g, " ");
452
- }
453
- message = "EventSource's response has a status " + status + " " + statusText + " that is not 200. Aborting the connection.";
454
- } else {
455
- message = "EventSource's response has a Content-Type specifying an unsupported type: " + (contentType == undefined ? "-" : contentType.replace(/\s+/g, " ")) + ". Aborting the connection.";
456
- }
457
- throwError(new Error(message));
458
- close();
459
- var event = new Event("error");
460
- es.dispatchEvent(event);
461
- fire(es, es.onerror, event);
462
- }
463
- }
464
- };
465
-
466
- var onProgress = function (textChunk) {
467
- if (currentState === OPEN) {
468
- var n = -1;
469
- for (var i = 0; i < textChunk.length; i += 1) {
470
- var c = textChunk.charCodeAt(i);
471
- if (c === "\n".charCodeAt(0) || c === "\r".charCodeAt(0)) {
472
- n = i;
473
- }
474
- }
475
- var chunk = (n !== -1 ? textBuffer : "") + textChunk.slice(0, n + 1);
476
- textBuffer = (n === -1 ? textBuffer : "") + textChunk.slice(n + 1);
477
- if (chunk !== "") {
478
- wasActivity = true;
479
- }
480
- for (var position = 0; position < chunk.length; position += 1) {
481
- var c = chunk.charCodeAt(position);
482
- if (state === AFTER_CR && c === "\n".charCodeAt(0)) {
483
- state = FIELD_START;
484
- } else {
485
- if (state === AFTER_CR) {
486
- state = FIELD_START;
487
- }
488
- if (c === "\r".charCodeAt(0) || c === "\n".charCodeAt(0)) {
489
- if (state !== FIELD_START) {
490
- if (state === FIELD) {
491
- valueStart = position + 1;
492
- }
493
- var field = chunk.slice(fieldStart, valueStart - 1);
494
- var value = chunk.slice(valueStart + (valueStart < position && chunk.charCodeAt(valueStart) === " ".charCodeAt(0) ? 1 : 0), position);
495
- if (field === "data") {
496
- dataBuffer += "\n";
497
- dataBuffer += value;
498
- } else if (field === "id") {
499
- lastEventIdBuffer = value;
500
- } else if (field === "event") {
501
- eventTypeBuffer = value;
502
- } else if (field === "retry") {
503
- initialRetry = parseDuration(value, initialRetry);
504
- retry = initialRetry;
505
- } else if (field === "heartbeatTimeout") {
506
- heartbeatTimeout = parseDuration(value, heartbeatTimeout);
507
- if (timeout !== 0) {
508
- clearTimeout(timeout);
509
- timeout = setTimeout(function () {
510
- onTimeout();
511
- }, heartbeatTimeout);
512
- }
513
- }
514
- }
515
- if (state === FIELD_START) {
516
- if (dataBuffer !== "") {
517
- lastEventId = lastEventIdBuffer;
518
- if (eventTypeBuffer === "") {
519
- eventTypeBuffer = "message";
520
- }
521
- var event = new MessageEvent(eventTypeBuffer, {
522
- data: dataBuffer.slice(1),
523
- lastEventId: lastEventIdBuffer
524
- });
525
- es.dispatchEvent(event);
526
- if (eventTypeBuffer === "message") {
527
- fire(es, es.onmessage, event);
528
- }
529
- if (currentState === CLOSED) {
530
- return;
531
- }
532
- }
533
- dataBuffer = "";
534
- eventTypeBuffer = "";
535
- }
536
- state = c === "\r".charCodeAt(0) ? AFTER_CR : FIELD_START;
537
- } else {
538
- if (state === FIELD_START) {
539
- fieldStart = position;
540
- state = FIELD;
541
- }
542
- if (state === FIELD) {
543
- if (c === ":".charCodeAt(0)) {
544
- valueStart = position + 1;
545
- state = VALUE_START;
546
- }
547
- } else if (state === VALUE_START) {
548
- state = VALUE;
549
- }
550
- }
551
- }
552
- }
553
- }
554
- };
555
-
556
- var onFinish = function () {
557
- if (currentState === OPEN || currentState === CONNECTING) {
558
- currentState = WAITING;
559
- if (timeout !== 0) {
560
- clearTimeout(timeout);
561
- timeout = 0;
562
- }
563
- timeout = setTimeout(function () {
564
- onTimeout();
565
- }, retry);
566
- retry = clampDuration(Math.min(initialRetry * 16, retry * 2));
567
-
568
- es.readyState = CONNECTING;
569
- var event = new Event("error");
570
- es.dispatchEvent(event);
571
- fire(es, es.onerror, event);
572
- }
573
- };
574
-
575
- var close = function () {
576
- currentState = CLOSED;
577
- transport.cancel();
578
- if (timeout !== 0) {
579
- clearTimeout(timeout);
580
- timeout = 0;
581
- }
582
- es.readyState = CLOSED;
583
- };
584
-
585
- var onTimeout = function () {
586
- timeout = 0;
587
-
588
- if (currentState !== WAITING) {
589
- if (!wasActivity) {
590
- throwError(new Error("No activity within " + heartbeatTimeout + " milliseconds. Reconnecting."));
591
- transport.cancel();
592
- } else {
593
- wasActivity = false;
594
- timeout = setTimeout(function () {
595
- onTimeout();
596
- }, heartbeatTimeout);
597
- }
598
- return;
599
- }
600
-
601
- wasActivity = false;
602
- timeout = setTimeout(function () {
603
- onTimeout();
604
- }, heartbeatTimeout);
605
-
606
- currentState = CONNECTING;
607
- dataBuffer = "";
608
- eventTypeBuffer = "";
609
- lastEventIdBuffer = lastEventId;
610
- textBuffer = "";
611
- fieldStart = 0;
612
- valueStart = 0;
613
- state = FIELD_START;
614
-
615
- // https://bugzilla.mozilla.org/show_bug.cgi?id=428916
616
- // Request header field Last-Event-ID is not allowed by Access-Control-Allow-Headers.
617
- var requestURL = url;
618
- if (url.slice(0, 5) !== "data:" &&
619
- url.slice(0, 5) !== "blob:") {
620
- requestURL = url + (url.indexOf("?", 0) === -1 ? "?" : "&") + "lastEventId=" + encodeURIComponent(lastEventId);
621
- }
622
- var requestHeaders = {};
623
- requestHeaders["Accept"] = "text/event-stream";
624
- if (headers != undefined) {
625
- for (var name in headers) {
626
- if (Object.prototype.hasOwnProperty.call(headers, name)) {
627
- requestHeaders[name] = headers[name];
628
- }
629
- }
630
- }
631
- try {
632
- transport.open(onStart, onProgress, onFinish, requestURL, withCredentials, requestHeaders);
633
- } catch (error) {
634
- close();
635
- throw error;
636
- }
637
- };
638
-
639
- es.url = url;
640
- es.readyState = CONNECTING;
641
- es.withCredentials = withCredentials;
642
- es._close = close;
643
-
644
- onTimeout();
645
- }
646
-
647
- EventSourcePolyfill.prototype = Object.create(EventTarget.prototype);
648
- EventSourcePolyfill.prototype.CONNECTING = CONNECTING;
649
- EventSourcePolyfill.prototype.OPEN = OPEN;
650
- EventSourcePolyfill.prototype.CLOSED = CLOSED;
651
- EventSourcePolyfill.prototype.close = function () {
652
- this._close();
653
- };
654
-
655
- EventSourcePolyfill.CONNECTING = CONNECTING;
656
- EventSourcePolyfill.OPEN = OPEN;
657
- EventSourcePolyfill.CLOSED = CLOSED;
658
- EventSourcePolyfill.prototype.withCredentials = undefined;
659
-
660
- global.EventSourcePolyfill = EventSourcePolyfill;
661
- global.NativeEventSource = NativeEventSource;
662
-
663
- if (XMLHttpRequest != undefined && (NativeEventSource == undefined || !("withCredentials" in NativeEventSource.prototype))) {
664
- // Why replace a native EventSource ?
665
- // https://bugzilla.mozilla.org/show_bug.cgi?id=444328
666
- // https://bugzilla.mozilla.org/show_bug.cgi?id=831392
667
- // https://code.google.com/p/chromium/issues/detail?id=260144
668
- // https://code.google.com/p/chromium/issues/detail?id=225654
669
- // ...
670
- global.EventSource = EventSourcePolyfill;
671
- }
672
-
673
- }(typeof window !== 'undefined' ? window : this));
1
+ /** @license
2
+ * eventsource.js
3
+ * Available under MIT License (MIT)
4
+ * https://github.com/Yaffle/EventSource/
5
+ */
6
+
7
+ /*jslint indent: 2, vars: true, plusplus: true */
8
+ /*global setTimeout, clearTimeout */
9
+
10
+ (function (global) {
11
+ "use strict";
12
+
13
+ var setTimeout = global.setTimeout;
14
+ var clearTimeout = global.clearTimeout;
15
+ var XMLHttpRequest = global.XMLHttpRequest;
16
+ var XDomainRequest = global.XDomainRequest;
17
+ var NativeEventSource = global.EventSource;
18
+ var document = global.document;
19
+
20
+ if (Object.create == null) {
21
+ Object.create = function (C) {
22
+ function F(){}
23
+ F.prototype = C;
24
+ return new F();
25
+ };
26
+ }
27
+
28
+ var k = function () {
29
+ };
30
+
31
+ function XHRWrapper(xhr) {
32
+ this.withCredentials = false;
33
+ this.responseType = "";
34
+ this.readyState = 0;
35
+ this.status = 0;
36
+ this.statusText = "";
37
+ this.responseText = "";
38
+ this.onprogress = k;
39
+ this.onreadystatechange = k;
40
+ this._contentType = "";
41
+ this._xhr = xhr;
42
+ this._sendTimeout = 0;
43
+ this._abort = k;
44
+ }
45
+
46
+ XHRWrapper.prototype.open = function (method, url) {
47
+ this._abort(true);
48
+
49
+ var that = this;
50
+ var xhr = this._xhr;
51
+ var state = 1;
52
+ var timeout = 0;
53
+
54
+ this._abort = function (silent) {
55
+ if (that._sendTimeout !== 0) {
56
+ clearTimeout(that._sendTimeout);
57
+ that._sendTimeout = 0;
58
+ }
59
+ if (state === 1 || state === 2 || state === 3) {
60
+ state = 4;
61
+ xhr.onload = k;
62
+ xhr.onerror = k;
63
+ xhr.onabort = k;
64
+ xhr.onprogress = k;
65
+ xhr.onreadystatechange = k;
66
+ // IE 8 - 9: XDomainRequest#abort() does not fire any event
67
+ // Opera < 10: XMLHttpRequest#abort() does not fire any event
68
+ xhr.abort();
69
+ if (timeout !== 0) {
70
+ clearTimeout(timeout);
71
+ timeout = 0;
72
+ }
73
+ if (!silent) {
74
+ that.readyState = 4;
75
+ that.onreadystatechange();
76
+ }
77
+ }
78
+ state = 0;
79
+ };
80
+
81
+ var onStart = function () {
82
+ if (state === 1) {
83
+ //state = 2;
84
+ var status = 0;
85
+ var statusText = "";
86
+ var contentType = undefined;
87
+ if (!("contentType" in xhr)) {
88
+ try {
89
+ status = xhr.status;
90
+ statusText = xhr.statusText;
91
+ contentType = xhr.getResponseHeader("Content-Type");
92
+ } catch (error) {
93
+ // IE < 10 throws exception for `xhr.status` when xhr.readyState === 2 || xhr.readyState === 3
94
+ // Opera < 11 throws exception for `xhr.status` when xhr.readyState === 2
95
+ // https://bugs.webkit.org/show_bug.cgi?id=29121
96
+ status = 0;
97
+ statusText = "";
98
+ contentType = undefined;
99
+ // Firefox < 14, Chrome ?, Safari ?
100
+ // https://bugs.webkit.org/show_bug.cgi?id=29658
101
+ // https://bugs.webkit.org/show_bug.cgi?id=77854
102
+ }
103
+ } else {
104
+ status = 200;
105
+ statusText = "OK";
106
+ contentType = xhr.contentType;
107
+ }
108
+ if (status !== 0) {
109
+ state = 2;
110
+ that.readyState = 2;
111
+ that.status = status;
112
+ that.statusText = statusText;
113
+ that._contentType = contentType;
114
+ that.onreadystatechange();
115
+ }
116
+ }
117
+ };
118
+ var onProgress = function () {
119
+ onStart();
120
+ if (state === 2 || state === 3) {
121
+ state = 3;
122
+ var responseText = "";
123
+ try {
124
+ responseText = xhr.responseText;
125
+ } catch (error) {
126
+ // IE 8 - 9 with XMLHttpRequest
127
+ }
128
+ that.readyState = 3;
129
+ that.responseText = responseText;
130
+ that.onprogress();
131
+ }
132
+ };
133
+ var onFinish = function () {
134
+ // Firefox 52 fires "readystatechange" (xhr.readyState === 4) without final "readystatechange" (xhr.readyState === 3)
135
+ // IE 8 fires "onload" without "onprogress"
136
+ onProgress();
137
+ if (state === 1 || state === 2 || state === 3) {
138
+ state = 4;
139
+ if (timeout !== 0) {
140
+ clearTimeout(timeout);
141
+ timeout = 0;
142
+ }
143
+ that.readyState = 4;
144
+ that.onreadystatechange();
145
+ }
146
+ };
147
+ var onReadyStateChange = function () {
148
+ if (xhr != undefined) { // Opera 12
149
+ if (xhr.readyState === 4) {
150
+ onFinish();
151
+ } else if (xhr.readyState === 3) {
152
+ onProgress();
153
+ } else if (xhr.readyState === 2) {
154
+ onStart();
155
+ }
156
+ }
157
+ };
158
+ var onTimeout = function () {
159
+ timeout = setTimeout(function () {
160
+ onTimeout();
161
+ }, 500);
162
+ if (xhr.readyState === 3) {
163
+ onProgress();
164
+ }
165
+ };
166
+
167
+ // XDomainRequest#abort removes onprogress, onerror, onload
168
+ xhr.onload = onFinish;
169
+ xhr.onerror = onFinish;
170
+ // improper fix to match Firefox behaviour, but it is better than just ignore abort
171
+ // see https://bugzilla.mozilla.org/show_bug.cgi?id=768596
172
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=880200
173
+ // https://code.google.com/p/chromium/issues/detail?id=153570
174
+ // IE 8 fires "onload" without "onprogress
175
+ xhr.onabort = onFinish;
176
+
177
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=736723
178
+ if (!("sendAsBinary" in XMLHttpRequest.prototype) && !("mozAnon" in XMLHttpRequest.prototype)) {
179
+ xhr.onprogress = onProgress;
180
+ }
181
+
182
+ // IE 8 - 9 (XMLHTTPRequest)
183
+ // Opera < 12
184
+ // Firefox < 3.5
185
+ // Firefox 3.5 - 3.6 - ? < 9.0
186
+ // onprogress is not fired sometimes or delayed
187
+ // see also #64
188
+ xhr.onreadystatechange = onReadyStateChange;
189
+
190
+ if ("contentType" in xhr) {
191
+ url += (url.indexOf("?", 0) === -1 ? "?" : "&") + "padding=true";
192
+ }
193
+ xhr.open(method, url, true);
194
+
195
+ if ("readyState" in xhr) {
196
+ // workaround for Opera 12 issue with "progress" events
197
+ // #91
198
+ timeout = setTimeout(function () {
199
+ onTimeout();
200
+ }, 0);
201
+ }
202
+ };
203
+ XHRWrapper.prototype.abort = function () {
204
+ this._abort(false);
205
+ };
206
+ XHRWrapper.prototype.getResponseHeader = function (name) {
207
+ return this._contentType;
208
+ };
209
+ XHRWrapper.prototype.setRequestHeader = function (name, value) {
210
+ var xhr = this._xhr;
211
+ if ("setRequestHeader" in xhr) {
212
+ xhr.setRequestHeader(name, value);
213
+ }
214
+ };
215
+ XHRWrapper.prototype.send = function () {
216
+ // loading indicator in Safari < ? (6), Chrome < 14, Firefox
217
+ if (!("ontimeout" in XMLHttpRequest.prototype) &&
218
+ document != undefined &&
219
+ document.readyState != undefined &&
220
+ document.readyState !== "complete") {
221
+ var that = this;
222
+ that._sendTimeout = setTimeout(function () {
223
+ that._sendTimeout = 0;
224
+ that.send();
225
+ }, 4);
226
+ return;
227
+ }
228
+
229
+ var xhr = this._xhr;
230
+ // withCredentials should be set after "open" for Safari and Chrome (< 19 ?)
231
+ xhr.withCredentials = this.withCredentials;
232
+ xhr.responseType = this.responseType;
233
+ try {
234
+ // xhr.send(); throws "Not enough arguments" in Firefox 3.0
235
+ xhr.send(undefined);
236
+ } catch (error1) {
237
+ // Safari 5.1.7, Opera 12
238
+ throw error1;
239
+ }
240
+ };
241
+
242
+ function XHRTransport(xhr) {
243
+ this._xhr = new XHRWrapper(xhr);
244
+ }
245
+
246
+ XHRTransport.prototype.open = function (onStartCallback, onProgressCallback, onFinishCallback, url, withCredentials, headers) {
247
+ var xhr = this._xhr;
248
+ xhr.open("GET", url);
249
+ var offset = 0;
250
+ xhr.onprogress = function () {
251
+ var responseText = xhr.responseText;
252
+ var chunk = responseText.slice(offset);
253
+ offset += chunk.length;
254
+ onProgressCallback(chunk);
255
+ };
256
+ xhr.onreadystatechange = function () {
257
+ if (xhr.readyState === 2) {
258
+ var status = xhr.status;
259
+ var statusText = xhr.statusText;
260
+ var contentType = xhr.getResponseHeader("Content-Type");
261
+ onStartCallback(status, statusText, contentType);
262
+ } else if (xhr.readyState === 4) {
263
+ onFinishCallback();
264
+ }
265
+ };
266
+ xhr.withCredentials = withCredentials;
267
+ xhr.responseType = "text";
268
+ for (var name in headers) {
269
+ if (Object.prototype.hasOwnProperty.call(headers, name)) {
270
+ xhr.setRequestHeader(name, headers[name]);
271
+ }
272
+ }
273
+ xhr.send();
274
+ };
275
+
276
+ XHRTransport.prototype.cancel = function () {
277
+ var xhr = this._xhr;
278
+ xhr.abort();
279
+ };
280
+
281
+ function EventTarget() {
282
+ this._listeners = Object.create(null);
283
+ }
284
+
285
+ function throwError(e) {
286
+ setTimeout(function () {
287
+ throw e;
288
+ }, 0);
289
+ }
290
+
291
+ EventTarget.prototype.dispatchEvent = function (event) {
292
+ event.target = this;
293
+ var typeListeners = this._listeners[event.type];
294
+ if (typeListeners != undefined) {
295
+ var length = typeListeners.length;
296
+ for (var i = 0; i < length; i += 1) {
297
+ var listener = typeListeners[i];
298
+ try {
299
+ if (typeof listener.handleEvent === "function") {
300
+ listener.handleEvent(event);
301
+ } else {
302
+ listener.call(this, event);
303
+ }
304
+ } catch (e) {
305
+ throwError(e);
306
+ }
307
+ }
308
+ }
309
+ };
310
+ EventTarget.prototype.addEventListener = function (type, listener) {
311
+ type = String(type);
312
+ var listeners = this._listeners;
313
+ var typeListeners = listeners[type];
314
+ if (typeListeners == undefined) {
315
+ typeListeners = [];
316
+ listeners[type] = typeListeners;
317
+ }
318
+ var found = false;
319
+ for (var i = 0; i < typeListeners.length; i += 1) {
320
+ if (typeListeners[i] === listener) {
321
+ found = true;
322
+ }
323
+ }
324
+ if (!found) {
325
+ typeListeners.push(listener);
326
+ }
327
+ };
328
+ EventTarget.prototype.removeEventListener = function (type, listener) {
329
+ type = String(type);
330
+ var listeners = this._listeners;
331
+ var typeListeners = listeners[type];
332
+ if (typeListeners != undefined) {
333
+ var filtered = [];
334
+ for (var i = 0; i < typeListeners.length; i += 1) {
335
+ if (typeListeners[i] !== listener) {
336
+ filtered.push(typeListeners[i]);
337
+ }
338
+ }
339
+ if (filtered.length === 0) {
340
+ delete listeners[type];
341
+ } else {
342
+ listeners[type] = filtered;
343
+ }
344
+ }
345
+ };
346
+
347
+ function Event(type) {
348
+ this.type = type;
349
+ this.target = undefined;
350
+ }
351
+
352
+ function MessageEvent(type, options) {
353
+ Event.call(this, type);
354
+ this.data = options.data;
355
+ this.lastEventId = options.lastEventId;
356
+ }
357
+
358
+ MessageEvent.prototype = Object.create(Event.prototype);
359
+
360
+ var WAITING = -1;
361
+ var CONNECTING = 0;
362
+ var OPEN = 1;
363
+ var CLOSED = 2;
364
+
365
+ var AFTER_CR = -1;
366
+ var FIELD_START = 0;
367
+ var FIELD = 1;
368
+ var VALUE_START = 2;
369
+ var VALUE = 3;
370
+
371
+ var contentTypeRegExp = /^text\/event\-stream;?(\s*charset\=utf\-8)?$/i;
372
+
373
+ var MINIMUM_DURATION = 1000;
374
+ var MAXIMUM_DURATION = 18000000;
375
+
376
+ var parseDuration = function (value, def) {
377
+ var n = parseInt(value, 10);
378
+ if (n !== n) {
379
+ n = def;
380
+ }
381
+ return clampDuration(n);
382
+ };
383
+ var clampDuration = function (n) {
384
+ return Math.min(Math.max(n, MINIMUM_DURATION), MAXIMUM_DURATION);
385
+ };
386
+
387
+ var fire = function (that, f, event) {
388
+ try {
389
+ if (typeof f === "function") {
390
+ f.call(that, event);
391
+ }
392
+ } catch (e) {
393
+ throwError(e);
394
+ }
395
+ };
396
+
397
+ function EventSourcePolyfill(url, options) {
398
+ EventTarget.call(this);
399
+
400
+ this.onopen = undefined;
401
+ this.onmessage = undefined;
402
+ this.onerror = undefined;
403
+
404
+ this.url = undefined;
405
+ this.readyState = undefined;
406
+ this.withCredentials = undefined;
407
+
408
+ this._close = undefined;
409
+
410
+ start(this, url, options);
411
+ }
412
+
413
+ function start(es, url, options) {
414
+ url = String(url);
415
+ var withCredentials = options != undefined && Boolean(options.withCredentials);
416
+
417
+ var initialRetry = clampDuration(1000);
418
+ var heartbeatTimeout = clampDuration(45000);
419
+
420
+ var lastEventId = "";
421
+ var retry = initialRetry;
422
+ var wasActivity = false;
423
+ var headers = options != undefined && options.headers != undefined ? JSON.parse(JSON.stringify(options.headers)) : undefined;
424
+ var CurrentTransport = options != undefined && options.Transport != undefined ? options.Transport : (XDomainRequest != undefined ? XDomainRequest : XMLHttpRequest);
425
+ var transport = new XHRTransport(new CurrentTransport());
426
+ var timeout = 0;
427
+ var currentState = WAITING;
428
+ var dataBuffer = "";
429
+ var lastEventIdBuffer = "";
430
+ var eventTypeBuffer = "";
431
+
432
+ var textBuffer = "";
433
+ var state = FIELD_START;
434
+ var fieldStart = 0;
435
+ var valueStart = 0;
436
+
437
+ var onStart = function (status, statusText, contentType) {
438
+ if (currentState === CONNECTING) {
439
+ if (status === 200 && contentType != undefined && contentTypeRegExp.test(contentType)) {
440
+ currentState = OPEN;
441
+ wasActivity = true;
442
+ retry = initialRetry;
443
+ es.readyState = OPEN;
444
+ var event = new Event("open");
445
+ es.dispatchEvent(event);
446
+ fire(es, es.onopen, event);
447
+ } else {
448
+ var message = "";
449
+ if (status !== 200) {
450
+ if (statusText) {
451
+ statusText = statusText.replace(/\s+/g, " ");
452
+ }
453
+ message = "EventSource's response has a status " + status + " " + statusText + " that is not 200. Aborting the connection.";
454
+ } else {
455
+ message = "EventSource's response has a Content-Type specifying an unsupported type: " + (contentType == undefined ? "-" : contentType.replace(/\s+/g, " ")) + ". Aborting the connection.";
456
+ }
457
+ throwError(new Error(message));
458
+ close();
459
+ var event = new Event("error");
460
+ es.dispatchEvent(event);
461
+ fire(es, es.onerror, event);
462
+ }
463
+ }
464
+ };
465
+
466
+ var onProgress = function (textChunk) {
467
+ if (currentState === OPEN) {
468
+ var n = -1;
469
+ for (var i = 0; i < textChunk.length; i += 1) {
470
+ var c = textChunk.charCodeAt(i);
471
+ if (c === "\n".charCodeAt(0) || c === "\r".charCodeAt(0)) {
472
+ n = i;
473
+ }
474
+ }
475
+ var chunk = (n !== -1 ? textBuffer : "") + textChunk.slice(0, n + 1);
476
+ textBuffer = (n === -1 ? textBuffer : "") + textChunk.slice(n + 1);
477
+ if (chunk !== "") {
478
+ wasActivity = true;
479
+ }
480
+ for (var position = 0; position < chunk.length; position += 1) {
481
+ var c = chunk.charCodeAt(position);
482
+ if (state === AFTER_CR && c === "\n".charCodeAt(0)) {
483
+ state = FIELD_START;
484
+ } else {
485
+ if (state === AFTER_CR) {
486
+ state = FIELD_START;
487
+ }
488
+ if (c === "\r".charCodeAt(0) || c === "\n".charCodeAt(0)) {
489
+ if (state !== FIELD_START) {
490
+ if (state === FIELD) {
491
+ valueStart = position + 1;
492
+ }
493
+ var field = chunk.slice(fieldStart, valueStart - 1);
494
+ var value = chunk.slice(valueStart + (valueStart < position && chunk.charCodeAt(valueStart) === " ".charCodeAt(0) ? 1 : 0), position);
495
+ if (field === "data") {
496
+ dataBuffer += "\n";
497
+ dataBuffer += value;
498
+ } else if (field === "id") {
499
+ lastEventIdBuffer = value;
500
+ } else if (field === "event") {
501
+ eventTypeBuffer = value;
502
+ } else if (field === "retry") {
503
+ initialRetry = parseDuration(value, initialRetry);
504
+ retry = initialRetry;
505
+ } else if (field === "heartbeatTimeout") {
506
+ heartbeatTimeout = parseDuration(value, heartbeatTimeout);
507
+ if (timeout !== 0) {
508
+ clearTimeout(timeout);
509
+ timeout = setTimeout(function () {
510
+ onTimeout();
511
+ }, heartbeatTimeout);
512
+ }
513
+ }
514
+ }
515
+ if (state === FIELD_START) {
516
+ if (dataBuffer !== "") {
517
+ lastEventId = lastEventIdBuffer;
518
+ if (eventTypeBuffer === "") {
519
+ eventTypeBuffer = "message";
520
+ }
521
+ var event = new MessageEvent(eventTypeBuffer, {
522
+ data: dataBuffer.slice(1),
523
+ lastEventId: lastEventIdBuffer
524
+ });
525
+ es.dispatchEvent(event);
526
+ if (eventTypeBuffer === "message") {
527
+ fire(es, es.onmessage, event);
528
+ }
529
+ if (currentState === CLOSED) {
530
+ return;
531
+ }
532
+ }
533
+ dataBuffer = "";
534
+ eventTypeBuffer = "";
535
+ }
536
+ state = c === "\r".charCodeAt(0) ? AFTER_CR : FIELD_START;
537
+ } else {
538
+ if (state === FIELD_START) {
539
+ fieldStart = position;
540
+ state = FIELD;
541
+ }
542
+ if (state === FIELD) {
543
+ if (c === ":".charCodeAt(0)) {
544
+ valueStart = position + 1;
545
+ state = VALUE_START;
546
+ }
547
+ } else if (state === VALUE_START) {
548
+ state = VALUE;
549
+ }
550
+ }
551
+ }
552
+ }
553
+ }
554
+ };
555
+
556
+ var onFinish = function () {
557
+ if (currentState === OPEN || currentState === CONNECTING) {
558
+ currentState = WAITING;
559
+ if (timeout !== 0) {
560
+ clearTimeout(timeout);
561
+ timeout = 0;
562
+ }
563
+ timeout = setTimeout(function () {
564
+ onTimeout();
565
+ }, retry);
566
+ retry = clampDuration(Math.min(initialRetry * 16, retry * 2));
567
+
568
+ es.readyState = CONNECTING;
569
+ var event = new Event("error");
570
+ es.dispatchEvent(event);
571
+ fire(es, es.onerror, event);
572
+ }
573
+ };
574
+
575
+ var close = function () {
576
+ currentState = CLOSED;
577
+ transport.cancel();
578
+ if (timeout !== 0) {
579
+ clearTimeout(timeout);
580
+ timeout = 0;
581
+ }
582
+ es.readyState = CLOSED;
583
+ };
584
+
585
+ var onTimeout = function () {
586
+ timeout = 0;
587
+
588
+ if (currentState !== WAITING) {
589
+ if (!wasActivity) {
590
+ throwError(new Error("No activity within " + heartbeatTimeout + " milliseconds. Reconnecting."));
591
+ transport.cancel();
592
+ } else {
593
+ wasActivity = false;
594
+ timeout = setTimeout(function () {
595
+ onTimeout();
596
+ }, heartbeatTimeout);
597
+ }
598
+ return;
599
+ }
600
+
601
+ wasActivity = false;
602
+ timeout = setTimeout(function () {
603
+ onTimeout();
604
+ }, heartbeatTimeout);
605
+
606
+ currentState = CONNECTING;
607
+ dataBuffer = "";
608
+ eventTypeBuffer = "";
609
+ lastEventIdBuffer = lastEventId;
610
+ textBuffer = "";
611
+ fieldStart = 0;
612
+ valueStart = 0;
613
+ state = FIELD_START;
614
+
615
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=428916
616
+ // Request header field Last-Event-ID is not allowed by Access-Control-Allow-Headers.
617
+ var requestURL = url;
618
+ if (url.slice(0, 5) !== "data:" &&
619
+ url.slice(0, 5) !== "blob:") {
620
+ requestURL = url + (url.indexOf("?", 0) === -1 ? "?" : "&") + "lastEventId=" + encodeURIComponent(lastEventId);
621
+ }
622
+ var requestHeaders = {};
623
+ requestHeaders["Accept"] = "text/event-stream";
624
+ if (headers != undefined) {
625
+ for (var name in headers) {
626
+ if (Object.prototype.hasOwnProperty.call(headers, name)) {
627
+ requestHeaders[name] = headers[name];
628
+ }
629
+ }
630
+ }
631
+ try {
632
+ transport.open(onStart, onProgress, onFinish, requestURL, withCredentials, requestHeaders);
633
+ } catch (error) {
634
+ close();
635
+ throw error;
636
+ }
637
+ };
638
+
639
+ es.url = url;
640
+ es.readyState = CONNECTING;
641
+ es.withCredentials = withCredentials;
642
+ es._close = close;
643
+
644
+ onTimeout();
645
+ }
646
+
647
+ EventSourcePolyfill.prototype = Object.create(EventTarget.prototype);
648
+ EventSourcePolyfill.prototype.CONNECTING = CONNECTING;
649
+ EventSourcePolyfill.prototype.OPEN = OPEN;
650
+ EventSourcePolyfill.prototype.CLOSED = CLOSED;
651
+ EventSourcePolyfill.prototype.close = function () {
652
+ this._close();
653
+ };
654
+
655
+ EventSourcePolyfill.CONNECTING = CONNECTING;
656
+ EventSourcePolyfill.OPEN = OPEN;
657
+ EventSourcePolyfill.CLOSED = CLOSED;
658
+ EventSourcePolyfill.prototype.withCredentials = undefined;
659
+
660
+ global.EventSourcePolyfill = EventSourcePolyfill;
661
+ global.NativeEventSource = NativeEventSource;
662
+
663
+ if (XMLHttpRequest != undefined && (NativeEventSource == undefined || !("withCredentials" in NativeEventSource.prototype))) {
664
+ // Why replace a native EventSource ?
665
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=444328
666
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=831392
667
+ // https://code.google.com/p/chromium/issues/detail?id=260144
668
+ // https://code.google.com/p/chromium/issues/detail?id=225654
669
+ // ...
670
+ global.EventSource = EventSourcePolyfill;
671
+ }
672
+
673
+ }(typeof window !== 'undefined' ? window : this));
inc/assets/js/eventsource.min.js CHANGED
@@ -1,6 +1,6 @@
1
- /** @license
2
- * eventsource.js
3
- * Available under MIT License (MIT)
4
- * https://github.com/Yaffle/EventSource/
5
- */
6
  !function(a){"use strict";function b(a){this.withCredentials=!1,this.responseType="",this.readyState=0,this.status=0,this.statusText="",this.responseText="",this.onprogress=p,this.onreadystatechange=p,this._contentType="",this._xhr=a,this._sendTimeout=0,this._abort=p}function c(a){this._xhr=new b(a)}function d(){this._listeners=Object.create(null)}function e(a){j(function(){throw a},0)}function f(a){this.type=a,this.target=void 0}function g(a,b){f.call(this,a),this.data=b.data,this.lastEventId=b.lastEventId}function h(a,b){d.call(this),this.onopen=void 0,this.onmessage=void 0,this.onerror=void 0,this.url=void 0,this.readyState=void 0,this.withCredentials=void 0,this._close=void 0,i(this,a,b)}function i(a,b,d){b=String(b);var h=void 0!=d&&Boolean(d.withCredentials),i=D(1e3),n=D(45e3),o="",p=i,A=!1,B=void 0!=d&&void 0!=d.headers?JSON.parse(JSON.stringify(d.headers)):void 0,F=void 0!=d&&void 0!=d.Transport?d.Transport:void 0!=m?m:l,G=new c(new F),H=0,I=q,J="",K="",L="",M="",N=v,O=0,P=0,Q=function(b,c,d){if(I===r)if(200===b&&void 0!=d&&z.test(d)){I=s,A=!0,p=i,a.readyState=s;var g=new f("open");a.dispatchEvent(g),E(a,a.onopen,g)}else{var h="";200!==b?(c&&(c=c.replace(/\s+/g," ")),h="EventSource's response has a status "+b+" "+c+" that is not 200. Aborting the connection."):h="EventSource's response has a Content-Type specifying an unsupported type: "+(void 0==d?"-":d.replace(/\s+/g," "))+". Aborting the connection.",e(new Error(h)),T();var g=new f("error");a.dispatchEvent(g),E(a,a.onerror,g)}},R=function(b){if(I===s){for(var c=-1,d=0;d<b.length;d+=1){var e=b.charCodeAt(d);(e==="\n".charCodeAt(0)||e==="\r".charCodeAt(0))&&(c=d)}var f=(-1!==c?M:"")+b.slice(0,c+1);M=(-1===c?M:"")+b.slice(c+1),""!==f&&(A=!0);for(var h=0;h<f.length;h+=1){var e=f.charCodeAt(h);if(N===u&&e==="\n".charCodeAt(0))N=v;else if(N===u&&(N=v),e==="\r".charCodeAt(0)||e==="\n".charCodeAt(0)){if(N!==v){N===w&&(P=h+1);var l=f.slice(O,P-1),m=f.slice(P+(h>P&&f.charCodeAt(P)===" ".charCodeAt(0)?1:0),h);"data"===l?(J+="\n",J+=m):"id"===l?K=m:"event"===l?L=m:"retry"===l?(i=C(m,i),p=i):"heartbeatTimeout"===l&&(n=C(m,n),0!==H&&(k(H),H=j(function(){U()},n)))}if(N===v){if(""!==J){o=K,""===L&&(L="message");var q=new g(L,{data:J.slice(1),lastEventId:K});if(a.dispatchEvent(q),"message"===L&&E(a,a.onmessage,q),I===t)return}J="",L=""}N=e==="\r".charCodeAt(0)?u:v}else N===v&&(O=h,N=w),N===w?e===":".charCodeAt(0)&&(P=h+1,N=x):N===x&&(N=y)}}},S=function(){if(I===s||I===r){I=q,0!==H&&(k(H),H=0),H=j(function(){U()},p),p=D(Math.min(16*i,2*p)),a.readyState=r;var b=new f("error");a.dispatchEvent(b),E(a,a.onerror,b)}},T=function(){I=t,G.cancel(),0!==H&&(k(H),H=0),a.readyState=t},U=function(){if(H=0,I!==q)return void(A?(A=!1,H=j(function(){U()},n)):(e(new Error("No activity within "+n+" milliseconds. Reconnecting.")),G.cancel()));A=!1,H=j(function(){U()},n),I=r,J="",L="",K=o,M="",O=0,P=0,N=v;var a=b;"data:"!==b.slice(0,5)&&"blob:"!==b.slice(0,5)&&(a=b+(-1===b.indexOf("?",0)?"?":"&")+"lastEventId="+encodeURIComponent(o));var c={};if(c.Accept="text/event-stream",void 0!=B)for(var d in B)Object.prototype.hasOwnProperty.call(B,d)&&(c[d]=B[d]);try{G.open(Q,R,S,a,h,c)}catch(f){throw T(),f}};a.url=b,a.readyState=r,a.withCredentials=h,a._close=T,U()}var j=a.setTimeout,k=a.clearTimeout,l=a.XMLHttpRequest,m=a.XDomainRequest,n=a.EventSource,o=a.document;null==Object.create&&(Object.create=function(a){function b(){}return b.prototype=a,new b});var p=function(){};b.prototype.open=function(a,b){this._abort(!0);var c=this,d=this._xhr,e=1,f=0;this._abort=function(a){0!==c._sendTimeout&&(k(c._sendTimeout),c._sendTimeout=0),(1===e||2===e||3===e)&&(e=4,d.onload=p,d.onerror=p,d.onabort=p,d.onprogress=p,d.onreadystatechange=p,d.abort(),0!==f&&(k(f),f=0),a||(c.readyState=4,c.onreadystatechange())),e=0};var g=function(){if(1===e){var a=0,b="",f=void 0;if("contentType"in d)a=200,b="OK",f=d.contentType;else try{a=d.status,b=d.statusText,f=d.getResponseHeader("Content-Type")}catch(g){a=0,b="",f=void 0}0!==a&&(e=2,c.readyState=2,c.status=a,c.statusText=b,c._contentType=f,c.onreadystatechange())}},h=function(){if(g(),2===e||3===e){e=3;var a="";try{a=d.responseText}catch(b){}c.readyState=3,c.responseText=a,c.onprogress()}},i=function(){h(),(1===e||2===e||3===e)&&(e=4,0!==f&&(k(f),f=0),c.readyState=4,c.onreadystatechange())},m=function(){void 0!=d&&(4===d.readyState?i():3===d.readyState?h():2===d.readyState&&g())},n=function(){f=j(function(){n()},500),3===d.readyState&&h()};d.onload=i,d.onerror=i,d.onabort=i,"sendAsBinary"in l.prototype||"mozAnon"in l.prototype||(d.onprogress=h),d.onreadystatechange=m,"contentType"in d&&(b+=(-1===b.indexOf("?",0)?"?":"&")+"padding=true"),d.open(a,b,!0),"readyState"in d&&(f=j(function(){n()},0))},b.prototype.abort=function(){this._abort(!1)},b.prototype.getResponseHeader=function(a){return this._contentType},b.prototype.setRequestHeader=function(a,b){var c=this._xhr;"setRequestHeader"in c&&c.setRequestHeader(a,b)},b.prototype.send=function(){if(!("ontimeout"in l.prototype)&&void 0!=o&&void 0!=o.readyState&&"complete"!==o.readyState){var a=this;return void(a._sendTimeout=j(function(){a._sendTimeout=0,a.send()},4))}var b=this._xhr;b.withCredentials=this.withCredentials,b.responseType=this.responseType;try{b.send(void 0)}catch(c){throw c}},c.prototype.open=function(a,b,c,d,e,f){var g=this._xhr;g.open("GET",d);var h=0;g.onprogress=function(){var a=g.responseText,c=a.slice(h);h+=c.length,b(c)},g.onreadystatechange=function(){if(2===g.readyState){var b=g.status,d=g.statusText,e=g.getResponseHeader("Content-Type");a(b,d,e)}else 4===g.readyState&&c()},g.withCredentials=e,g.responseType="text";for(var i in f)Object.prototype.hasOwnProperty.call(f,i)&&g.setRequestHeader(i,f[i]);g.send()},c.prototype.cancel=function(){var a=this._xhr;a.abort()},d.prototype.dispatchEvent=function(a){a.target=this;var b=this._listeners[a.type];if(void 0!=b)for(var c=b.length,d=0;c>d;d+=1){var f=b[d];try{"function"==typeof f.handleEvent?f.handleEvent(a):f.call(this,a)}catch(g){e(g)}}},d.prototype.addEventListener=function(a,b){a=String(a);var c=this._listeners,d=c[a];void 0==d&&(d=[],c[a]=d);for(var e=!1,f=0;f<d.length;f+=1)d[f]===b&&(e=!0);e||d.push(b)},d.prototype.removeEventListener=function(a,b){a=String(a);var c=this._listeners,d=c[a];if(void 0!=d){for(var e=[],f=0;f<d.length;f+=1)d[f]!==b&&e.push(d[f]);0===e.length?delete c[a]:c[a]=e}},g.prototype=Object.create(f.prototype);var q=-1,r=0,s=1,t=2,u=-1,v=0,w=1,x=2,y=3,z=/^text\/event\-stream;?(\s*charset\=utf\-8)?$/i,A=1e3,B=18e6,C=function(a,b){var c=parseInt(a,10);return c!==c&&(c=b),D(c)},D=function(a){return Math.min(Math.max(a,A),B)},E=function(a,b,c){try{"function"==typeof b&&b.call(a,c)}catch(d){e(d)}};h.prototype=Object.create(d.prototype),h.prototype.CONNECTING=r,h.prototype.OPEN=s,h.prototype.CLOSED=t,h.prototype.close=function(){this._close()},h.CONNECTING=r,h.OPEN=s,h.CLOSED=t,h.prototype.withCredentials=void 0,a.EventSourcePolyfill=h,a.NativeEventSource=n,void 0==l||void 0!=n&&"withCredentials"in n.prototype||(a.EventSource=h)}("undefined"!=typeof window?window:this);
1
+ /** @license
2
+ * eventsource.js
3
+ * Available under MIT License (MIT)
4
+ * https://github.com/Yaffle/EventSource/
5
+ */
6
  !function(a){"use strict";function b(a){this.withCredentials=!1,this.responseType="",this.readyState=0,this.status=0,this.statusText="",this.responseText="",this.onprogress=p,this.onreadystatechange=p,this._contentType="",this._xhr=a,this._sendTimeout=0,this._abort=p}function c(a){this._xhr=new b(a)}function d(){this._listeners=Object.create(null)}function e(a){j(function(){throw a},0)}function f(a){this.type=a,this.target=void 0}function g(a,b){f.call(this,a),this.data=b.data,this.lastEventId=b.lastEventId}function h(a,b){d.call(this),this.onopen=void 0,this.onmessage=void 0,this.onerror=void 0,this.url=void 0,this.readyState=void 0,this.withCredentials=void 0,this._close=void 0,i(this,a,b)}function i(a,b,d){b=String(b);var h=void 0!=d&&Boolean(d.withCredentials),i=D(1e3),n=D(45e3),o="",p=i,A=!1,B=void 0!=d&&void 0!=d.headers?JSON.parse(JSON.stringify(d.headers)):void 0,F=void 0!=d&&void 0!=d.Transport?d.Transport:void 0!=m?m:l,G=new c(new F),H=0,I=q,J="",K="",L="",M="",N=v,O=0,P=0,Q=function(b,c,d){if(I===r)if(200===b&&void 0!=d&&z.test(d)){I=s,A=!0,p=i,a.readyState=s;var g=new f("open");a.dispatchEvent(g),E(a,a.onopen,g)}else{var h="";200!==b?(c&&(c=c.replace(/\s+/g," ")),h="EventSource's response has a status "+b+" "+c+" that is not 200. Aborting the connection."):h="EventSource's response has a Content-Type specifying an unsupported type: "+(void 0==d?"-":d.replace(/\s+/g," "))+". Aborting the connection.",e(new Error(h)),T();var g=new f("error");a.dispatchEvent(g),E(a,a.onerror,g)}},R=function(b){if(I===s){for(var c=-1,d=0;d<b.length;d+=1){var e=b.charCodeAt(d);(e==="\n".charCodeAt(0)||e==="\r".charCodeAt(0))&&(c=d)}var f=(-1!==c?M:"")+b.slice(0,c+1);M=(-1===c?M:"")+b.slice(c+1),""!==f&&(A=!0);for(var h=0;h<f.length;h+=1){var e=f.charCodeAt(h);if(N===u&&e==="\n".charCodeAt(0))N=v;else if(N===u&&(N=v),e==="\r".charCodeAt(0)||e==="\n".charCodeAt(0)){if(N!==v){N===w&&(P=h+1);var l=f.slice(O,P-1),m=f.slice(P+(h>P&&f.charCodeAt(P)===" ".charCodeAt(0)?1:0),h);"data"===l?(J+="\n",J+=m):"id"===l?K=m:"event"===l?L=m:"retry"===l?(i=C(m,i),p=i):"heartbeatTimeout"===l&&(n=C(m,n),0!==H&&(k(H),H=j(function(){U()},n)))}if(N===v){if(""!==J){o=K,""===L&&(L="message");var q=new g(L,{data:J.slice(1),lastEventId:K});if(a.dispatchEvent(q),"message"===L&&E(a,a.onmessage,q),I===t)return}J="",L=""}N=e==="\r".charCodeAt(0)?u:v}else N===v&&(O=h,N=w),N===w?e===":".charCodeAt(0)&&(P=h+1,N=x):N===x&&(N=y)}}},S=function(){if(I===s||I===r){I=q,0!==H&&(k(H),H=0),H=j(function(){U()},p),p=D(Math.min(16*i,2*p)),a.readyState=r;var b=new f("error");a.dispatchEvent(b),E(a,a.onerror,b)}},T=function(){I=t,G.cancel(),0!==H&&(k(H),H=0),a.readyState=t},U=function(){if(H=0,I!==q)return void(A?(A=!1,H=j(function(){U()},n)):(e(new Error("No activity within "+n+" milliseconds. Reconnecting.")),G.cancel()));A=!1,H=j(function(){U()},n),I=r,J="",L="",K=o,M="",O=0,P=0,N=v;var a=b;"data:"!==b.slice(0,5)&&"blob:"!==b.slice(0,5)&&(a=b+(-1===b.indexOf("?",0)?"?":"&")+"lastEventId="+encodeURIComponent(o));var c={};if(c.Accept="text/event-stream",void 0!=B)for(var d in B)Object.prototype.hasOwnProperty.call(B,d)&&(c[d]=B[d]);try{G.open(Q,R,S,a,h,c)}catch(f){throw T(),f}};a.url=b,a.readyState=r,a.withCredentials=h,a._close=T,U()}var j=a.setTimeout,k=a.clearTimeout,l=a.XMLHttpRequest,m=a.XDomainRequest,n=a.EventSource,o=a.document;null==Object.create&&(Object.create=function(a){function b(){}return b.prototype=a,new b});var p=function(){};b.prototype.open=function(a,b){this._abort(!0);var c=this,d=this._xhr,e=1,f=0;this._abort=function(a){0!==c._sendTimeout&&(k(c._sendTimeout),c._sendTimeout=0),(1===e||2===e||3===e)&&(e=4,d.onload=p,d.onerror=p,d.onabort=p,d.onprogress=p,d.onreadystatechange=p,d.abort(),0!==f&&(k(f),f=0),a||(c.readyState=4,c.onreadystatechange())),e=0};var g=function(){if(1===e){var a=0,b="",f=void 0;if("contentType"in d)a=200,b="OK",f=d.contentType;else try{a=d.status,b=d.statusText,f=d.getResponseHeader("Content-Type")}catch(g){a=0,b="",f=void 0}0!==a&&(e=2,c.readyState=2,c.status=a,c.statusText=b,c._contentType=f,c.onreadystatechange())}},h=function(){if(g(),2===e||3===e){e=3;var a="";try{a=d.responseText}catch(b){}c.readyState=3,c.responseText=a,c.onprogress()}},i=function(){h(),(1===e||2===e||3===e)&&(e=4,0!==f&&(k(f),f=0),c.readyState=4,c.onreadystatechange())},m=function(){void 0!=d&&(4===d.readyState?i():3===d.readyState?h():2===d.readyState&&g())},n=function(){f=j(function(){n()},500),3===d.readyState&&h()};d.onload=i,d.onerror=i,d.onabort=i,"sendAsBinary"in l.prototype||"mozAnon"in l.prototype||(d.onprogress=h),d.onreadystatechange=m,"contentType"in d&&(b+=(-1===b.indexOf("?",0)?"?":"&")+"padding=true"),d.open(a,b,!0),"readyState"in d&&(f=j(function(){n()},0))},b.prototype.abort=function(){this._abort(!1)},b.prototype.getResponseHeader=function(a){return this._contentType},b.prototype.setRequestHeader=function(a,b){var c=this._xhr;"setRequestHeader"in c&&c.setRequestHeader(a,b)},b.prototype.send=function(){if(!("ontimeout"in l.prototype)&&void 0!=o&&void 0!=o.readyState&&"complete"!==o.readyState){var a=this;return void(a._sendTimeout=j(function(){a._sendTimeout=0,a.send()},4))}var b=this._xhr;b.withCredentials=this.withCredentials,b.responseType=this.responseType;try{b.send(void 0)}catch(c){throw c}},c.prototype.open=function(a,b,c,d,e,f){var g=this._xhr;g.open("GET",d);var h=0;g.onprogress=function(){var a=g.responseText,c=a.slice(h);h+=c.length,b(c)},g.onreadystatechange=function(){if(2===g.readyState){var b=g.status,d=g.statusText,e=g.getResponseHeader("Content-Type");a(b,d,e)}else 4===g.readyState&&c()},g.withCredentials=e,g.responseType="text";for(var i in f)Object.prototype.hasOwnProperty.call(f,i)&&g.setRequestHeader(i,f[i]);g.send()},c.prototype.cancel=function(){var a=this._xhr;a.abort()},d.prototype.dispatchEvent=function(a){a.target=this;var b=this._listeners[a.type];if(void 0!=b)for(var c=b.length,d=0;c>d;d+=1){var f=b[d];try{"function"==typeof f.handleEvent?f.handleEvent(a):f.call(this,a)}catch(g){e(g)}}},d.prototype.addEventListener=function(a,b){a=String(a);var c=this._listeners,d=c[a];void 0==d&&(d=[],c[a]=d);for(var e=!1,f=0;f<d.length;f+=1)d[f]===b&&(e=!0);e||d.push(b)},d.prototype.removeEventListener=function(a,b){a=String(a);var c=this._listeners,d=c[a];if(void 0!=d){for(var e=[],f=0;f<d.length;f+=1)d[f]!==b&&e.push(d[f]);0===e.length?delete c[a]:c[a]=e}},g.prototype=Object.create(f.prototype);var q=-1,r=0,s=1,t=2,u=-1,v=0,w=1,x=2,y=3,z=/^text\/event\-stream;?(\s*charset\=utf\-8)?$/i,A=1e3,B=18e6,C=function(a,b){var c=parseInt(a,10);return c!==c&&(c=b),D(c)},D=function(a){return Math.min(Math.max(a,A),B)},E=function(a,b,c){try{"function"==typeof b&&b.call(a,c)}catch(d){e(d)}};h.prototype=Object.create(d.prototype),h.prototype.CONNECTING=r,h.prototype.OPEN=s,h.prototype.CLOSED=t,h.prototype.close=function(){this._close()},h.CONNECTING=r,h.OPEN=s,h.CLOSED=t,h.prototype.withCredentials=void 0,a.EventSourcePolyfill=h,a.NativeEventSource=n,void 0==l||void 0!=n&&"withCredentials"in n.prototype||(a.EventSource=h)}("undefined"!=typeof window?window:this);
inc/assets/js/render-grid.js CHANGED
@@ -1,592 +1,592 @@
1
- (function($){
2
-
3
- AstraRender = {
4
-
5
- _ref : null,
6
-
7
- /**
8
- * _api_params = {
9
- * 'search' : '',
10
- * 'per_page' : '',
11
- * 'astra-site-category' : '',
12
- * 'astra-site-page-builder' : '',
13
- * 'page' : '',
14
- * };
15
- *
16
- * E.g. per_page=<page-id>&astra-site-category=<category-ids>&astra-site-page-builder=<page-builder-ids>&page=<page>
17
- */
18
- _api_params : {},
19
- _breakpoint : 768,
20
- _has_default_page_builder : false,
21
-
22
- init: function()
23
- {
24
- this._resetPagedCount();
25
- this._bind();
26
- this._loadPageBuilders();
27
- },
28
-
29
- /**
30
- * Binds events for the Astra Sites.
31
- *
32
- * @since 1.0.0
33
- * @access private
34
- * @method _bind
35
- */
36
- _bind: function()
37
- {
38
- $( document ).on('astra-sites-api-request-error' , AstraRender._addSuggestionBox );
39
- $( document ).on('astra-sites-api-request-fail' , AstraRender._addSuggestionBox );
40
- $( document ).on('astra-api-post-loaded-on-scroll' , AstraRender._reinitGridScrolled );
41
- $( document ).on('astra-api-post-loaded' , AstraRender._reinitGrid );
42
- $( document ).on('astra-api-page-builder-loaded' , AstraRender._addPageBuilders );
43
- $( document ).on('astra-api-category-loaded' , AstraRender._loadFirstGrid );
44
-
45
- // Event's for API request.
46
- $( document ).on('click' , '.filter-links a', AstraRender._filterClick );
47
- $( document ).on('keyup input' , '#wp-filter-search-input', AstraRender._search );
48
- $( document ).on('scroll' , AstraRender._scroll );
49
- $( document ).on('astra-sites-api-request-fail', AstraRender._site_unreachable );
50
- },
51
-
52
- /**
53
- * Website is Down
54
- *
55
- * @since 1.2.11
56
- * @return null
57
- */
58
- _site_unreachable: function( event, jqXHR, textStatus, args ) {
59
- event.preventDefault();
60
- if ( 'astra-site-page-builder' === args.id ) {
61
- $('#astra-sites-admin').html( wp.template('astra-site-down') )
62
- }
63
- },
64
-
65
- /**
66
- * On Filter Clicked
67
- *
68
- * Prepare Before API Request:
69
- * - Empty search input field to avoid search term on filter click.
70
- * - Remove Inline Height
71
- * - Added 'hide-me' class to hide the 'No more sites!' string.
72
- * - Added 'loading-content' for body.
73
- * - Show spinner.
74
- */
75
- _filterClick: function( event ) {
76
-
77
- event.preventDefault();
78
-
79
- if( $( this ).parents('.astra-site-category').length && ! $('body').hasClass('page-builder-selected') ) {
80
- return;
81
- }
82
-
83
- $(this).parents('.filter-links').find('a').removeClass('current');
84
- $(this).addClass('current');
85
-
86
- // Prepare Before Search.
87
- $('.no-more-demos').addClass('hide-me');
88
- $('.astra-sites-suggestions').remove();
89
-
90
- // Empty the search input only click on category filter not on page builder filter.
91
- if( $(this).parents('.filter-links').hasClass('astra-site-category') ) {
92
- $('#wp-filter-search-input').val('');
93
- }
94
- $('#astra-sites').hide().css('height', '');
95
-
96
- $('body').addClass('loading-content');
97
- $('#astra-sites-admin').find('.spinner').removeClass('hide-me');
98
-
99
- // Show sites.
100
- AstraRender._showSites();
101
- },
102
-
103
- /**
104
- * Search Site.
105
- *
106
- * Prepare Before API Request:
107
- * - Remove Inline Height
108
- * - Added 'hide-me' class to hide the 'No more sites!' string.
109
- * - Added 'loading-content' for body.
110
- * - Show spinner.
111
- */
112
- _search: function() {
113
-
114
- if( ! $('body').hasClass('page-builder-selected') ) {
115
- return;
116
- }
117
-
118
- $this = jQuery('#wp-filter-search-input').val();
119
-
120
- // Prepare Before Search.
121
- $('#astra-sites').hide().css('height', '');
122
- $('.no-more-demos').addClass('hide-me');
123
- $('.astra-sites-suggestions').remove();
124
-
125
- $('body').addClass('loading-content');
126
- $('#astra-sites-admin').find('.spinner').removeClass('hide-me');
127
-
128
- window.clearTimeout(AstraRender._ref);
129
- AstraRender._ref = window.setTimeout(function () {
130
- AstraRender._ref = null;
131
-
132
- AstraRender._resetPagedCount();
133
- jQuery('body').addClass('loading-content');
134
- jQuery('body').attr('data-astra-demo-search', $this);
135
-
136
- AstraRender._showSites();
137
-
138
- }, 500);
139
-
140
- },
141
-
142
- /**
143
- * On Scroll
144
- */
145
- _scroll: function(event) {
146
-
147
- if( ! $('body').hasClass('page-builder-selected') ) {
148
- return;
149
- }
150
-
151
- if( ! $('body').hasClass('listed-all-sites') ) {
152
-
153
- var scrollDistance = jQuery(window).scrollTop();
154
-
155
- var themesBottom = Math.abs(jQuery(window).height() - jQuery('#astra-sites').offset().top - jQuery('#astra-sites').height());
156
- themesBottom = themesBottom - 100;
157
-
158
- ajaxLoading = jQuery('body').data('scrolling');
159
-
160
- if (scrollDistance > themesBottom && ajaxLoading == false) {
161
- AstraRender._updatedPagedCount();
162
-
163
- if( ! $('#astra-sites .no-themes').length ) {
164
- $('#astra-sites-admin').find('.spinner').addClass('is-active');
165
- }
166
-
167
- jQuery('body').data('scrolling', true);
168
-
169
- /**
170
- * @see _reinitGridScrolled() which called in trigger 'astra-api-post-loaded-on-scroll'
171
- */
172
- AstraRender._showSites( false, 'astra-api-post-loaded-on-scroll' );
173
- }
174
- }
175
- },
176
-
177
- _apiAddParam_status: function() {
178
- if( astraRenderGrid.sites && astraRenderGrid.sites.status ) {
179
- AstraRender._api_params['status'] = astraRenderGrid.sites.status;
180
- }
181
- },
182
-
183
- // Add 'search'
184
- _apiAddParam_search: function() {
185
- var search_val = jQuery('#wp-filter-search-input').val() || '';
186
- if( '' !== search_val ) {
187
- AstraRender._api_params['search'] = search_val;
188
- }
189
- },
190
-
191
- _apiAddParam_per_page: function() {
192
- // Add 'per_page'
193
- var per_page_val = 15;
194
- if( astraRenderGrid.sites && astraRenderGrid.sites["par-page"] ) {
195
- per_page_val = parseInt( astraRenderGrid.sites["par-page"] );
196
- }
197
- AstraRender._api_params['per_page'] = per_page_val;
198
- },
199
-
200
- _apiAddParam_astra_site_category: function() {
201
- // Add 'astra-site-category'
202
- var selected_category_id = jQuery('.filter-links.astra-site-category').find('.current').data('group') || '';
203
- if( '' !== selected_category_id && 'all' !== selected_category_id ) {
204
- AstraRender._api_params['astra-site-category'] = selected_category_id;
205
- } else if( astraRenderGrid.sites && astraRenderGrid['categories'].include ) {
206
- if( AstraRender._isArray( astraRenderGrid['categories'].include ) ) {
207
- AstraRender._api_params['astra-site-category'] = astraRenderGrid['categories'].include.join(',');
208
- } else {
209
- AstraRender._api_params['astra-site-category'] = astraRenderGrid['categories'].include;
210
- }
211
- }
212
- },
213
-
214
- _apiAddParam_astra_site_page_builder: function() {
215
- // Add 'astra-site-page-builder'
216
- var selected_page_builder_id = jQuery('.filter-links.astra-site-page-builder').find('.current').data('group') || '';
217
- if( '' !== selected_page_builder_id && 'all' !== selected_page_builder_id ) {
218
- AstraRender._api_params['astra-site-page-builder'] = selected_page_builder_id;
219
- } else if( astraRenderGrid.sites && astraRenderGrid['page-builders'].include ) {
220
- if( AstraRender._isArray( astraRenderGrid['page-builders'].include ) ) {
221
- AstraRender._api_params['astra-site-page-builder'] = astraRenderGrid['page-builders'].include.join(',');
222
- } else {
223
- AstraRender._api_params['astra-site-page-builder'] = astraRenderGrid['page-builders'].include;
224
- }
225
- }
226
- },
227
-
228
- _apiAddParam_page: function() {
229
- // Add 'page'
230
- var page_val = parseInt(jQuery('body').attr('data-astra-demo-paged')) || 1;
231
- AstraRender._api_params['page'] = page_val;
232
- },
233
-
234
- _apiAddParam_purchase_key: function() {
235
- if( astraRenderGrid.sites && astraRenderGrid.sites.purchase_key ) {
236
- AstraRender._api_params['purchase_key'] = astraRenderGrid.sites.purchase_key;
237
- }
238
- },
239
-
240
- _apiAddParam_site_url: function() {
241
- if( astraRenderGrid.sites && astraRenderGrid.sites.site_url ) {
242
- AstraRender._api_params['site_url'] = astraRenderGrid.sites.site_url;
243
- }
244
- },
245
-
246
- /**
247
- * Show Sites
248
- *
249
- * Params E.g. per_page=<page-id>&astra-site-category=<category-ids>&astra-site-page-builder=<page-builder-ids>&page=<page>
250
- *
251
- * @param {Boolean} resetPagedCount Reset Paged Count.
252
- * @param {String} trigger Filtered Trigger.
253
- */
254
- _showSites: function( resetPagedCount, trigger ) {
255
-
256
- if( undefined === resetPagedCount ) {
257
- resetPagedCount = true
258
- }
259
-
260
- if( undefined === trigger ) {
261
- trigger = 'astra-api-post-loaded';
262
- }
263
-
264
- if( resetPagedCount ) {
265
- AstraRender._resetPagedCount();
266
- }
267
-
268
- // Add Params for API request.
269
- AstraRender._api_params = {};
270
-
271
- AstraRender._apiAddParam_status();
272
- AstraRender._apiAddParam_search();
273
- AstraRender._apiAddParam_per_page();
274
- AstraRender._apiAddParam_astra_site_category();
275
- AstraRender._apiAddParam_astra_site_page_builder();
276
- AstraRender._apiAddParam_page();
277
- AstraRender._apiAddParam_site_url();
278
- AstraRender._apiAddParam_purchase_key();
279
-
280
- // API Request.
281
- var api_post = {
282
- slug: 'astra-sites?' + decodeURIComponent( $.param( AstraRender._api_params ) ),
283
- trigger: trigger,
284
- };
285
-
286
- AstraSitesAPI._api_request( api_post );
287
-
288
- },
289
-
290
- /**
291
- * Get Category Params
292
- *
293
- * @since 1.2.4
294
- * @param {string} category_slug Category Slug.
295
- * @return {mixed} Add `include=<category-ids>` in API request.
296
- */
297
- _getPageBuilderParams: function()
298
- {
299
- var _params = {};
300
-
301
- if( astraRenderGrid.sites && astraRenderGrid.sites.purchase_key ) {
302
- _params['purchase_key'] = astraRenderGrid.sites.purchase_key;
303
- }
304
-
305
- if( astraRenderGrid.sites && astraRenderGrid.sites.site_url ) {
306
- _params['site_url'] = astraRenderGrid.sites.site_url;
307
- }
308
-
309
- if( astraRenderGrid.sites && astraRenderGrid['page-builders'].include ) {
310
- if( AstraRender._isArray( astraRenderGrid['page-builders'].include ) ) {
311
- _params['include'] = astraRenderGrid['page-builders'].include.join(',');
312
- } else {
313
- _params['include'] = astraRenderGrid['page-builders'].include;
314
- }
315
- }
316
-
317
- var decoded_params = decodeURIComponent( $.param( _params ) );
318
-
319
- if( decoded_params.length ) {
320
- return '/?' + decoded_params;
321
- }
322
-
323
- return '/';
324
- },
325
-
326
- /**
327
- * Get Category Params
328
- *
329
- * @param {string} category_slug Category Slug.
330
- * @return {mixed} Add `include=<category-ids>` in API request.
331
- */
332
- _getCategoryParams: function( category_slug ) {
333
-
334
- var _params = {};
335
-
336
- if( astraRenderGrid.sites && astraRenderGrid['categories'].include ) {
337
- if( AstraRender._isArray( astraRenderGrid['categories'].include ) ) {
338
- _params['include'] = astraRenderGrid['categories'].include.join(',');
339
- } else {
340
- _params['include'] = astraRenderGrid['categories'].include;
341
- }
342
- }
343
-
344
- var decoded_params = decodeURIComponent( $.param( _params ) );
345
-
346
- if( decoded_params.length ) {
347
- return '/?' + decoded_params;
348
- }
349
-
350
- return '/';
351
- },
352
-
353
- /**
354
- * Get All Select Status
355
- *
356
- * @param {string} category_slug Category Slug.
357
- * @return {boolean} Return true/false.
358
- */
359
- _getCategoryAllSelectStatus: function( category_slug ) {
360
-
361
- // Has category?
362
- if( category_slug in astraRenderGrid.settings ) {
363
-
364
- // Has `all` in stored list?
365
- if( $.inArray('all', astraRenderGrid.settings[ category_slug ]) === -1 ) {
366
- return false;
367
- }
368
- }
369
-
370
- return true;
371
- },
372
-
373
- /**
374
- * Show Filters
375
- */
376
- _loadPageBuilders: function() {
377
-
378
- /**
379
- * Page Builder
380
- */
381
- var category_slug = 'astra-site-page-builder';
382
- var category = {
383
- slug : category_slug + AstraRender._getPageBuilderParams(),
384
- id : category_slug,
385
- class : category_slug,
386
- trigger : 'astra-api-page-builder-loaded',
387
- wrapper_class : 'filter-links',
388
- show_all : false,
389
- };
390
-
391
- AstraSitesAPI._api_request( category );
392
- },
393
-
394
- /**
395
- * Load First Grid.
396
- *
397
- * This is triggered after all category loaded.
398
- *
399
- * @param {object} event Event Object.
400
- */
401
- _loadFirstGrid: function( event, data ) {
402
-
403
- event.preventDefault();
404
-
405
- if( $('#' + data.args.id).length ) {
406
- var template = wp.template('astra-site-filters');
407
- $('#' + data.args.id).html(template( data ));
408
-
409
- if( 'true' === $('body').attr( 'data-default-page-builder-selected' ) ) {
410
- $('#' + data.args.id).find('li:first a').addClass('current');
411
- AstraRender._showSites();
412
- } else {
413
- $('body').removeClass('loading-content');
414
- if( ! $('#astra-sites-admin .astra-site-select-page-builder').length ) {
415
- $('#astra-sites-admin').append( wp.template( 'astra-site-select-page-builder' ) );
416
- }
417
- }
418
- } else {
419
- AstraRender._showSites();
420
- }
421
-
422
- },
423
-
424
- /**
425
- * Append filters.
426
- *
427
- * @param {object} event Object.
428
- * @param {object} data API response data.
429
- */
430
- _addPageBuilders: function( event, data ) {
431
- event.preventDefault();
432
-
433
- if( $('#' + data.args.id).length ) {
434
- var template = wp.template('astra-site-filters');
435
- $('#' + data.args.id).html(template( data ));
436
-
437
- if( 1 === parseInt( data.items_count ) ) {
438
- $('body').attr( 'data-default-page-builder-selected', true );
439
- $('#' + data.args.id).find('li:first a').addClass('current');
440
- }
441
- }
442
-
443
- /**
444
- * Categories
445
- */
446
- var category_slug = 'astra-site-category';
447
- var category = {
448
- slug : category_slug + AstraRender._getCategoryParams( category_slug ),
449
- id : category_slug,
450
- class : category_slug,
451
- trigger : 'astra-api-category-loaded',
452
- wrapper_class : 'filter-links',
453
- show_all : AstraRender._getCategoryAllSelectStatus( category_slug ),
454
- };
455
-
456
- AstraSitesAPI._api_request( category );
457
-
458
- },
459
-
460
-
461
- /**
462
- * Append sites on scroll.
463
- *
464
- * @param {object} event Object.
465
- * @param {object} data API response data.
466
- */
467
- _reinitGridScrolled: function( event, data ) {
468
-
469
- var template = wp.template('astra-sites-list');
470
-
471
- if( data.items.length > 0 ) {
472
-
473
- $('body').removeClass( 'loading-content' );
474
- $('.filter-count .count').text( data.items_count );
475
-
476
- setTimeout(function() {
477
- jQuery('#astra-sites').append(template( data ));
478
-
479
- AstraRender._imagesLoaded();
480
- }, 800);
481
- } else {
482
- $('body').addClass('listed-all-sites');
483
- }
484
-
485
- },
486
-
487
- /**
488
- * Update Astra sites list.
489
- *
490
- * @param {object} event Object.
491
- * @param {object} data API response data.
492
- */
493
- _reinitGrid: function( event, data ) {
494
-
495
- var template = wp.template('astra-sites-list');
496
-
497
- $('body').addClass( 'page-builder-selected' );
498
- $('body').removeClass( 'loading-content' );
499
- $('.filter-count .count').text( data.items_count );
500
-
501
- jQuery('body').attr('data-astra-demo-last-request', data.items_count);
502
-
503
- jQuery('#astra-sites').show().html(template( data ));
504
-
505
- AstraRender._imagesLoaded();
506
-
507
- $('#astra-sites-admin').find('.spinner').removeClass('is-active');
508
-
509
- if( data.items_count <= 0 ) {
510
- $('#astra-sites-admin').find('.spinner').removeClass('is-active');
511
- $('.no-more-demos').addClass('hide-me');
512
- $('.astra-sites-suggestions').remove();
513
-
514
- } else {
515
- $('body').removeClass('listed-all-sites');
516
- }
517
-
518
-
519
- },
520
-
521
- /**
522
- * Check image loaded with function `imagesLoaded()`
523
- */
524
- _imagesLoaded: function() {
525
-
526
- var self = jQuery('#sites-filter.execute-only-one-time a');
527
-
528
- $('.astra-sites-grid').imagesLoaded()
529
- .always( function( instance ) {
530
- if( jQuery( window ).outerWidth() > AstraRender._breakpoint ) {
531
- // $('#astra-sites').masonry('reload');
532
- }
533
-
534
- $('#astra-sites-admin').find('.spinner').removeClass('is-active');
535
- })
536
- .progress( function( instance, image ) {
537
- var result = image.isLoaded ? 'loaded' : 'broken';
538
- });
539
-
540
- },
541
-
542
- /**
543
- * Add Suggestion Box
544
- */
545
- _addSuggestionBox: function() {
546
- $('#astra-sites-admin').find('.spinner').removeClass('is-active').addClass('hide-me');
547
-
548
- $('#astra-sites-admin').find('.no-more-demos').removeClass('hide-me');
549
- var template = wp.template('astra-sites-suggestions');
550
- if( ! $( '.astra-sites-suggestions').length ) {
551
- $('#astra-sites').append( template );
552
- }
553
- },
554
-
555
- /**
556
- * Update Page Count.
557
- */
558
- _updatedPagedCount: function() {
559
- paged = parseInt(jQuery('body').attr('data-astra-demo-paged'));
560
- jQuery('body').attr('data-astra-demo-paged', paged + 1);
561
- window.setTimeout(function () {
562
- jQuery('body').data('scrolling', false);
563
- }, 800);
564
- },
565
-
566
- /**
567
- * Reset Page Count.
568
- */
569
- _resetPagedCount: function() {
570
-
571
- jQuery('body').attr('data-astra-demo-last-request', '1');
572
- jQuery('body').attr('data-astra-demo-paged', '1');
573
- jQuery('body').attr('data-astra-demo-search', '');
574
- jQuery('body').attr('data-scrolling', false);
575
-
576
- },
577
-
578
- // Returns if a value is an array
579
- _isArray: function(value) {
580
- return value && typeof value === 'object' && value.constructor === Array;
581
- }
582
-
583
- };
584
-
585
- /**
586
- * Initialize AstraRender
587
- */
588
- $(function(){
589
- AstraRender.init();
590
- });
591
-
592
  })(jQuery);
1
+ (function($){
2
+
3
+ AstraRender = {
4
+
5
+ _ref : null,
6
+
7
+ /**
8
+ * _api_params = {
9
+ * 'search' : '',
10
+ * 'per_page' : '',
11
+ * 'astra-site-category' : '',
12
+ * 'astra-site-page-builder' : '',
13
+ * 'page' : '',
14
+ * };
15
+ *
16
+ * E.g. per_page=<page-id>&astra-site-category=<category-ids>&astra-site-page-builder=<page-builder-ids>&page=<page>
17
+ */
18
+ _api_params : {},
19
+ _breakpoint : 768,
20
+ _has_default_page_builder : false,
21
+
22
+ init: function()
23
+ {
24
+ this._resetPagedCount();
25
+ this._bind();
26
+ this._loadPageBuilders();
27
+ },
28
+
29
+ /**
30
+ * Binds events for the Astra Sites.
31
+ *
32
+ * @since 1.0.0
33
+ * @access private
34
+ * @method _bind
35
+ */
36
+ _bind: function()
37
+ {
38
+ $( document ).on('astra-sites-api-request-error' , AstraRender._addSuggestionBox );
39
+ $( document ).on('astra-sites-api-request-fail' , AstraRender._addSuggestionBox );
40
+ $( document ).on('astra-api-post-loaded-on-scroll' , AstraRender._reinitGridScrolled );
41
+ $( document ).on('astra-api-post-loaded' , AstraRender._reinitGrid );
42
+ $( document ).on('astra-api-page-builder-loaded' , AstraRender._addPageBuilders );
43
+ $( document ).on('astra-api-category-loaded' , AstraRender._loadFirstGrid );
44
+
45
+ // Event's for API request.
46
+ $( document ).on('click' , '.filter-links a', AstraRender._filterClick );
47
+ $( document ).on('keyup input' , '#wp-filter-search-input', AstraRender._search );
48
+ $( document ).on('scroll' , AstraRender._scroll );
49
+ $( document ).on('astra-sites-api-request-fail', AstraRender._site_unreachable );
50
+ },
51
+
52
+ /**
53
+ * Website is Down
54
+ *
55
+ * @since 1.2.11
56
+ * @return null
57
+ */
58
+ _site_unreachable: function( event, jqXHR, textStatus, args ) {
59
+ event.preventDefault();
60
+ if ( 'astra-site-page-builder' === args.id ) {
61
+ $('#astra-sites-admin').html( wp.template('astra-site-down') )
62
+ }
63
+ },
64
+
65
+ /**
66
+ * On Filter Clicked
67
+ *
68
+ * Prepare Before API Request:
69
+ * - Empty search input field to avoid search term on filter click.
70
+ * - Remove Inline Height
71
+ * - Added 'hide-me' class to hide the 'No more sites!' string.
72
+ * - Added 'loading-content' for body.
73
+ * - Show spinner.
74
+ */
75
+ _filterClick: function( event ) {
76
+
77
+ event.preventDefault();
78
+
79
+ if( $( this ).parents('.astra-site-category').length && ! $('body').hasClass('page-builder-selected') ) {
80
+ return;
81
+ }
82
+
83
+ $(this).parents('.filter-links').find('a').removeClass('current');
84
+ $(this).addClass('current');
85
+
86
+ // Prepare Before Search.
87
+ $('.no-more-demos').addClass('hide-me');
88
+ $('.astra-sites-suggestions').remove();
89
+
90
+ // Empty the search input only click on category filter not on page builder filter.
91
+ if( $(this).parents('.filter-links').hasClass('astra-site-category') ) {
92
+ $('#wp-filter-search-input').val('');
93
+ }
94
+ $('#astra-sites').hide().css('height', '');
95
+
96
+ $('body').addClass('loading-content');
97
+ $('#astra-sites-admin').find('.spinner').removeClass('hide-me');
98
+
99
+ // Show sites.
100
+ AstraRender._showSites();
101
+ },
102
+
103
+ /**
104
+ * Search Site.
105
+ *
106
+ * Prepare Before API Request:
107
+ * - Remove Inline Height
108
+ * - Added 'hide-me' class to hide the 'No more sites!' string.
109
+ * - Added 'loading-content' for body.
110
+ * - Show spinner.
111
+ */
112
+ _search: function() {
113
+
114
+ if( ! $('body').hasClass('page-builder-selected') ) {
115
+ return;
116
+ }
117
+
118
+ $this = jQuery('#wp-filter-search-input').val();
119
+
120
+ // Prepare Before Search.
121
+ $('#astra-sites').hide().css('height', '');
122
+ $('.no-more-demos').addClass('hide-me');
123
+ $('.astra-sites-suggestions').remove();
124
+
125
+ $('body').addClass('loading-content');
126
+ $('#astra-sites-admin').find('.spinner').removeClass('hide-me');
127
+
128
+ window.clearTimeout(AstraRender._ref);
129
+ AstraRender._ref = window.setTimeout(function () {
130
+ AstraRender._ref = null;
131
+
132
+ AstraRender._resetPagedCount();
133
+ jQuery('body').addClass('loading-content');
134
+ jQuery('body').attr('data-astra-demo-search', $this);
135
+
136
+ AstraRender._showSites();
137
+
138
+ }, 500);
139
+
140
+ },
141
+
142
+ /**
143
+ * On Scroll
144
+ */
145
+ _scroll: function(event) {
146
+
147
+ if( ! $('body').hasClass('page-builder-selected') ) {
148
+ return;
149
+ }
150
+
151
+ if( ! $('body').hasClass('listed-all-sites') ) {
152
+
153
+ var scrollDistance = jQuery(window).scrollTop();
154
+
155
+ var themesBottom = Math.abs(jQuery(window).height() - jQuery('#astra-sites').offset().top - jQuery('#astra-sites').height());
156
+ themesBottom = themesBottom - 100;
157
+
158
+ ajaxLoading = jQuery('body').data('scrolling');
159
+
160
+ if (scrollDistance > themesBottom && ajaxLoading == false) {
161
+ AstraRender._updatedPagedCount();
162
+
163
+ if( ! $('#astra-sites .no-themes').length ) {
164
+ $('#astra-sites-admin').find('.spinner').addClass('is-active');
165
+ }
166
+
167
+ jQuery('body').data('scrolling', true);
168
+
169
+ /**
170
+ * @see _reinitGridScrolled() which called in trigger 'astra-api-post-loaded-on-scroll'
171
+ */
172
+ AstraRender._showSites( false, 'astra-api-post-loaded-on-scroll' );
173
+ }
174
+ }
175
+ },
176
+
177
+ _apiAddParam_status: function() {
178
+ if( astraRenderGrid.sites && astraRenderGrid.sites.status ) {
179
+ AstraRender._api_params['status'] = astraRenderGrid.sites.status;
180
+ }
181
+ },
182
+
183
+ // Add 'search'
184
+ _apiAddParam_search: function() {
185
+ var search_val = jQuery('#wp-filter-search-input').val() || '';
186
+ if( '' !== search_val ) {
187
+ AstraRender._api_params['search'] = search_val;
188
+ }
189
+ },
190
+
191
+ _apiAddParam_per_page: function() {
192
+ // Add 'per_page'
193
+ var per_page_val = 15;
194
+ if( astraRenderGrid.sites && astraRenderGrid.sites["par-page"] ) {
195
+ per_page_val = parseInt( astraRenderGrid.sites["par-page"] );
196
+ }
197
+ AstraRender._api_params['per_page'] = per_page_val;
198
+ },
199
+
200
+ _apiAddParam_astra_site_category: function() {
201
+ // Add 'astra-site-category'
202
+ var selected_category_id = jQuery('.filter-links.astra-site-category').find('.current').data('group') || '';
203
+ if( '' !== selected_category_id && 'all' !== selected_category_id ) {
204
+ AstraRender._api_params['astra-site-category'] = selected_category_id;
205
+ } else if( astraRenderGrid.sites && astraRenderGrid['categories'].include ) {
206
+ if( AstraRender._isArray( astraRenderGrid['categories'].include ) ) {
207
+ AstraRender._api_params['astra-site-category'] = astraRenderGrid['categories'].include.join(',');
208
+ } else {
209
+ AstraRender._api_params['astra-site-category'] = astraRenderGrid['categories'].include;
210
+ }
211
+ }
212
+ },
213
+
214
+ _apiAddParam_astra_site_page_builder: function() {
215
+ // Add 'astra-site-page-builder'
216
+ var selected_page_builder_id = jQuery('.filter-links.astra-site-page-builder').find('.current').data('group') || '';
217
+ if( '' !== selected_page_builder_id && 'all' !== selected_page_builder_id ) {
218
+ AstraRender._api_params['astra-site-page-builder'] = selected_page_builder_id;
219
+ } else if( astraRenderGrid.sites && astraRenderGrid['page-builders'].include ) {
220
+ if( AstraRender._isArray( astraRenderGrid['page-builders'].include ) ) {
221
+ AstraRender._api_params['astra-site-page-builder'] = astraRenderGrid['page-builders'].include.join(',');
222
+ } else {
223
+ AstraRender._api_params['astra-site-page-builder'] = astraRenderGrid['page-builders'].include;
224
+ }
225
+ }
226
+ },
227
+
228
+ _apiAddParam_page: function() {
229
+ // Add 'page'
230
+ var page_val = parseInt(jQuery('body').attr('data-astra-demo-paged')) || 1;
231
+ AstraRender._api_params['page'] = page_val;
232
+ },
233
+
234
+ _apiAddParam_purchase_key: function() {
235
+ if( astraRenderGrid.sites && astraRenderGrid.sites.purchase_key ) {
236
+ AstraRender._api_params['purchase_key'] = astraRenderGrid.sites.purchase_key;
237
+ }
238
+ },
239
+
240
+ _apiAddParam_site_url: function() {
241
+ if( astraRenderGrid.sites && astraRenderGrid.sites.site_url ) {
242
+ AstraRender._api_params['site_url'] = astraRenderGrid.sites.site_url;
243
+ }
244
+ },
245
+
246
+ /**
247
+ * Show Sites
248
+ *
249
+ * Params E.g. per_page=<page-id>&astra-site-category=<category-ids>&astra-site-page-builder=<page-builder-ids>&page=<page>
250
+ *
251
+ * @param {Boolean} resetPagedCount Reset Paged Count.
252
+ * @param {String} trigger Filtered Trigger.
253
+ */
254
+ _showSites: function( resetPagedCount, trigger ) {
255
+
256
+ if( undefined === resetPagedCount ) {
257
+ resetPagedCount = true
258
+ }
259
+
260
+ if( undefined === trigger ) {
261
+ trigger = 'astra-api-post-loaded';
262
+ }
263
+
264
+ if( resetPagedCount ) {
265
+ AstraRender._resetPagedCount();
266
+ }
267
+
268
+ // Add Params for API request.
269
+ AstraRender._api_params = {};
270
+
271
+ AstraRender._apiAddParam_status();
272
+ AstraRender._apiAddParam_search();
273
+ AstraRender._apiAddParam_per_page();
274
+ AstraRender._apiAddParam_astra_site_category();
275
+ AstraRender._apiAddParam_astra_site_page_builder();
276
+ AstraRender._apiAddParam_page();
277
+ AstraRender._apiAddParam_site_url();
278
+ AstraRender._apiAddParam_purchase_key();
279
+
280
+ // API Request.
281
+ var api_post = {
282
+ slug: 'astra-sites?' + decodeURIComponent( $.param( AstraRender._api_params ) ),
283
+ trigger: trigger,
284
+ };
285
+
286
+ AstraSitesAPI._api_request( api_post );
287
+
288
+ },
289
+
290
+ /**
291
+ * Get Category Params
292
+ *
293
+ * @since 1.2.4
294
+ * @param {string} category_slug Category Slug.
295
+ * @return {mixed} Add `include=<category-ids>` in API request.
296
+ */
297
+ _getPageBuilderParams: function()
298
+ {
299
+ var _params = {};
300
+
301
+ if( astraRenderGrid.sites && astraRenderGrid.sites.purchase_key ) {
302
+ _params['purchase_key'] = astraRenderGrid.sites.purchase_key;
303
+ }
304
+
305
+ if( astraRenderGrid.sites && astraRenderGrid.sites.site_url ) {
306
+ _params['site_url'] = astraRenderGrid.sites.site_url;
307
+ }
308
+
309
+ if( astraRenderGrid.sites && astraRenderGrid['page-builders'].include ) {
310
+ if( AstraRender._isArray( astraRenderGrid['page-builders'].include ) ) {
311
+ _params['include'] = astraRenderGrid['page-builders'].include.join(',');
312
+ } else {
313
+ _params['include'] = astraRenderGrid['page-builders'].include;
314
+ }
315
+ }
316
+
317
+ var decoded_params = decodeURIComponent( $.param( _params ) );
318
+
319
+ if( decoded_params.length ) {
320
+ return '/?' + decoded_params;
321
+ }
322
+
323
+ return '/';
324
+ },
325
+
326
+ /**
327
+ * Get Category Params
328
+ *
329
+ * @param {string} category_slug Category Slug.
330
+ * @return {mixed} Add `include=<category-ids>` in API request.
331
+ */
332
+ _getCategoryParams: function( category_slug ) {
333
+
334
+ var _params = {};
335
+
336
+ if( astraRenderGrid.sites && astraRenderGrid['categories'].include ) {
337
+ if( AstraRender._isArray( astraRenderGrid['categories'].include ) ) {
338
+ _params['include'] = astraRenderGrid['categories'].include.join(',');
339
+ } else {
340
+ _params['include'] = astraRenderGrid['categories'].include;
341
+ }
342
+ }
343
+
344
+ var decoded_params = decodeURIComponent( $.param( _params ) );
345
+
346
+ if( decoded_params.length ) {
347
+ return '/?' + decoded_params;
348
+ }
349
+
350
+ return '/';
351
+ },
352
+
353
+ /**
354
+ * Get All Select Status
355
+ *
356
+ * @param {string} category_slug Category Slug.
357
+ * @return {boolean} Return true/false.
358
+ */
359
+ _getCategoryAllSelectStatus: function( category_slug ) {
360
+
361
+ // Has category?
362
+ if( category_slug in astraRenderGrid.settings ) {
363
+
364
+ // Has `all` in stored list?
365
+ if( $.inArray('all', astraRenderGrid.settings[ category_slug ]) === -1 ) {
366
+ return false;
367
+ }
368
+ }
369
+
370
+ return true;
371
+ },
372
+
373
+ /**
374
+ * Show Filters
375
+ */
376
+ _loadPageBuilders: function() {
377
+
378
+ /**
379
+ * Page Builder
380
+ */
381
+ var category_slug = 'astra-site-page-builder';
382
+ var category = {
383
+ slug : category_slug + AstraRender._getPageBuilderParams(),
384
+ id : category_slug,
385
+ class : category_slug,
386
+ trigger : 'astra-api-page-builder-loaded',
387
+ wrapper_class : 'filter-links',
388
+ show_all : false,
389
+ };
390
+
391
+ AstraSitesAPI._api_request( category );
392
+ },
393
+
394
+ /**
395
+ * Load First Grid.
396
+ *
397
+ * This is triggered after all category loaded.
398
+ *
399
+ * @param {object} event Event Object.
400
+ */
401
+ _loadFirstGrid: function( event, data ) {
402
+
403
+ event.preventDefault();
404
+
405
+ if( $('#' + data.args.id).length ) {
406
+ var template = wp.template('astra-site-filters');
407
+ $('#' + data.args.id).html(template( data ));
408
+
409
+ if( 'true' === $('body').attr( 'data-default-page-builder-selected' ) ) {
410
+ $('#' + data.args.id).find('li:first a').addClass('current');
411
+ AstraRender._showSites();
412
+ } else {
413
+ $('body').removeClass('loading-content');
414
+ if( ! $('#astra-sites-admin .astra-site-select-page-builder').length ) {
415
+ $('#astra-sites-admin').append( wp.template( 'astra-site-select-page-builder' ) );
416
+ }
417
+ }
418
+ } else {
419
+ AstraRender._showSites();
420
+ }
421
+
422
+ },
423
+
424
+ /**
425
+ * Append filters.
426
+ *
427
+ * @param {object} event Object.
428
+ * @param {object} data API response data.
429
+ */
430
+ _addPageBuilders: function( event, data ) {
431
+ event.preventDefault();
432
+
433
+ if( $('#' + data.args.id).length ) {
434
+ var template = wp.template('astra-site-filters');
435
+ $('#' + data.args.id).html(template( data ));
436
+
437
+ if( 1 === parseInt( data.items_count ) ) {
438
+ $('body').attr( 'data-default-page-builder-selected', true );
439
+ $('#' + data.args.id).find('li:first a').addClass('current');
440
+ }
441
+ }
442
+
443
+ /**
444
+ * Categories
445
+ */
446
+ var category_slug = 'astra-site-category';
447
+ var category = {
448
+ slug : category_slug + AstraRender._getCategoryParams( category_slug ),
449
+ id : category_slug,
450
+ class : category_slug,
451
+ trigger : 'astra-api-category-loaded',
452
+ wrapper_class : 'filter-links',
453
+ show_all : AstraRender._getCategoryAllSelectStatus( category_slug ),
454
+ };
455
+
456
+ AstraSitesAPI._api_request( category );
457
+
458
+ },
459
+
460
+
461
+ /**
462
+ * Append sites on scroll.
463
+ *
464
+ * @param {object} event Object.
465
+ * @param {object} data API response data.
466
+ */
467
+ _reinitGridScrolled: function( event, data ) {
468
+
469
+ var template = wp.template('astra-sites-list');
470
+
471
+ if( data.items.length > 0 ) {
472
+
473
+ $('body').removeClass( 'loading-content' );
474
+ $('.filter-count .count').text( data.items_count );
475
+
476
+ setTimeout(function() {
477
+ jQuery('#astra-sites').append(template( data ));
478
+
479
+ AstraRender._imagesLoaded();
480
+ }, 800);
481
+ } else {
482
+ $('body').addClass('listed-all-sites');
483
+ }
484
+
485
+ },
486
+
487
+ /**
488
+ * Update Astra sites list.
489
+ *
490
+ * @param {object} event Object.
491
+ * @param {object} data API response data.
492
+ */
493
+ _reinitGrid: function( event, data ) {
494
+
495
+ var template = wp.template('astra-sites-list');
496
+
497
+ $('body').addClass( 'page-builder-selected' );
498
+ $('body').removeClass( 'loading-content' );
499
+ $('.filter-count .count').text( data.items_count );
500
+
501
+ jQuery('body').attr('data-astra-demo-last-request', data.items_count);
502
+
503
+ jQuery('#astra-sites').show().html(template( data ));
504
+
505
+ AstraRender._imagesLoaded();
506
+
507
+ $('#astra-sites-admin').find('.spinner').removeClass('is-active');
508
+
509
+ if( data.items_count <= 0 ) {
510
+ $('#astra-sites-admin').find('.spinner').removeClass('is-active');
511
+ $('.no-more-demos').addClass('hide-me');
512
+ $('.astra-sites-suggestions').remove();
513
+
514
+ } else {
515
+ $('body').removeClass('listed-all-sites');
516
+ }
517
+
518
+
519
+ },
520
+
521
+ /**
522
+ * Check image loaded with function `imagesLoaded()`
523
+ */
524
+ _imagesLoaded: function() {
525
+
526
+ var self = jQuery('#sites-filter.execute-only-one-time a');
527
+
528
+ $('.astra-sites-grid').imagesLoaded()
529
+ .always( function( instance ) {
530
+ if( jQuery( window ).outerWidth() > AstraRender._breakpoint ) {
531
+ // $('#astra-sites').masonry('reload');
532
+ }
533
+
534
+ $('#astra-sites-admin').find('.spinner').removeClass('is-active');
535
+ })
536
+ .progress( function( instance, image ) {
537
+ var result = image.isLoaded ? 'loaded' : 'broken';
538
+ });
539
+
540
+ },
541
+
542
+ /**
543
+ * Add Suggestion Box
544
+ */
545
+ _addSuggestionBox: function() {
546
+ $('#astra-sites-admin').find('.spinner').removeClass('is-active').addClass('hide-me');
547
+
548
+ $('#astra-sites-admin').find('.no-more-demos').removeClass('hide-me');
549
+ var template = wp.template('astra-sites-suggestions');
550
+ if( ! $( '.astra-sites-suggestions').length ) {
551
+ $('#astra-sites').append( template );
552
+ }
553
+ },
554
+
555
+ /**
556
+ * Update Page Count.
557
+ */
558
+ _updatedPagedCount: function() {
559
+ paged = parseInt(jQuery('body').attr('data-astra-demo-paged'));
560
+ jQuery('body').attr('data-astra-demo-paged', paged + 1);
561
+ window.setTimeout(function () {
562
+ jQuery('body').data('scrolling', false);
563
+ }, 800);
564
+ },
565
+
566
+ /**
567
+ * Reset Page Count.
568
+ */
569
+ _resetPagedCount: function() {
570
+
571
+ jQuery('body').attr('data-astra-demo-last-request', '1');
572
+ jQuery('body').attr('data-astra-demo-paged', '1');
573
+ jQuery('body').attr('data-astra-demo-search', '');
574
+ jQuery('body').attr('data-scrolling', false);
575
+
576
+ },
577
+
578
+ // Returns if a value is an array
579
+ _isArray: function(value) {
580
+ return value && typeof value === 'object' && value.constructor === Array;
581
+ }
582
+
583
+ };
584
+
585
+ /**
586
+ * Initialize AstraRender
587
+ */
588
+ $(function(){
589
+ AstraRender.init();
590
+ });
591
+
592
  })(jQuery);
inc/classes/class-astra-sites-importer.php CHANGED
@@ -1,334 +1,407 @@
1
- <?php
2
- /**
3
- * Astra Sites Importer
4
- *
5
- * @since 1.0.0
6
- * @package Astra Sites
7
- */
8
-
9
- defined( 'ABSPATH' ) or exit;
10
-
11
- if ( ! class_exists( 'Astra_Sites_Importer' ) ) :
12
-
13
- /**
14
- * Astra Sites Importer
15
- */
16
- class Astra_Sites_Importer {
17
-
18
- /**
19
- * Instance
20
- *
21
- * @since 1.0.0
22
- * @var (Object) Class object
23
- */
24
- public static $_instance = null;
25
-
26
- /**
27
- * Set Instance
28
- *
29
- * @since 1.0.0
30
- *
31
- * @return object Class object.
32
- */
33
- public static function get_instance() {
34
- if ( ! isset( self::$_instance ) ) {
35
- self::$_instance = new self;
36
- }
37
-
38
- return self::$_instance;
39
- }
40
-
41
- /**
42
- * Constructor.
43
- *
44
- * @since 1.0.0
45
- */
46
- public function __construct() {
47
-
48
- require_once ASTRA_SITES_DIR . 'inc/classes/class-astra-sites-importer-log.php';
49
- require_once ASTRA_SITES_DIR . 'inc/importers/class-astra-sites-helper.php';
50
- require_once ASTRA_SITES_DIR . 'inc/importers/class-widgets-importer.php';
51
- require_once ASTRA_SITES_DIR . 'inc/importers/class-astra-customizer-import.php';
52
- require_once ASTRA_SITES_DIR . 'inc/importers/class-astra-site-options-import.php';
53
-
54
- // Import AJAX.
55
- add_action( 'wp_ajax_astra-sites-import-set-site-data', array( $this, 'import_start' ) );
56
- add_action( 'wp_ajax_astra-sites-import-customizer-settings', array( $this, 'import_customizer_settings' ) );
57
- add_action( 'wp_ajax_astra-sites-import-prepare-xml', array( $this, 'prepare_xml_data' ) );
58
- add_action( 'wp_ajax_astra-sites-import-options', array( $this, 'import_options' ) );
59
- add_action( 'wp_ajax_astra-sites-import-widgets', array( $this, 'import_widgets' ) );
60
- add_action( 'wp_ajax_astra-sites-import-end', array( $this, 'import_end' ) );
61
-
62
- // Hooks in AJAX.
63
- add_action( 'astra_sites_import_complete', array( $this, 'clear_cache' ) );
64
- add_action( 'init', array( $this, 'load_importer' ) );
65
-
66
- require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/class-astra-sites-batch-processing.php';
67
-
68
- add_action( 'astra_sites_image_import_complete', array( $this, 'clear_cache' ) );
69
- }
70
-
71
- /**
72
- * Load WordPress WXR importer.
73
- */
74
- public function load_importer() {
75
- require_once ASTRA_SITES_DIR . 'inc/importers/wxr-importer/class-astra-wxr-importer.php';
76
- }
77
-
78
- /**
79
- * Start Site Import
80
- *
81
- * @since 1.1.0
82
- * @return void
83
- */
84
- function import_start() {
85
-
86
- if ( ! current_user_can( 'customize' ) ) {
87
- wp_send_json_error( __( 'You have not "customize" access to import the Astra site.', 'astra-sites' ) );
88
- }
89
-
90
- $demo_api_uri = isset( $_POST['api_url'] ) ? esc_url( $_POST['api_url'] ) : '';
91
-
92
- if ( ! empty( $demo_api_uri ) ) {
93
-
94
- $demo_data = self::get_astra_single_demo( $demo_api_uri );
95
-
96
- update_option( 'astra_sites_import_data', $demo_data );
97
-
98
- if ( is_wp_error( $demo_data ) ) {
99
- wp_send_json_error( $demo_data->get_error_message() );
100
- } else {
101
- $log_file = Astra_Sites_Importer_Log::add_log_file_url();
102
- if ( isset( $log_file['abs_url'] ) && ! empty( $log_file['abs_url'] ) ) {
103
- $demo_data['log_file'] = $log_file['abs_url'];
104
- }
105
- do_action( 'astra_sites_import_start', $demo_data, $demo_api_uri );
106
- }
107
-
108
- wp_send_json_success( $demo_data );
109
-
110
- } else {
111
- wp_send_json_error( __( 'Request site API URL is empty. Try again!', 'astra-sites' ) );
112
- }
113
-
114
- }
115
-
116
- /**
117
- * Import Customizer Settings.
118
- *
119
- * @since 1.0.14
120
- * @return void
121
- */
122
- function import_customizer_settings() {
123
-
124
- do_action( 'astra_sites_import_customizer_settings' );
125
-
126
- $customizer_data = ( isset( $_POST['customizer_data'] ) ) ? (array) json_decode( stripcslashes( $_POST['customizer_data'] ), 1 ) : '';
127
-
128
- if ( isset( $customizer_data ) ) {
129
-
130
- Astra_Customizer_Import::instance()->import( $customizer_data );
131
- wp_send_json_success( $customizer_data );
132
-
133
- } else {
134
- wp_send_json_error( __( 'Customizer data is empty!', 'astra-sites' ) );
135
- }
136
-
137
- }
138
-
139
- /**
140
- * Prepare XML Data.
141
- *
142
- * @since 1.1.0
143
- * @return void
144
- */
145
- function prepare_xml_data() {
146
-
147
- do_action( 'astra_sites_import_prepare_xml_data' );
148
-
149
- if ( ! class_exists( 'XMLReader' ) ) {
150
- wp_send_json_error( __( 'If XMLReader is not available, it imports all other settings and only skips XML import. This creates an incomplete website. We should bail early and not import anything if this is not present.', 'astra-sites' ) );
151
- }
152
-
153
- $wxr_url = ( isset( $_REQUEST['wxr_url'] ) ) ? urldecode( $_REQUEST['wxr_url'] ) : '';
154
-
155
- if ( isset( $wxr_url ) ) {
156
-
157
- // Download XML file.
158
- $xml_path = Astra_Sites_Helper::download_file( $wxr_url );
159
-
160
- if ( $xml_path['success'] ) {
161
- if ( isset( $xml_path['data']['file'] ) ) {
162
- $data = Astra_WXR_Importer::instance()->get_xml_data( $xml_path['data']['file'] );
163
- $data['xml'] = $xml_path['data'];
164
- wp_send_json_success( $data );
165
- } else {
166
- wp_send_json_error( __( 'There was an error downloading the XML file.', 'astra-sites' ) );
167
- }
168
- } else {
169
- wp_send_json_error( $xml_path['data'] );
170
- }
171
- } else {
172
- wp_send_json_error( __( 'Invalid site XML file!', 'astra-sites' ) );
173
- }
174
-
175
- }
176
-
177
- /**
178
- * Import Options.
179
- *
180
- * @since 1.0.14
181
- * @return void
182
- */
183
- function import_options() {
184
-
185
- do_action( 'astra_sites_import_options' );
186
-
187
- $options_data = ( isset( $_POST['options_data'] ) ) ? (array) json_decode( stripcslashes( $_POST['options_data'] ), 1 ) : '';
188
-
189
- if ( isset( $options_data ) ) {
190
- $options_importer = Astra_Site_Options_Import::instance();
191
- $options_importer->import_options( $options_data );
192
- wp_send_json_success( $options_data );
193
- } else {
194
- wp_send_json_error( __( 'Site options are empty!', 'astra-sites' ) );
195
- }
196
-
197
- }
198
-
199
- /**
200
- * Import Widgets.
201
- *
202
- * @since 1.0.14
203
- * @return void
204
- */
205
- function import_widgets() {
206
-
207
- do_action( 'astra_sites_import_widgets' );
208
-
209
- $widgets_data = ( isset( $_POST['widgets_data'] ) ) ? (object) json_decode( stripcslashes( $_POST['widgets_data'] ) ) : '';
210
-
211
- if ( isset( $widgets_data ) ) {
212
- $widgets_importer = Astra_Widget_Importer::instance();
213
- $status = $widgets_importer->import_widgets_data( $widgets_data );
214
- wp_send_json_success( $widgets_data );
215
- } else {
216
- wp_send_json_error( __( 'Widget data is empty!', 'astra-sites' ) );
217
- }
218
-
219
- }
220
-
221
- /**
222
- * Import End.
223
- *
224
- * @since 1.0.14
225
- * @return void
226
- */
227
- function import_end() {
228
- do_action( 'astra_sites_import_complete' );
229
- }
230
-
231
- /**
232
- * Get single demo.
233
- *
234
- * @since 1.0.0
235
- *
236
- * @param (String) $demo_api_uri API URL of a demo.
237
- *
238
- * @return (Array) $astra_demo_data demo data for the demo.
239
- */
240
- public static function get_astra_single_demo( $demo_api_uri ) {
241
-
242
- // default values.
243
- $remote_args = array();
244
- $defaults = array(
245
- 'id' => '',
246
- 'astra-site-widgets-data' => '',
247
- 'astra-site-customizer-data' => '',
248
- 'astra-site-options-data' => '',
249
- 'astra-post-data-mapping' => '',
250
- 'astra-site-wxr-path' => '',
251
- 'astra-enabled-extensions' => '',
252
- 'astra-custom-404' => '',
253
- 'required-plugins' => '',
254
- );
255
-
256
- $api_args = apply_filters(
257
- 'astra_sites_api_args',
258
- array(
259
- 'timeout' => 15,
260
- )
261
- );
262
-
263
- // Use this for premium demos.
264
- $request_params = apply_filters(
265
- 'astra_sites_api_params',
266
- array(
267
- 'purchase_key' => '',
268
- 'site_url' => '',
269
- )
270
- );
271
-
272
- $demo_api_uri = add_query_arg( $request_params, $demo_api_uri );
273
-
274
- // API Call.
275
- $response = wp_remote_get( $demo_api_uri, $api_args );
276
-
277
- if ( is_wp_error( $response ) || ( isset( $response->status ) && 0 == $response->status ) ) {
278
- if ( isset( $response->status ) ) {
279
- $data = json_decode( $response, true );
280
- } else {
281
- return new WP_Error( 'api_invalid_response_code', $response->get_error_message() );
282
- }
283
- } else {
284
- $data = json_decode( wp_remote_retrieve_body( $response ), true );
285
- }
286
-
287
- $data = json_decode( wp_remote_retrieve_body( $response ), true );
288
-
289
- if ( ! isset( $data['code'] ) ) {
290
- $remote_args['id'] = $data['id'];
291
- $remote_args['astra-site-widgets-data'] = json_decode( $data['astra-site-widgets-data'] );
292
- $remote_args['astra-site-customizer-data'] = $data['astra-site-customizer-data'];
293
- $remote_args['astra-site-options-data'] = $data['astra-site-options-data'];
294
- $remote_args['astra-post-data-mapping'] = $data['astra-post-data-mapping'];
295
- $remote_args['astra-site-wxr-path'] = $data['astra-site-wxr-path'];
296
- $remote_args['astra-enabled-extensions'] = $data['astra-enabled-extensions'];
297
- $remote_args['astra-custom-404'] = $data['astra-custom-404'];
298
- $remote_args['required-plugins'] = $data['required-plugins'];
299
- }
300
-
301
- // Merge remote demo and defaults.
302
- return wp_parse_args( $remote_args, $defaults );
303
- }
304
-
305
- /**
306
- * Clear Cache.
307
- *
308
- * @since 1.0.9
309
- */
310
- public function clear_cache() {
311
- // Clear 'Elementor' file cache.
312
- if ( class_exists( '\Elementor\Plugin' ) ) {
313
- Elementor\Plugin::$instance->posts_css_manager->clear_cache();
314
- }
315
-
316
- // Clear 'Builder Builder' cache.
317
- if ( is_callable( 'FLBuilderModel::delete_asset_cache_for_all_posts' ) ) {
318
- FLBuilderModel::delete_asset_cache_for_all_posts();
319
- }
320
-
321
- // Clear 'Astra Addon' cache.
322
- if ( is_callable( 'Astra_Minify::refresh_assets' ) ) {
323
- Astra_Minify::refresh_assets();
324
- }
325
- }
326
-
327
- }
328
-
329
- /**
330
- * Kicking this off by calling 'get_instance()' method
331
- */
332
- Astra_Sites_Importer::get_instance();
333
-
334
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Astra Sites Importer
4
+ *
5
+ * @since 1.0.0
6
+ * @package Astra Sites
7
+ */
8
+
9
+ defined( 'ABSPATH' ) or exit;
10
+
11
+ if ( ! class_exists( 'Astra_Sites_Importer' ) ) :
12
+
13
+ /**
14
+ * Astra Sites Importer
15
+ */
16
+ class Astra_Sites_Importer {
17
+
18
+ /**
19
+ * Instance
20
+ *
21
+ * @since 1.0.0
22
+ * @var (Object) Class object
23
+ */
24
+ public static $_instance = null;
25
+
26
+ /**
27
+ * Set Instance
28
+ *
29
+ * @since 1.0.0
30
+ *
31
+ * @return object Class object.
32
+ */
33
+ public static function get_instance() {
34
+ if ( ! isset( self::$_instance ) ) {
35
+ self::$_instance = new self;
36
+ }
37
+
38
+ return self::$_instance;
39
+ }
40
+
41
+ /**
42
+ * Constructor.
43
+ *
44
+ * @since 1.0.0
45
+ */
46
+ public function __construct() {
47
+
48
+ require_once ASTRA_SITES_DIR . 'inc/classes/class-astra-sites-importer-log.php';
49
+ require_once ASTRA_SITES_DIR . 'inc/importers/class-astra-sites-helper.php';
50
+ require_once ASTRA_SITES_DIR . 'inc/importers/class-widgets-importer.php';
51
+ require_once ASTRA_SITES_DIR . 'inc/importers/class-astra-customizer-import.php';
52
+ require_once ASTRA_SITES_DIR . 'inc/importers/class-astra-site-options-import.php';
53
+
54
+ // Import AJAX.
55
+ add_action( 'wp_ajax_astra-sites-import-set-site-data', array( $this, 'import_start' ) );
56
+ add_action( 'wp_ajax_astra-sites-import-wpforms', array( $this, 'import_wpforms' ) );
57
+ add_action( 'wp_ajax_astra-sites-import-customizer-settings', array( $this, 'import_customizer_settings' ) );
58
+ add_action( 'wp_ajax_astra-sites-import-prepare-xml', array( $this, 'prepare_xml_data' ) );
59
+ add_action( 'wp_ajax_astra-sites-import-options', array( $this, 'import_options' ) );
60
+ add_action( 'wp_ajax_astra-sites-import-widgets', array( $this, 'import_widgets' ) );
61
+ add_action( 'wp_ajax_astra-sites-import-end', array( $this, 'import_end' ) );
62
+
63
+ // Hooks in AJAX.
64
+ add_action( 'astra_sites_import_complete', array( $this, 'clear_cache' ) );
65
+ add_action( 'init', array( $this, 'load_importer' ) );
66
+
67
+ require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/class-astra-sites-batch-processing.php';
68
+
69
+ add_action( 'astra_sites_image_import_complete', array( $this, 'clear_cache' ) );
70
+ }
71
+
72
+ /**
73
+ * Load WordPress WXR importer.
74
+ */
75
+ public function load_importer() {
76
+ require_once ASTRA_SITES_DIR . 'inc/importers/wxr-importer/class-astra-wxr-importer.php';
77
+ }
78
+
79
+ /**
80
+ * Start Site Import
81
+ *
82
+ * @since 1.1.0
83
+ * @return void
84
+ */
85
+ function import_start() {
86
+
87
+ if ( ! current_user_can( 'customize' ) ) {
88
+ wp_send_json_error( __( 'You have not "customize" access to import the Astra site.', 'astra-sites' ) );
89
+ }
90
+
91
+ $demo_api_uri = isset( $_POST['api_url'] ) ? esc_url( $_POST['api_url'] ) : '';
92
+
93
+ if ( ! empty( $demo_api_uri ) ) {
94
+
95
+ $demo_data = self::get_astra_single_demo( $demo_api_uri );
96
+
97
+ update_option( 'astra_sites_import_data', $demo_data );
98
+
99
+ if ( is_wp_error( $demo_data ) ) {
100
+ wp_send_json_error( $demo_data->get_error_message() );
101
+ } else {
102
+ $log_file = Astra_Sites_Importer_Log::add_log_file_url();
103
+ if ( isset( $log_file['url'] ) && ! empty( $log_file['url'] ) ) {
104
+ $demo_data['log_file'] = $log_file['url'];
105
+ }
106
+ do_action( 'astra_sites_import_start', $demo_data, $demo_api_uri );
107
+ }
108
+
109
+ wp_send_json_success( $demo_data );
110
+
111
+ } else {
112
+ wp_send_json_error( __( 'Request site API URL is empty. Try again!', 'astra-sites' ) );
113
+ }
114
+
115
+ }
116
+
117
+ /**
118
+ * Import WP Forms
119
+ *
120
+ * @since 1.2.14
121
+ *
122
+ * @return void
123
+ */
124
+ function import_wpforms() {
125
+
126
+ $wpforms_url = ( isset( $_REQUEST['wpforms_url'] ) ) ? urldecode( $_REQUEST['wpforms_url'] ) : '';
127
+ $ids_mapping = array();
128
+
129
+ if ( ! empty( $wpforms_url ) ) {
130
+
131
+ // Download XML file.
132
+ $xml_path = Astra_Sites_Helper::download_file( $wpforms_url );
133
+
134
+ if ( $xml_path['success'] ) {
135
+ if ( isset( $xml_path['data']['file'] ) ) {
136
+
137
+ $ext = strtolower( pathinfo( $xml_path['data']['file'], PATHINFO_EXTENSION ) );
138
+
139
+ if ( 'json' === $ext ) {
140
+ $forms = json_decode( file_get_contents( $xml_path['data']['file'] ), true );
141
+
142
+ if ( ! empty( $forms ) ) {
143
+
144
+ foreach ( $forms as $form ) {
145
+ $title = ! empty( $form['settings']['form_title'] ) ? $form['settings']['form_title'] : '';
146
+ $desc = ! empty( $form['settings']['form_desc'] ) ? $form['settings']['form_desc'] : '';
147
+
148
+ $new_id = post_exists( $title );
149
+
150
+ if ( ! $new_id ) {
151
+ $new_id = wp_insert_post(
152
+ array(
153
+ 'post_title' => $title,
154
+ 'post_status' => 'publish',
155
+ 'post_type' => 'wpforms',
156
+ 'post_excerpt' => $desc,
157
+ )
158
+ );
159
+ }
160
+
161
+ if ( $new_id ) {
162
+
163
+ // ID mapping.
164
+ $ids_mapping[ $form['id'] ] = $new_id;
165
+
166
+ $form['id'] = $new_id;
167
+ wp_update_post(
168
+ array(
169
+ 'ID' => $new_id,
170
+ 'post_content' => wpforms_encode( $form ),
171
+ )
172
+ );
173
+ }
174
+ }
175
+ }
176
+ }
177
+ }
178
+ }
179
+ }
180
+
181
+ update_option( 'astra_sites_wpforms_ids_mapping', $ids_mapping );
182
+
183
+ wp_send_json_success( $ids_mapping );
184
+ }
185
+
186
+ /**
187
+ * Import Customizer Settings.
188
+ *
189
+ * @since 1.0.14
190
+ * @return void
191
+ */
192
+ function import_customizer_settings() {
193
+
194
+ do_action( 'astra_sites_import_customizer_settings' );
195
+
196
+ $customizer_data = ( isset( $_POST['customizer_data'] ) ) ? (array) json_decode( stripcslashes( $_POST['customizer_data'] ), 1 ) : '';
197
+
198
+ if ( isset( $customizer_data ) ) {
199
+
200
+ Astra_Customizer_Import::instance()->import( $customizer_data );
201
+ wp_send_json_success( $customizer_data );
202
+
203
+ } else {
204
+ wp_send_json_error( __( 'Customizer data is empty!', 'astra-sites' ) );
205
+ }
206
+
207
+ }
208
+
209
+ /**
210
+ * Prepare XML Data.
211
+ *
212
+ * @since 1.1.0
213
+ * @return void
214
+ */
215
+ function prepare_xml_data() {
216
+
217
+ do_action( 'astra_sites_import_prepare_xml_data' );
218
+
219
+ if ( ! class_exists( 'XMLReader' ) ) {
220
+ wp_send_json_error( __( 'If XMLReader is not available, it imports all other settings and only skips XML import. This creates an incomplete website. We should bail early and not import anything if this is not present.', 'astra-sites' ) );
221
+ }
222
+
223
+ $wxr_url = ( isset( $_REQUEST['wxr_url'] ) ) ? urldecode( $_REQUEST['wxr_url'] ) : '';
224
+
225
+ if ( isset( $wxr_url ) ) {
226
+
227
+ // Download XML file.
228
+ $xml_path = Astra_Sites_Helper::download_file( $wxr_url );
229
+
230
+ if ( $xml_path['success'] ) {
231
+ if ( isset( $xml_path['data']['file'] ) ) {
232
+ $data = Astra_WXR_Importer::instance()->get_xml_data( $xml_path['data']['file'] );
233
+ $data['xml'] = $xml_path['data'];
234
+ wp_send_json_success( $data );
235
+ } else {
236
+ wp_send_json_error( __( 'There was an error downloading the XML file.', 'astra-sites' ) );
237
+ }
238
+ } else {
239
+ wp_send_json_error( $xml_path['data'] );
240
+ }
241
+ } else {
242
+ wp_send_json_error( __( 'Invalid site XML file!', 'astra-sites' ) );
243
+ }
244
+
245
+ }
246
+
247
+ /**
248
+ * Import Options.
249
+ *
250
+ * @since 1.0.14
251
+ * @return void
252
+ */
253
+ function import_options() {
254
+
255
+ do_action( 'astra_sites_import_options' );
256
+
257
+ $options_data = ( isset( $_POST['options_data'] ) ) ? (array) json_decode( stripcslashes( $_POST['options_data'] ), 1 ) : '';
258
+
259
+ if ( isset( $options_data ) ) {
260
+ $options_importer = Astra_Site_Options_Import::instance();
261
+ $options_importer->import_options( $options_data );
262
+ wp_send_json_success( $options_data );
263
+ } else {
264
+ wp_send_json_error( __( 'Site options are empty!', 'astra-sites' ) );
265
+ }
266
+
267
+ }
268
+
269
+ /**
270
+ * Import Widgets.
271
+ *
272
+ * @since 1.0.14
273
+ * @return void
274
+ */
275
+ function import_widgets() {
276
+
277
+ do_action( 'astra_sites_import_widgets' );
278
+
279
+ $widgets_data = ( isset( $_POST['widgets_data'] ) ) ? (object) json_decode( stripcslashes( $_POST['widgets_data'] ) ) : '';
280
+
281
+ if ( isset( $widgets_data ) ) {
282
+ $widgets_importer = Astra_Widget_Importer::instance();
283
+ $status = $widgets_importer->import_widgets_data( $widgets_data );
284
+ wp_send_json_success( $widgets_data );
285
+ } else {
286
+ wp_send_json_error( __( 'Widget data is empty!', 'astra-sites' ) );
287
+ }
288
+
289
+ }
290
+
291
+ /**
292
+ * Import End.
293
+ *
294
+ * @since 1.0.14
295
+ * @return void
296
+ */
297
+ function import_end() {
298
+ do_action( 'astra_sites_import_complete' );
299
+ }
300
+
301
+
302
+ /**
303
+ * Get single demo.
304
+ *
305
+ * @since 1.0.0
306
+ *
307
+ * @param (String) $demo_api_uri API URL of a demo.
308
+ *
309
+ * @return (Array) $astra_demo_data demo data for the demo.
310
+ */
311
+ public static function get_astra_single_demo( $demo_api_uri ) {
312
+
313
+ // default values.
314
+ $remote_args = array();
315
+ $defaults = array(
316
+ 'id' => '',
317
+ 'astra-site-widgets-data' => '',
318
+ 'astra-site-customizer-data' => '',
319
+ 'astra-site-options-data' => '',
320
+ 'astra-post-data-mapping' => '',
321
+ 'astra-site-wxr-path' => '',
322
+ 'astra-site-wpforms-path' => '',
323
+ 'astra-enabled-extensions' => '',
324
+ 'astra-custom-404' => '',
325
+ 'required-plugins' => '',
326
+ );
327
+
328
+ $api_args = apply_filters(
329
+ 'astra_sites_api_args',
330
+ array(
331
+ 'timeout' => 15,
332
+ )
333
+ );
334
+
335
+ // Use this for premium demos.
336
+ $request_params = apply_filters(
337
+ 'astra_sites_api_params',
338
+ array(
339
+ 'purchase_key' => '',
340
+ 'site_url' => '',
341
+ )
342
+ );
343
+
344
+ $demo_api_uri = add_query_arg( $request_params, $demo_api_uri );
345
+
346
+ // API Call.
347
+ $response = wp_remote_get( $demo_api_uri, $api_args );
348
+
349
+ if ( is_wp_error( $response ) || ( isset( $response->status ) && 0 == $response->status ) ) {
350
+ if ( isset( $response->status ) ) {
351
+ $data = json_decode( $response, true );
352
+ } else {
353
+ return new WP_Error( 'api_invalid_response_code', $response->get_error_message() );
354
+ }
355
+ } else {
356
+ $data = json_decode( wp_remote_retrieve_body( $response ), true );
357
+ }
358
+
359
+ $data = json_decode( wp_remote_retrieve_body( $response ), true );
360
+
361
+ if ( ! isset( $data['code'] ) ) {
362
+ $remote_args['id'] = $data['id'];
363
+ $remote_args['astra-site-widgets-data'] = json_decode( $data['astra-site-widgets-data'] );
364
+ $remote_args['astra-site-customizer-data'] = $data['astra-site-customizer-data'];
365
+ $remote_args['astra-site-options-data'] = $data['astra-site-options-data'];
366
+ $remote_args['astra-post-data-mapping'] = $data['astra-post-data-mapping'];
367
+ $remote_args['astra-site-wxr-path'] = $data['astra-site-wxr-path'];
368
+ $remote_args['astra-site-wpforms-path'] = $data['astra-site-wpforms-path'];
369
+ $remote_args['astra-enabled-extensions'] = $data['astra-enabled-extensions'];
370
+ $remote_args['astra-custom-404'] = $data['astra-custom-404'];
371
+ $remote_args['required-plugins'] = $data['required-plugins'];
372
+ }
373
+
374
+ // Merge remote demo and defaults.
375
+ return wp_parse_args( $remote_args, $defaults );
376
+ }
377
+
378
+ /**
379
+ * Clear Cache.
380
+ *
381
+ * @since 1.0.9
382
+ */
383
+ public function clear_cache() {
384
+ // Clear 'Elementor' file cache.
385
+ if ( class_exists( '\Elementor\Plugin' ) ) {
386
+ Elementor\Plugin::$instance->posts_css_manager->clear_cache();
387
+ }
388
+
389
+ // Clear 'Builder Builder' cache.
390
+ if ( is_callable( 'FLBuilderModel::delete_asset_cache_for_all_posts' ) ) {
391
+ FLBuilderModel::delete_asset_cache_for_all_posts();
392
+ }
393
+
394
+ // Clear 'Astra Addon' cache.
395
+ if ( is_callable( 'Astra_Minify::refresh_assets' ) ) {
396
+ Astra_Minify::refresh_assets();
397
+ }
398
+ }
399
+
400
+ }
401
+
402
+ /**
403
+ * Kicking this off by calling 'get_instance()' method
404
+ */
405
+ Astra_Sites_Importer::get_instance();
406
+
407
+ endif;
inc/classes/class-astra-sites.php CHANGED
@@ -1,468 +1,471 @@
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 get_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
- self::set_api_url();
57
-
58
- $this->includes();
59
-
60
- add_action( 'admin_notices', array( $this, 'add_notice' ), 1 );
61
- add_action( 'admin_notices', array( $this, 'admin_notices' ) );
62
- add_action( 'plugins_loaded', array( $this, 'load_textdomain' ) );
63
- add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue' ) );
64
-
65
- // AJAX.
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
- * Add Admin Notice.
72
- */
73
- function add_notice() {
74
-
75
- Astra_Sites_Notices::add_notice(
76
- array(
77
- 'id' => 'astra-theme-activation-nag',
78
- 'type' => 'error',
79
- 'show_if' => ( ! defined( 'ASTRA_THEME_SETTINGS' ) ) ? true : false,
80
- /* translators: 1: theme.php file*/
81
- 'message' => sprintf( __( 'Astra Theme needs to be active for you to use currently installed "%1$s" plugin. <a href="%2$s">Install & Activate Now</a>', 'astra-sites' ), ASTRA_SITES_NAME, esc_url( admin_url( 'themes.php?theme=astra' ) ) ),
82
- 'dismissible' => true,
83
- 'dismissible-time' => WEEK_IN_SECONDS,
84
- )
85
- );
86
-
87
- }
88
-
89
- /**
90
- * Loads textdomain for the plugin.
91
- *
92
- * @since 1.0.1
93
- */
94
- function load_textdomain() {
95
- load_plugin_textdomain( 'astra-sites' );
96
- }
97
-
98
- /**
99
- * Admin Notices
100
- *
101
- * @since 1.0.5
102
- * @return void
103
- */
104
- function admin_notices() {
105
-
106
- if ( ! defined( 'ASTRA_THEME_SETTINGS' ) ) {
107
- return;
108
- }
109
-
110
- add_action( 'plugin_action_links_' . ASTRA_SITES_BASE, array( $this, 'action_links' ) );
111
- }
112
-
113
- /**
114
- * Show action links on the plugin screen.
115
- *
116
- * @param mixed $links Plugin Action links.
117
- * @return array
118
- */
119
- function action_links( $links ) {
120
- $action_links = array(
121
- 'settings' => '<a href="' . admin_url( 'themes.php?page=astra-sites' ) . '" aria-label="' . esc_attr__( 'See Library', 'astra-sites' ) . '">' . esc_html__( 'See Library', 'astra-sites' ) . '</a>',
122
- );
123
-
124
- return array_merge( $action_links, $links );
125
- }
126
-
127
- /**
128
- * Setter for $api_url
129
- *
130
- * @since 1.0.0
131
- */
132
- public static function set_api_url() {
133
-
134
- self::$api_url = apply_filters( 'astra_sites_api_url', 'https://websitedemos.net/wp-json/wp/v2/' );
135
-
136
- }
137
-
138
- /**
139
- * Enqueue admin scripts.
140
- *
141
- * @since 1.0.5 Added 'getUpgradeText' and 'getUpgradeURL' localize variables.
142
- *
143
- * @since 1.0.0
144
- *
145
- * @param string $hook Current hook name.
146
- * @return void
147
- */
148
- public function admin_enqueue( $hook = '' ) {
149
-
150
- if ( 'appearance_page_astra-sites' !== $hook ) {
151
- return;
152
- }
153
-
154
- global $is_IE, $is_edge;
155
-
156
- if ( $is_IE || $is_edge ) {
157
- wp_enqueue_script( 'astra-sites-eventsource', ASTRA_SITES_URI . 'inc/assets/js/eventsource.min.js', array( 'jquery', 'wp-util', 'updates' ), ASTRA_SITES_VER, true );
158
- }
159
-
160
- // API.
161
- wp_register_script( 'astra-sites-api', ASTRA_SITES_URI . 'inc/assets/js/astra-sites-api.js', array( 'jquery' ), ASTRA_SITES_VER, true );
162
-
163
- // Admin Page.
164
- wp_enqueue_style( 'astra-sites-admin', ASTRA_SITES_URI . 'inc/assets/css/admin.css', ASTRA_SITES_VER, true );
165
- wp_enqueue_script( 'astra-sites-admin-page', ASTRA_SITES_URI . 'inc/assets/js/admin-page.js', array( 'jquery', 'wp-util', 'updates' ), ASTRA_SITES_VER, true );
166
- wp_enqueue_script( 'astra-sites-render-grid', ASTRA_SITES_URI . 'inc/assets/js/render-grid.js', array( 'wp-util', 'astra-sites-api', 'imagesloaded', 'jquery' ), ASTRA_SITES_VER, true );
167
-
168
- $data = apply_filters(
169
- 'astra_sites_localize_vars',
170
- array(
171
- 'ApiURL' => self::$api_url,
172
- 'filters' => array(
173
- 'page_builder' => array(
174
- 'title' => __( 'Page Builder', 'astra-sites' ),
175
- 'slug' => 'astra-site-page-builder',
176
- 'trigger' => 'astra-api-category-loaded',
177
- ),
178
- 'categories' => array(
179
- 'title' => __( 'Categories', 'astra-sites' ),
180
- 'slug' => 'astra-site-category',
181
- 'trigger' => 'astra-api-category-loaded',
182
- ),
183
- ),
184
- )
185
- );
186
- wp_localize_script( 'astra-sites-api', 'astraSitesApi', $data );
187
-
188
- // Use this for premium demos.
189
- $request_params = apply_filters(
190
- 'astra_sites_api_params',
191
- array(
192
- 'purchase_key' => '',
193
- 'site_url' => '',
194
- 'par-page' => 15,
195
- )
196
- );
197
-
198
- $data = apply_filters(
199
- 'astra_sites_render_localize_vars',
200
- array(
201
- 'sites' => $request_params,
202
- 'page-builders' => array(),
203
- 'categories' => array(),
204
- 'settings' => array(),
205
- )
206
- );
207
-
208
- wp_localize_script( 'astra-sites-render-grid', 'astraRenderGrid', $data );
209
-
210
- $data = apply_filters(
211
- 'astra_sites_localize_vars',
212
- array(
213
- 'debug' => ( ( defined( 'WP_DEBUG' ) && WP_DEBUG ) || isset( $_GET['debug'] ) ) ? true : false,
214
- 'isPro' => defined( 'ASTRA_PRO_SITES_NAME' ) ? true : false,
215
- 'isWhiteLabeled' => Astra_Sites_White_Label::get_instance()->is_white_labeled(),
216
- 'ajaxurl' => esc_url( admin_url( 'admin-ajax.php' ) ),
217
- 'siteURL' => site_url(),
218
- 'getProText' => __( 'Get Agency Bundle', 'astra-sites' ),
219
- 'getProURL' => esc_url( 'https://wpastra.com/agency/?utm_source=demo-import-panel&utm_campaign=astra-sites&utm_medium=wp-dashboard' ),
220
- 'getUpgradeText' => __( 'Upgrade', 'astra-sites' ),
221
- 'getUpgradeURL' => esc_url( 'https://wpastra.com/agency/?utm_source=demo-import-panel&utm_campaign=astra-sites&utm_medium=wp-dashboard' ),
222
- '_ajax_nonce' => wp_create_nonce( 'astra-sites' ),
223
- 'requiredPlugins' => array(),
224
- 'XMLReaderDisabled' => ! class_exists( 'XMLReader' ) ? true : false,
225
- 'strings' => array(
226
- /* translators: %s are HTML tags. */
227
- 'warningXMLReader' => sprintf( __( '%1$sRequired XMLReader PHP extension is missing on your server!%2$sAstra Sites import requires XMLReader extension to be installed. Please contact your web hosting provider and ask them to install and activate the XMLReader PHP extension.', 'astra-sites' ), '<div class="notice astra-sites-xml-notice notice-error"><p><b>', '</b></p><p>', '</p></div>' ),
228
- 'warningBeforeCloseWindow' => __( 'Warning! Astra Site Import process is not complete. Don\'t close the window until import process complete. Do you still want to leave the window?', 'astra-sites' ),
229
- 'importFailedBtnSmall' => __( 'Error!', 'astra-sites' ),
230
- 'importFailedBtnLarge' => __( 'Error! Read Possibilities.', 'astra-sites' ),
231
- 'importFailedURL' => esc_url( 'https://wpastra.com/docs/?p=1314&utm_source=demo-import-panel&utm_campaign=astra-sites&utm_medium=import-failed' ),
232
- 'viewSite' => __( 'Done! View Site', 'astra-sites' ),
233
- 'btnActivating' => __( 'Activating', 'astra-sites' ) . '&hellip;',
234
- 'btnActive' => __( 'Active', 'astra-sites' ),
235
- 'importFailBtn' => __( 'Import failed.', 'astra-sites' ),
236
- 'importFailBtnLarge' => __( 'Import failed. See error log.', 'astra-sites' ),
237
- 'importDemo' => __( 'Import This Site', 'astra-sites' ),
238
- 'importingDemo' => __( 'Importing..', 'astra-sites' ),
239
- 'DescExpand' => __( 'Read more', 'astra-sites' ) . '&hellip;',
240
- 'DescCollapse' => __( 'Hide', 'astra-sites' ),
241
- 'responseError' => __( 'There was a problem receiving a response from server.', 'astra-sites' ),
242
- 'searchNoFound' => __( 'No Demos found, Try a different search.', 'astra-sites' ),
243
- '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' ),
244
- ),
245
- 'log' => array(
246
- 'installingPlugin' => __( 'Installing plugin ', 'astra-sites' ),
247
- 'installed' => __( 'Successfully plugin installed!', 'astra-sites' ),
248
- 'activating' => __( 'Activating plugin ', 'astra-sites' ),
249
- 'activated' => __( 'Successfully plugin activated ', 'astra-sites' ),
250
- 'bulkActivation' => __( 'Bulk plugin activation...', 'astra-sites' ),
251
- 'activate' => __( 'Successfully plugin activate - ', 'astra-sites' ),
252
- 'activationError' => __( 'Error! While activating plugin - ', 'astra-sites' ),
253
- 'bulkInstall' => __( 'Bulk plugin installation...', 'astra-sites' ),
254
- 'api' => __( 'Site API ', 'astra-sites' ),
255
- 'importing' => __( 'Importing..', 'astra-sites' ),
256
- 'processingRequest' => __( 'Processing requests...', 'astra-sites' ),
257
- 'importCustomizer' => __( '1) Importing "Customizer Settings"...', 'astra-sites' ),
258
- 'importCustomizerSuccess' => __( 'Successfully imported customizer settings!', 'astra-sites' ),
259
- 'importXMLPrepare' => __( '2) Preparing "XML" Data...', 'astra-sites' ),
260
- 'importXMLPrepareSuccess' => __( 'Successfully set XML data!', 'astra-sites' ),
261
- 'importXML' => __( '3) Importing "XML"...', 'astra-sites' ),
262
- 'importXMLSuccess' => __( 'Successfully imported XML!', 'astra-sites' ),
263
- 'importOptions' => __( '4) Importing "Options"...', 'astra-sites' ),
264
- 'importOptionsSuccess' => __( 'Successfully imported Options!', 'astra-sites' ),
265
- 'importWidgets' => __( '5) Importing "Widgets"...', 'astra-sites' ),
266
- 'importWidgetsSuccess' => __( 'Successfully imported Widgets!', 'astra-sites' ),
267
- 'serverConfiguration' => esc_url( 'https://wpastra.com/docs/?p=1314&utm_source=demo-import-panel&utm_campaign=import-error&utm_medium=wp-dashboard' ),
268
- 'success' => __( 'Site imported successfully! visit : ', 'astra-sites' ),
269
- 'gettingData' => __( 'Getting Site Information..', 'astra-sites' ),
270
- 'importingCustomizer' => __( 'Importing Customizer Settings..', 'astra-sites' ),
271
- 'importXMLPreparing' => __( 'Setting up import data..', 'astra-sites' ),
272
- 'importingXML' => __( 'Importing Pages, Posts & Media..', 'astra-sites' ),
273
- 'importingOptions' => __( 'Importing Site Options..', 'astra-sites' ),
274
- 'importingWidgets' => __( 'Importing Widgets..', 'astra-sites' ),
275
- 'importComplete' => __( 'Import Complete..', 'astra-sites' ),
276
- 'preview' => __( 'Previewing ', 'astra-sites' ),
277
- 'importLogText' => __( 'See Error Log &rarr;', 'astra-sites' ),
278
- ),
279
- )
280
- );
281
-
282
- wp_localize_script( 'astra-sites-admin-page', 'astraSitesAdmin', $data );
283
-
284
- }
285
-
286
- /**
287
- * Load all the required files in the importer.
288
- *
289
- * @since 1.0.0
290
- */
291
- private function includes() {
292
-
293
- require_once ASTRA_SITES_DIR . 'inc/classes/class-astra-sites-notices.php';
294
- require_once ASTRA_SITES_DIR . 'inc/classes/class-astra-sites-page.php';
295
- require_once ASTRA_SITES_DIR . 'inc/classes/compatibility/class-astra-sites-compatibility.php';
296
- require_once ASTRA_SITES_DIR . 'inc/classes/class-astra-sites-white-label.php';
297
- require_once ASTRA_SITES_DIR . 'inc/classes/class-astra-sites-importer.php';
298
-
299
- }
300
-
301
- /**
302
- * Required Plugin Activate
303
- *
304
- * @since 1.0.0
305
- */
306
- public function required_plugin_activate() {
307
-
308
- if ( ! current_user_can( 'install_plugins' ) || ! isset( $_POST['init'] ) || ! $_POST['init'] ) {
309
- wp_send_json_error(
310
- array(
311
- 'success' => false,
312
- 'message' => __( 'No plugin specified', 'astra-sites' ),
313
- )
314
- );
315
- }
316
-
317
- $data = array();
318
- $plugin_init = ( isset( $_POST['init'] ) ) ? esc_attr( $_POST['init'] ) : '';
319
- $astra_site_options = ( isset( $_POST['options'] ) ) ? json_decode( stripslashes( $_POST['options'] ) ) : '';
320
- $enabled_extensions = ( isset( $_POST['enabledExtensions'] ) ) ? json_decode( stripslashes( $_POST['enabledExtensions'] ) ) : '';
321
-
322
- $data['astra_site_options'] = $astra_site_options;
323
- $data['enabled_extensions'] = $enabled_extensions;
324
-
325
- $activate = activate_plugin( $plugin_init, '', false, true );
326
-
327
- if ( is_wp_error( $activate ) ) {
328
- wp_send_json_error(
329
- array(
330
- 'success' => false,
331
- 'message' => $activate->get_error_message(),
332
- )
333
- );
334
- }
335
-
336
- do_action( 'astra_sites_after_plugin_activation', $plugin_init, $data );
337
-
338
- wp_send_json_success(
339
- array(
340
- 'success' => true,
341
- 'message' => __( 'Plugin Successfully Activated', 'astra-sites' ),
342
- )
343
- );
344
-
345
- }
346
-
347
- /**
348
- * Required Plugin
349
- *
350
- * @since 1.0.0
351
- * @return void
352
- */
353
- public function required_plugin() {
354
-
355
- // Verify Nonce.
356
- check_ajax_referer( 'astra-sites', '_ajax_nonce' );
357
-
358
- $response = array(
359
- 'active' => array(),
360
- 'inactive' => array(),
361
- 'notinstalled' => array(),
362
- );
363
-
364
- if ( ! current_user_can( 'customize' ) ) {
365
- wp_send_json_error( $response );
366
- }
367
-
368
- $required_plugins = ( isset( $_POST['required_plugins'] ) ) ? $_POST['required_plugins'] : array();
369
-
370
- if ( count( $required_plugins ) > 0 ) {
371
- foreach ( $required_plugins as $key => $plugin ) {
372
-
373
- /**
374
- * Has Pro Version Support?
375
- * And
376
- * Is Pro Version Installed?
377
- */
378
- $plugin_pro = self::pro_plugin_exist( $plugin['init'] );
379
- if ( $plugin_pro ) {
380
-
381
- // Pro - Active.
382
- if ( is_plugin_active( $plugin_pro['init'] ) ) {
383
- $response['active'][] = $plugin_pro;
384
-
385
- // Pro - Inactive.
386
- } else {
387
- $response['inactive'][] = $plugin_pro;
388
- }
389
- } else {
390
-
391
- // Lite - Installed but Inactive.
392
- if ( file_exists( WP_PLUGIN_DIR . '/' . $plugin['init'] ) && is_plugin_inactive( $plugin['init'] ) ) {
393
-
394
- $response['inactive'][] = $plugin;
395
-
396
- // Lite - Not Installed.
397
- } elseif ( ! file_exists( WP_PLUGIN_DIR . '/' . $plugin['init'] ) ) {
398
-
399
- $response['notinstalled'][] = $plugin;
400
-
401
- // Lite - Active.
402
- } else {
403
- $response['active'][] = $plugin;
404
- }
405
- }
406
- }
407
- }
408
-
409
- // Send response.
410
- wp_send_json_success( $response );
411
- }
412
-
413
- /**
414
- * Has Pro Version Support?
415
- * And
416
- * Is Pro Version Installed?
417
- *
418
- * Check Pro plugin version exist of requested plugin lite version.
419
- *
420
- * Eg. If plugin 'BB Lite Version' required to import demo. Then we check the 'BB Agency Version' is exist?
421
- * If yes then we only 'Activate' Agency Version. [We couldn't install agency version.]
422
- * Else we 'Activate' or 'Install' Lite Version.
423
- *
424
- * @since 1.0.1
425
- *
426
- * @param string $lite_version Lite version init file.
427
- * @return mixed Return false if not installed or not supported by us
428
- * else return 'Pro' version details.
429
- */
430
- public static function pro_plugin_exist( $lite_version = '' ) {
431
-
432
- // Lite init => Pro init.
433
- $plugins = apply_filters(
434
- 'astra_sites_pro_plugin_exist',
435
- array(
436
- 'beaver-builder-lite-version/fl-builder.php' => array(
437
- 'slug' => 'bb-plugin',
438
- 'init' => 'bb-plugin/fl-builder.php',
439
- 'name' => 'Beaver Builder Plugin',
440
- ),
441
- 'ultimate-addons-for-beaver-builder-lite/bb-ultimate-addon.php' => array(
442
- 'slug' => 'bb-ultimate-addon',
443
- 'init' => 'bb-ultimate-addon/bb-ultimate-addon.php',
444
- 'name' => 'Ultimate Addon for Beaver Builder',
445
- ),
446
- ),
447
- $lite_version
448
- );
449
-
450
- if ( isset( $plugins[ $lite_version ] ) ) {
451
-
452
- // Pro plugin directory exist?
453
- if ( file_exists( WP_PLUGIN_DIR . '/' . $plugins[ $lite_version ]['init'] ) ) {
454
- return $plugins[ $lite_version ];
455
- }
456
- }
457
-
458
- return false;
459
- }
460
-
461
- }
462
-
463
- /**
464
- * Kicking this off by calling 'get_instance()' method
465
- */
466
- Astra_Sites::get_instance();
467
-
468
- endif;
 
 
 
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 get_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
+ self::set_api_url();
57
+
58
+ $this->includes();
59
+
60
+ add_action( 'admin_notices', array( $this, 'add_notice' ), 1 );
61
+ add_action( 'admin_notices', array( $this, 'admin_notices' ) );
62
+ add_action( 'plugins_loaded', array( $this, 'load_textdomain' ) );
63
+ add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue' ) );
64
+
65
+ // AJAX.
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
+ * Add Admin Notice.
72
+ */
73
+ function add_notice() {
74
+
75
+ Astra_Sites_Notices::add_notice(
76
+ array(
77
+ 'id' => 'astra-theme-activation-nag',
78
+ 'type' => 'error',
79
+ 'show_if' => ( ! defined( 'ASTRA_THEME_SETTINGS' ) ) ? true : false,
80
+ /* translators: 1: theme.php file*/
81
+ 'message' => sprintf( __( 'Astra Theme needs to be active for you to use currently installed "%1$s" plugin. <a href="%2$s">Install & Activate Now</a>', 'astra-sites' ), ASTRA_SITES_NAME, esc_url( admin_url( 'themes.php?theme=astra' ) ) ),
82
+ 'dismissible' => true,
83
+ 'dismissible-time' => WEEK_IN_SECONDS,
84
+ )
85
+ );
86
+
87
+ }
88
+
89
+ /**
90
+ * Loads textdomain for the plugin.
91
+ *
92
+ * @since 1.0.1
93
+ */
94
+ function load_textdomain() {
95
+ load_plugin_textdomain( 'astra-sites' );
96
+ }
97
+
98
+ /**
99
+ * Admin Notices
100
+ *
101
+ * @since 1.0.5
102
+ * @return void
103
+ */
104
+ function admin_notices() {
105
+
106
+ if ( ! defined( 'ASTRA_THEME_SETTINGS' ) ) {
107
+ return;
108
+ }
109
+
110
+ add_action( 'plugin_action_links_' . ASTRA_SITES_BASE, array( $this, 'action_links' ) );
111
+ }
112
+
113
+ /**
114
+ * Show action links on the plugin screen.
115
+ *
116
+ * @param mixed $links Plugin Action links.
117
+ * @return array
118
+ */
119
+ function action_links( $links ) {
120
+ $action_links = array(
121
+ 'settings' => '<a href="' . admin_url( 'themes.php?page=astra-sites' ) . '" aria-label="' . esc_attr__( 'See Library', 'astra-sites' ) . '">' . esc_html__( 'See Library', 'astra-sites' ) . '</a>',
122
+ );
123
+
124
+ return array_merge( $action_links, $links );
125
+ }
126
+
127
+ /**
128
+ * Setter for $api_url
129
+ *
130
+ * @since 1.0.0
131
+ */
132
+ public static function set_api_url() {
133
+
134
+ self::$api_url = apply_filters( 'astra_sites_api_url', 'https://websitedemos.net/wp-json/wp/v2/' );
135
+
136
+ }
137
+
138
+ /**
139
+ * Enqueue admin scripts.
140
+ *
141
+ * @since 1.0.5 Added 'getUpgradeText' and 'getUpgradeURL' localize variables.
142
+ *
143
+ * @since 1.0.0
144
+ *
145
+ * @param string $hook Current hook name.
146
+ * @return void
147
+ */
148
+ public function admin_enqueue( $hook = '' ) {
149
+
150
+ if ( 'appearance_page_astra-sites' !== $hook ) {
151
+ return;
152
+ }
153
+
154
+ global $is_IE, $is_edge;
155
+
156
+ if ( $is_IE || $is_edge ) {
157
+ wp_enqueue_script( 'astra-sites-eventsource', ASTRA_SITES_URI . 'inc/assets/js/eventsource.min.js', array( 'jquery', 'wp-util', 'updates' ), ASTRA_SITES_VER, true );
158
+ }
159
+
160
+ // API.
161
+ wp_register_script( 'astra-sites-api', ASTRA_SITES_URI . 'inc/assets/js/astra-sites-api.js', array( 'jquery' ), ASTRA_SITES_VER, true );
162
+
163
+ // Admin Page.
164
+ wp_enqueue_style( 'astra-sites-admin', ASTRA_SITES_URI . 'inc/assets/css/admin.css', ASTRA_SITES_VER, true );
165
+ wp_enqueue_script( 'astra-sites-admin-page', ASTRA_SITES_URI . 'inc/assets/js/admin-page.js', array( 'jquery', 'wp-util', 'updates' ), ASTRA_SITES_VER, true );
166
+ wp_enqueue_script( 'astra-sites-render-grid', ASTRA_SITES_URI . 'inc/assets/js/render-grid.js', array( 'wp-util', 'astra-sites-api', 'imagesloaded', 'jquery' ), ASTRA_SITES_VER, true );
167
+
168
+ $data = apply_filters(
169
+ 'astra_sites_localize_vars',
170
+ array(
171
+ 'ApiURL' => self::$api_url,
172
+ 'filters' => array(
173
+ 'page_builder' => array(
174
+ 'title' => __( 'Page Builder', 'astra-sites' ),
175
+ 'slug' => 'astra-site-page-builder',
176
+ 'trigger' => 'astra-api-category-loaded',
177
+ ),
178
+ 'categories' => array(
179
+ 'title' => __( 'Categories', 'astra-sites' ),
180
+ 'slug' => 'astra-site-category',
181
+ 'trigger' => 'astra-api-category-loaded',
182
+ ),
183
+ ),
184
+ )
185
+ );
186
+ wp_localize_script( 'astra-sites-api', 'astraSitesApi', $data );
187
+
188
+ // Use this for premium demos.
189
+ $request_params = apply_filters(
190
+ 'astra_sites_api_params',
191
+ array(
192
+ 'purchase_key' => '',
193
+ 'site_url' => '',
194
+ 'par-page' => 15,
195
+ )
196
+ );
197
+
198
+ $data = apply_filters(
199
+ 'astra_sites_render_localize_vars',
200
+ array(
201
+ 'sites' => $request_params,
202
+ 'page-builders' => array(),
203
+ 'categories' => array(),
204
+ 'settings' => array(),
205
+ )
206
+ );
207
+
208
+ wp_localize_script( 'astra-sites-render-grid', 'astraRenderGrid', $data );
209
+
210
+ $data = apply_filters(
211
+ 'astra_sites_localize_vars',
212
+ array(
213
+ 'debug' => ( ( defined( 'WP_DEBUG' ) && WP_DEBUG ) || isset( $_GET['debug'] ) ) ? true : false,
214
+ 'isPro' => defined( 'ASTRA_PRO_SITES_NAME' ) ? true : false,
215
+ 'isWhiteLabeled' => Astra_Sites_White_Label::get_instance()->is_white_labeled(),
216
+ 'ajaxurl' => esc_url( admin_url( 'admin-ajax.php' ) ),
217
+ 'siteURL' => site_url(),
218
+ 'getProText' => __( 'Get Agency Bundle', 'astra-sites' ),
219
+ 'getProURL' => esc_url( 'https://wpastra.com/agency/?utm_source=demo-import-panel&utm_campaign=astra-sites&utm_medium=wp-dashboard' ),
220
+ 'getUpgradeText' => __( 'Upgrade', 'astra-sites' ),
221
+ 'getUpgradeURL' => esc_url( 'https://wpastra.com/agency/?utm_source=demo-import-panel&utm_campaign=astra-sites&utm_medium=wp-dashboard' ),
222
+ '_ajax_nonce' => wp_create_nonce( 'astra-sites' ),
223
+ 'requiredPlugins' => array(),
224
+ 'XMLReaderDisabled' => ! class_exists( 'XMLReader' ) ? true : false,
225
+ 'strings' => array(
226
+ /* translators: %s are HTML tags. */
227
+ 'warningXMLReader' => sprintf( __( '%1$sRequired XMLReader PHP extension is missing on your server!%2$sAstra Sites import requires XMLReader extension to be installed. Please contact your web hosting provider and ask them to install and activate the XMLReader PHP extension.', 'astra-sites' ), '<div class="notice astra-sites-xml-notice notice-error"><p><b>', '</b></p><p>', '</p></div>' ),
228
+ 'warningBeforeCloseWindow' => __( 'Warning! Astra Site Import process is not complete. Don\'t close the window until import process complete. Do you still want to leave the window?', 'astra-sites' ),
229
+ 'importFailedBtnSmall' => __( 'Error!', 'astra-sites' ),
230
+ 'importFailedBtnLarge' => __( 'Error! Read Possibilities.', 'astra-sites' ),
231
+ 'importFailedURL' => esc_url( 'https://wpastra.com/docs/?p=1314&utm_source=demo-import-panel&utm_campaign=astra-sites&utm_medium=import-failed' ),
232
+ 'viewSite' => __( 'Done! View Site', 'astra-sites' ),
233
+ 'btnActivating' => __( 'Activating', 'astra-sites' ) . '&hellip;',
234
+ 'btnActive' => __( 'Active', 'astra-sites' ),
235
+ 'importFailBtn' => __( 'Import failed.', 'astra-sites' ),
236
+ 'importFailBtnLarge' => __( 'Import failed. See error log.', 'astra-sites' ),
237
+ 'importDemo' => __( 'Import This Site', 'astra-sites' ),
238
+ 'importingDemo' => __( 'Importing..', 'astra-sites' ),
239
+ 'DescExpand' => __( 'Read more', 'astra-sites' ) . '&hellip;',
240
+ 'DescCollapse' => __( 'Hide', 'astra-sites' ),
241
+ 'responseError' => __( 'There was a problem receiving a response from server.', 'astra-sites' ),
242
+ 'searchNoFound' => __( 'No Demos found, Try a different search.', 'astra-sites' ),
243
+ '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' ),
244
+ ),
245
+ 'log' => array(
246
+ 'installingPlugin' => __( 'Installing plugin ', 'astra-sites' ),
247
+ 'installed' => __( 'Successfully plugin installed!', 'astra-sites' ),
248
+ 'activating' => __( 'Activating plugin ', 'astra-sites' ),
249
+ 'activated' => __( 'Successfully plugin activated ', 'astra-sites' ),
250
+ 'bulkActivation' => __( 'Bulk plugin activation...', 'astra-sites' ),
251
+ 'activate' => __( 'Successfully plugin activate - ', 'astra-sites' ),
252
+ 'activationError' => __( 'Error! While activating plugin - ', 'astra-sites' ),
253
+ 'bulkInstall' => __( 'Bulk plugin installation...', 'astra-sites' ),
254
+ 'api' => __( 'Site API ', 'astra-sites' ),
255
+ 'importing' => __( 'Importing..', 'astra-sites' ),
256
+ 'processingRequest' => __( 'Processing requests...', 'astra-sites' ),
257
+ 'importCustomizer' => __( '1) Importing "Customizer Settings"...', 'astra-sites' ),
258
+ 'importCustomizerSuccess' => __( 'Successfully imported customizer settings!', 'astra-sites' ),
259
+ 'importWPForms' => __( '2) Importing "WPForms"...', 'astra-sites' ),
260
+ 'importWPFormsSuccess' => __( 'Successfully imported WPForms!', 'astra-sites' ),
261
+ 'importXMLPrepare' => __( '3) Preparing "XML" Data...', 'astra-sites' ),
262
+ 'importXMLPrepareSuccess' => __( 'Successfully set XML data!', 'astra-sites' ),
263
+ 'importXML' => __( '4) Importing "XML"...', 'astra-sites' ),
264
+ 'importXMLSuccess' => __( 'Successfully imported XML!', 'astra-sites' ),
265
+ 'importOptions' => __( '5) Importing "Options"...', 'astra-sites' ),
266
+ 'importOptionsSuccess' => __( 'Successfully imported Options!', 'astra-sites' ),
267
+ 'importWidgets' => __( '6) Importing "Widgets"...', 'astra-sites' ),
268
+ 'importWidgetsSuccess' => __( 'Successfully imported Widgets!', 'astra-sites' ),
269
+ 'serverConfiguration' => esc_url( 'https://wpastra.com/docs/?p=1314&utm_source=demo-import-panel&utm_campaign=import-error&utm_medium=wp-dashboard' ),
270
+ 'success' => __( 'Site imported successfully! visit : ', 'astra-sites' ),
271
+ 'gettingData' => __( 'Getting Site Information..', 'astra-sites' ),
272
+ 'importingCustomizer' => __( 'Importing Customizer Settings..', 'astra-sites' ),
273
+ 'importingWPForms' => __( 'Importing WP Forms..', 'astra-sites' ),
274
+ 'importXMLPreparing' => __( 'Setting up import data..', 'astra-sites' ),
275
+ 'importingXML' => __( 'Importing Pages, Posts & Media..', 'astra-sites' ),
276
+ 'importingOptions' => __( 'Importing Site Options..', 'astra-sites' ),
277
+ 'importingWidgets' => __( 'Importing Widgets..', 'astra-sites' ),
278
+ 'importComplete' => __( 'Import Complete..', 'astra-sites' ),
279
+ 'preview' => __( 'Previewing ', 'astra-sites' ),
280
+ 'importLogText' => __( 'See Error Log &rarr;', 'astra-sites' ),
281
+ ),
282
+ )
283
+ );
284
+
285
+ wp_localize_script( 'astra-sites-admin-page', 'astraSitesAdmin', $data );
286
+
287
+ }
288
+
289
+ /**
290
+ * Load all the required files in the importer.
291
+ *
292
+ * @since 1.0.0
293
+ */
294
+ private function includes() {
295
+
296
+ require_once ASTRA_SITES_DIR . 'inc/classes/class-astra-sites-notices.php';
297
+ require_once ASTRA_SITES_DIR . 'inc/classes/class-astra-sites-page.php';
298
+ require_once ASTRA_SITES_DIR . 'inc/classes/compatibility/class-astra-sites-compatibility.php';
299
+ require_once ASTRA_SITES_DIR . 'inc/classes/class-astra-sites-white-label.php';
300
+ require_once ASTRA_SITES_DIR . 'inc/classes/class-astra-sites-importer.php';
301
+
302
+ }
303
+
304
+ /**
305
+ * Required Plugin Activate
306
+ *
307
+ * @since 1.0.0
308
+ */
309
+ public function required_plugin_activate() {
310
+
311
+ if ( ! current_user_can( 'install_plugins' ) || ! isset( $_POST['init'] ) || ! $_POST['init'] ) {
312
+ wp_send_json_error(
313
+ array(
314
+ 'success' => false,
315
+ 'message' => __( 'No plugin specified', 'astra-sites' ),
316
+ )
317
+ );
318
+ }
319
+
320
+ $data = array();
321
+ $plugin_init = ( isset( $_POST['init'] ) ) ? esc_attr( $_POST['init'] ) : '';
322
+ $astra_site_options = ( isset( $_POST['options'] ) ) ? json_decode( stripslashes( $_POST['options'] ) ) : '';
323
+ $enabled_extensions = ( isset( $_POST['enabledExtensions'] ) ) ? json_decode( stripslashes( $_POST['enabledExtensions'] ) ) : '';
324
+
325
+ $data['astra_site_options'] = $astra_site_options;
326
+ $data['enabled_extensions'] = $enabled_extensions;
327
+
328
+ $activate = activate_plugin( $plugin_init, '', false, true );
329
+
330
+ if ( is_wp_error( $activate ) ) {
331
+ wp_send_json_error(
332
+ array(
333
+ 'success' => false,
334
+ 'message' => $activate->get_error_message(),
335
+ )
336
+ );
337
+ }
338
+
339
+ do_action( 'astra_sites_after_plugin_activation', $plugin_init, $data );
340
+
341
+ wp_send_json_success(
342
+ array(
343
+ 'success' => true,
344
+ 'message' => __( 'Plugin Successfully Activated', 'astra-sites' ),
345
+ )
346
+ );
347
+
348
+ }
349
+
350
+ /**
351
+ * Required Plugin
352
+ *
353
+ * @since 1.0.0
354
+ * @return void
355
+ */
356
+ public function required_plugin() {
357
+
358
+ // Verify Nonce.
359
+ check_ajax_referer( 'astra-sites', '_ajax_nonce' );
360
+
361
+ $response = array(
362
+ 'active' => array(),
363
+ 'inactive' => array(),
364
+ 'notinstalled' => array(),
365
+ );
366
+
367
+ if ( ! current_user_can( 'customize' ) ) {
368
+ wp_send_json_error( $response );
369
+ }
370
+
371
+ $required_plugins = ( isset( $_POST['required_plugins'] ) ) ? $_POST['required_plugins'] : array();
372
+
373
+ if ( count( $required_plugins ) > 0 ) {
374
+ foreach ( $required_plugins as $key => $plugin ) {
375
+
376
+ /**
377
+ * Has Pro Version Support?
378
+ * And
379
+ * Is Pro Version Installed?
380
+ */
381
+ $plugin_pro = self::pro_plugin_exist( $plugin['init'] );
382
+ if ( $plugin_pro ) {
383
+
384
+ // Pro - Active.
385
+ if ( is_plugin_active( $plugin_pro['init'] ) ) {
386
+ $response['active'][] = $plugin_pro;
387
+
388
+ // Pro - Inactive.
389
+ } else {
390
+ $response['inactive'][] = $plugin_pro;
391
+ }
392
+ } else {
393
+
394
+ // Lite - Installed but Inactive.
395
+ if ( file_exists( WP_PLUGIN_DIR . '/' . $plugin['init'] ) && is_plugin_inactive( $plugin['init'] ) ) {
396
+
397
+ $response['inactive'][] = $plugin;
398
+
399
+ // Lite - Not Installed.
400
+ } elseif ( ! file_exists( WP_PLUGIN_DIR . '/' . $plugin['init'] ) ) {
401
+
402
+ $response['notinstalled'][] = $plugin;
403
+
404
+ // Lite - Active.
405
+ } else {
406
+ $response['active'][] = $plugin;
407
+ }
408
+ }
409
+ }
410
+ }
411
+
412
+ // Send response.
413
+ wp_send_json_success( $response );
414
+ }
415
+
416
+ /**
417
+ * Has Pro Version Support?
418
+ * And
419
+ * Is Pro Version Installed?
420
+ *
421
+ * Check Pro plugin version exist of requested plugin lite version.
422
+ *
423
+ * Eg. If plugin 'BB Lite Version' required to import demo. Then we check the 'BB Agency Version' is exist?
424
+ * If yes then we only 'Activate' Agency Version. [We couldn't install agency version.]
425
+ * Else we 'Activate' or 'Install' Lite Version.
426
+ *
427
+ * @since 1.0.1
428
+ *
429
+ * @param string $lite_version Lite version init file.
430
+ * @return mixed Return false if not installed or not supported by us
431
+ * else return 'Pro' version details.
432
+ */
433
+ public static function pro_plugin_exist( $lite_version = '' ) {
434
+
435
+ // Lite init => Pro init.
436
+ $plugins = apply_filters(
437
+ 'astra_sites_pro_plugin_exist',
438
+ array(
439
+ 'beaver-builder-lite-version/fl-builder.php' => array(
440
+ 'slug' => 'bb-plugin',
441
+ 'init' => 'bb-plugin/fl-builder.php',
442
+ 'name' => 'Beaver Builder Plugin',
443
+ ),
444
+ 'ultimate-addons-for-beaver-builder-lite/bb-ultimate-addon.php' => array(
445
+ 'slug' => 'bb-ultimate-addon',
446
+ 'init' => 'bb-ultimate-addon/bb-ultimate-addon.php',
447
+ 'name' => 'Ultimate Addon for Beaver Builder',
448
+ ),
449
+ ),
450
+ $lite_version
451
+ );
452
+
453
+ if ( isset( $plugins[ $lite_version ] ) ) {
454
+
455
+ // Pro plugin directory exist?
456
+ if ( file_exists( WP_PLUGIN_DIR . '/' . $plugins[ $lite_version ]['init'] ) ) {
457
+ return $plugins[ $lite_version ];
458
+ }
459
+ }
460
+
461
+ return false;
462
+ }
463
+
464
+ }
465
+
466
+ /**
467
+ * Kicking this off by calling 'get_instance()' method
468
+ */
469
+ Astra_Sites::get_instance();
470
+
471
+ endif;
inc/classes/compatibility/class-astra-sites-compatibility.php CHANGED
@@ -1,67 +1,66 @@
1
- <?php
2
- /**
3
- * Astra Sites Compatibility for 3rd party plugins.
4
- *
5
- * @package Astra Sites
6
- * @since 1.0.11
7
- */
8
-
9
- if ( ! class_exists( 'Astra_Sites_Compatibility' ) ) :
10
-
11
- /**
12
- * Astra Sites Compatibility
13
- *
14
- * @since 1.0.11
15
- */
16
- class Astra_Sites_Compatibility {
17
-
18
- /**
19
- * Instance
20
- *
21
- * @access private
22
- * @var object Class object.
23
- * @since 1.0.11
24
- */
25
- private static $instance;
26
-
27
- /**
28
- * Initiator
29
- *
30
- * @since 1.0.11
31
- * @return object initialized object of class.
32
- */
33
- public static function 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.11
44
- */
45
- public function __construct() {
46
-
47
- // Plugin - Astra Pro.
48
- require_once ASTRA_SITES_DIR . 'inc/classes/compatibility/astra-pro/class-astra-sites-compatibility-astra-pro.php';
49
-
50
- // Plugin - Site Origin Widgets.
51
- require_once ASTRA_SITES_DIR . 'inc/classes/compatibility/so-widgets-bundle/class-astra-sites-compatibility-so-widgets.php';
52
-
53
- // Plugin - WooCommerce.
54
- require_once ASTRA_SITES_DIR . 'inc/classes/compatibility/woocommerce/class-astra-sites-compatibility-woocommerce.php';
55
-
56
- }
57
-
58
- }
59
-
60
- /**
61
- * Kicking this off by calling 'instance()' method
62
- */
63
- Astra_Sites_Compatibility::instance();
64
-
65
- endif;
66
-
67
-
1
+ <?php
2
+ /**
3
+ * Astra Sites Compatibility for 3rd party plugins.
4
+ *
5
+ * @package Astra Sites
6
+ * @since 1.0.11
7
+ */
8
+
9
+ if ( ! class_exists( 'Astra_Sites_Compatibility' ) ) :
10
+
11
+ /**
12
+ * Astra Sites Compatibility
13
+ *
14
+ * @since 1.0.11
15
+ */
16
+ class Astra_Sites_Compatibility {
17
+
18
+ /**
19
+ * Instance
20
+ *
21
+ * @access private
22
+ * @var object Class object.
23
+ * @since 1.0.11
24
+ */
25
+ private static $instance;
26
+
27
+ /**
28
+ * Initiator
29
+ *
30
+ * @since 1.0.11
31
+ * @return object initialized object of class.
32
+ */
33
+ public static function 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.11
44
+ */
45
+ public function __construct() {
46
+
47
+ // Plugin - Astra Pro.
48
+ require_once ASTRA_SITES_DIR . 'inc/classes/compatibility/astra-pro/class-astra-sites-compatibility-astra-pro.php';
49
+
50
+ // Plugin - Site Origin Widgets.
51
+ require_once ASTRA_SITES_DIR . 'inc/classes/compatibility/so-widgets-bundle/class-astra-sites-compatibility-so-widgets.php';
52
+
53
+ // Plugin - WooCommerce.
54
+ require_once ASTRA_SITES_DIR . 'inc/classes/compatibility/woocommerce/class-astra-sites-compatibility-woocommerce.php';
55
+ }
56
+
57
+ }
58
+
59
+ /**
60
+ * Kicking this off by calling 'instance()' method
61
+ */
62
+ Astra_Sites_Compatibility::instance();
63
+
64
+ endif;
65
+
66
+
 
inc/importers/batch-processing/class-astra-sites-batch-processing-beaver-builder.php CHANGED
@@ -1,236 +1,263 @@
1
- <?php
2
- /**
3
- * Batch Processing
4
- *
5
- * @package Astra Sites
6
- * @since 1.0.14
7
- */
8
-
9
- if ( ! class_exists( 'Astra_Sites_Batch_Processing_Beaver_Builder' ) ) :
10
-
11
- /**
12
- * Astra_Sites_Batch_Processing_Beaver_Builder
13
- *
14
- * @since 1.0.14
15
- */
16
- class Astra_Sites_Batch_Processing_Beaver_Builder {
17
-
18
- /**
19
- * Instance
20
- *
21
- * @since 1.0.14
22
- * @access private
23
- * @var object Class object.
24
- */
25
- private static $instance;
26
-
27
- /**
28
- * Initiator
29
- *
30
- * @since 1.0.14
31
- * @return object initialized object of class.
32
- */
33
- public static function get_instance() {
34
-
35
- if ( ! isset( self::$instance ) ) {
36
- self::$instance = new self;
37
- }
38
- return self::$instance;
39
- }
40
-
41
- /**
42
- * Constructor
43
- *
44
- * @since 1.0.14
45
- */
46
- public function __construct() {
47
- }
48
-
49
- /**
50
- * Import
51
- *
52
- * @since 1.0.14
53
- * @return void
54
- */
55
- public function import() {
56
-
57
- Astra_Sites_Image_Importer::log( '---- Processing WordPress Posts / Pages - for Beaver Builder ----' );
58
-
59
- $post_ids = Astra_Sites_Batch_Processing::get_pages();
60
- if ( is_array( $post_ids ) ) {
61
- foreach ( $post_ids as $post_id ) {
62
- $this->import_single_post( $post_id );
63
- }
64
- }
65
- }
66
-
67
- /**
68
- * Update post meta.
69
- *
70
- * @param integer $post_id Post ID.
71
- * @return void
72
- */
73
- public function import_single_post( $post_id = 0 ) {
74
-
75
- Astra_Sites_Image_Importer::log( 'Post ID: ' . $post_id );
76
-
77
- if ( ! empty( $post_id ) ) {
78
-
79
- // Get page builder data.
80
- $data = get_post_meta( $post_id, '_fl_builder_data', true );
81
-
82
- if ( ! empty( $data ) ) {
83
- foreach ( $data as $key => $el ) {
84
-
85
- // Import 'row' images.
86
- if ( 'row' === $el->type ) {
87
- $data[ $key ]->settings = self::import_row_images( $el->settings );
88
- }
89
-
90
- // Import 'module' images.
91
- if ( 'module' === $el->type ) {
92
- $data[ $key ]->settings = self::import_module_images( $el->settings );
93
- }
94
-
95
- // Import 'column' images.
96
- if ( 'column' === $el->type ) {
97
- $data[ $key ]->settings = self::import_column_images( $el->settings );
98
- }
99
- }
100
-
101
- // Update page builder data.
102
- update_post_meta( $post_id, '_fl_builder_data', $data );
103
- update_post_meta( $post_id, '_fl_builder_draft', $data );
104
-
105
- // Clear all cache.
106
- FLBuilderModel::delete_asset_cache_for_all_posts();
107
- }
108
- }
109
- }
110
-
111
- /**
112
- * Import Module Images.
113
- *
114
- * @param object $settings Module settings object.
115
- * @return object
116
- */
117
- public static function import_module_images( $settings ) {
118
-
119
- /**
120
- * 1) Set photos.
121
- */
122
- $settings = self::import_photo( $settings );
123
-
124
- /**
125
- * 2) Set `$settings->data` for Only type 'image-icon'
126
- *
127
- * @todo Remove the condition `'image-icon' === $settings->type` if `$settings->data` is used only for the Image Icon.
128
- */
129
- if (
130
- isset( $settings->data ) &&
131
- isset( $settings->photo ) && ! empty( $settings->photo ) &&
132
- 'image-icon' === $settings->type
133
- ) {
134
- $settings->data = FLBuilderPhoto::get_attachment_data( $settings->photo );
135
- }
136
-
137
- /**
138
- * 3) Set `list item` module images
139
- */
140
- if ( isset( $settings->add_list_item ) ) {
141
- foreach ( $settings->add_list_item as $key => $value ) {
142
- $settings->add_list_item[ $key ] = self::import_photo( $value );
143
- }
144
- }
145
-
146
- return $settings;
147
- }
148
-
149
- /**
150
- * Import Column Images.
151
- *
152
- * @param object $settings Column settings object.
153
- * @return object
154
- */
155
- public static function import_column_images( $settings ) {
156
-
157
- // 1) Set BG Images.
158
- $settings = self::import_bg_image( $settings );
159
-
160
- return $settings;
161
- }
162
-
163
- /**
164
- * Import Row Images.
165
- *
166
- * @param object $settings Row settings object.
167
- * @return object
168
- */
169
- public static function import_row_images( $settings ) {
170
-
171
- // 1) Set BG Images.
172
- $settings = self::import_bg_image( $settings );
173
-
174
- return $settings;
175
- }
176
-
177
- /**
178
- * Helper: Import BG Images.
179
- *
180
- * @param object $settings Row settings object.
181
- * @return object
182
- */
183
- public static function import_bg_image( $settings ) {
184
-
185
- if (
186
- ( ! empty( $settings->bg_image ) && ! empty( $settings->bg_image_src ) )
187
- ) {
188
- $image = array(
189
- 'url' => $settings->bg_image_src,
190
- 'id' => $settings->bg_image,
191
- );
192
-
193
- $downloaded_image = Astra_Sites_Image_Importer::get_instance()->import( $image );
194
-
195
- $settings->bg_image_src = $downloaded_image['url'];
196
- $settings->bg_image = $downloaded_image['id'];
197
- }
198
-
199
- return $settings;
200
- }
201
-
202
- /**
203
- * Helper: Import Photo.
204
- *
205
- * @param object $settings Row settings object.
206
- * @return object
207
- */
208
- public static function import_photo( $settings ) {
209
-
210
- if ( ! empty( $settings->photo ) && ! empty( $settings->photo_src ) ) {
211
-
212
- $image = array(
213
- 'url' => $settings->photo_src,
214
- 'id' => $settings->photo,
215
- );
216
-
217
- $downloaded_image = Astra_Sites_Image_Importer::get_instance()->import( $image );
218
-
219
- $settings->photo_src = $downloaded_image['url'];
220
- $settings->photo = $downloaded_image['id'];
221
- }
222
-
223
- return $settings;
224
- }
225
-
226
-
227
- }
228
-
229
- /**
230
- * Kicking this off by calling 'get_instance()' method
231
- */
232
- Astra_Sites_Batch_Processing_Beaver_Builder::get_instance();
233
-
234
- endif;
235
-
236
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Batch Processing
4
+ *
5
+ * @package Astra Sites
6
+ * @since 1.0.14
7
+ */
8
+
9
+ if ( ! class_exists( 'Astra_Sites_Batch_Processing_Beaver_Builder' ) ) :
10
+
11
+ /**
12
+ * Astra_Sites_Batch_Processing_Beaver_Builder
13
+ *
14
+ * @since 1.0.14
15
+ */
16
+ class Astra_Sites_Batch_Processing_Beaver_Builder {
17
+
18
+ /**
19
+ * Instance
20
+ *
21
+ * @since 1.0.14
22
+ * @access private
23
+ * @var object Class object.
24
+ */
25
+ private static $instance;
26
+
27
+ /**
28
+ * Initiator
29
+ *
30
+ * @since 1.0.14
31
+ * @return object initialized object of class.
32
+ */
33
+ public static function get_instance() {
34
+
35
+ if ( ! isset( self::$instance ) ) {
36
+ self::$instance = new self;
37
+ }
38
+ return self::$instance;
39
+ }
40
+
41
+ /**
42
+ * Constructor
43
+ *
44
+ * @since 1.0.14
45
+ */
46
+ public function __construct() {
47
+ }
48
+
49
+ /**
50
+ * Import
51
+ *
52
+ * @since 1.0.14
53
+ * @return void
54
+ */
55
+ public function import() {
56
+
57
+ Astra_Sites_Image_Importer::log( '---- Processing WordPress Posts / Pages - for Beaver Builder ----' );
58
+
59
+ if ( ! is_callable( 'FLBuilderModel::get_post_types' ) ) {
60
+ return;
61
+ }
62
+
63
+ $post_types = FLBuilderModel::get_post_types( 'post-types' );
64
+ if ( empty( $post_types ) && ! is_array( $post_types ) ) {
65
+ return;
66
+ }
67
+
68
+ $post_ids = Astra_Sites_Batch_Processing::get_pages( $post_types );
69
+ if ( empty( $post_ids ) && ! is_array( $post_ids ) ) {
70
+ return;
71
+ }
72
+
73
+ foreach ( $post_ids as $post_id ) {
74
+ $is_bb_post = get_post_meta( $post_id, '_fl_builder_enabled', true );
75
+ if ( $is_bb_post ) {
76
+ $this->import_single_post( $post_id );
77
+ }
78
+ }
79
+ }
80
+
81
+ /**
82
+ * Update post meta.
83
+ *
84
+ * @param integer $post_id Post ID.
85
+ * @return void
86
+ */
87
+ public function import_single_post( $post_id = 0 ) {
88
+
89
+ Astra_Sites_Image_Importer::log( 'Post ID: ' . $post_id );
90
+
91
+ if ( ! empty( $post_id ) ) {
92
+
93
+ // Get page builder data.
94
+ $data = get_post_meta( $post_id, '_fl_builder_data', true );
95
+
96
+ if ( ! empty( $data ) ) {
97
+ foreach ( $data as $key => $el ) {
98
+
99
+ // Update 'row' images.
100
+ if ( 'row' === $el->type ) {
101
+ $data[ $key ]->settings = self::update_row( $el->settings );
102
+ }
103
+
104
+ // Update 'module' images.
105
+ if ( 'module' === $el->type ) {
106
+ $data[ $key ]->settings = self::update_module( $el->settings );
107
+ }
108
+
109
+ // Update 'column' images.
110
+ if ( 'column' === $el->type ) {
111
+ $data[ $key ]->settings = self::update_column( $el->settings );
112
+ }
113
+ }
114
+
115
+ // Update page builder data.
116
+ update_post_meta( $post_id, '_fl_builder_data', $data );
117
+ update_post_meta( $post_id, '_fl_builder_draft', $data );
118
+
119
+ // Clear all cache.
120
+ FLBuilderModel::delete_asset_cache_for_all_posts();
121
+ }
122
+ }
123
+
124
+ }
125
+
126
+ /**
127
+ * Import Module Images.
128
+ *
129
+ * @param object $settings Module settings object.
130
+ * @return object
131
+ */
132
+ public static function update_module( $settings ) {
133
+
134
+ // 1) Set photos.
135
+ $settings = self::import_photo( $settings );
136
+
137
+ /**
138
+ * 2) Set `$settings->data` for Only type 'image-icon'
139
+ *
140
+ * @todo Remove the condition `'image-icon' === $settings->type` if `$settings->data` is used only for the Image Icon.
141
+ */
142
+ if (
143
+ isset( $settings->data ) &&
144
+ isset( $settings->photo ) && ! empty( $settings->photo ) &&
145
+ 'image-icon' === $settings->type
146
+ ) {
147
+ $settings->data = FLBuilderPhoto::get_attachment_data( $settings->photo );
148
+ }
149
+
150
+ // 3) Set `list item` module images.
151
+ if ( isset( $settings->add_list_item ) ) {
152
+ foreach ( $settings->add_list_item as $key => $value ) {
153
+ $settings->add_list_item[ $key ] = self::import_photo( $value );
154
+ }
155
+ }
156
+
157
+ // 4) Set `list item` module images.
158
+ if ( isset( $settings->text ) ) {
159
+ $ids_mapping = get_option( 'astra_sites_wpforms_ids_mapping', array() );
160
+ if ( $ids_mapping ) {
161
+
162
+ // Keep old data in temp.
163
+ $updated_data = $settings->text;
164
+
165
+ // Update WP form IDs.
166
+ foreach ( $ids_mapping as $old_id => $new_id ) {
167
+ $updated_data = str_replace( '[wpforms id="' . $old_id, '[wpforms id="' . $new_id, $updated_data );
168
+ }
169
+
170
+ // Update modified data.
171
+ $settings->text = $updated_data;
172
+ }
173
+ }
174
+
175
+ return $settings;
176
+ }
177
+
178
+ /**
179
+ * Import Column Images.
180
+ *
181
+ * @param object $settings Column settings object.
182
+ * @return object
183
+ */
184
+ public static function update_column( $settings ) {
185
+
186
+ // 1) Set BG Images.
187
+ $settings = self::import_bg_image( $settings );
188
+
189
+ return $settings;
190
+ }
191
+
192
+ /**
193
+ * Import Row Images.
194
+ *
195
+ * @param object $settings Row settings object.
196
+ * @return object
197
+ */
198
+ public static function update_row( $settings ) {
199
+
200
+ // 1) Set BG Images.
201
+ $settings = self::import_bg_image( $settings );
202
+
203
+ return $settings;
204
+ }
205
+
206
+ /**
207
+ * Helper: Import BG Images.
208
+ *
209
+ * @param object $settings Row settings object.
210
+ * @return object
211
+ */
212
+ public static function import_bg_image( $settings ) {
213
+
214
+ if (
215
+ ( ! empty( $settings->bg_image ) && ! empty( $settings->bg_image_src ) )
216
+ ) {
217
+ $image = array(
218
+ 'url' => $settings->bg_image_src,
219
+ 'id' => $settings->bg_image,
220
+ );
221
+
222
+ $downloaded_image = Astra_Sites_Image_Importer::get_instance()->import( $image );
223
+
224
+ $settings->bg_image_src = $downloaded_image['url'];
225
+ $settings->bg_image = $downloaded_image['id'];
226
+ }
227
+
228
+ return $settings;
229
+ }
230
+
231
+ /**
232
+ * Helper: Import Photo.
233
+ *
234
+ * @param object $settings Row settings object.
235
+ * @return object
236
+ */
237
+ public static function import_photo( $settings ) {
238
+
239
+ if ( ! empty( $settings->photo ) && ! empty( $settings->photo_src ) ) {
240
+
241
+ $image = array(
242
+ 'url' => $settings->photo_src,
243
+ 'id' => $settings->photo,
244
+ );
245
+
246
+ $downloaded_image = Astra_Sites_Image_Importer::get_instance()->import( $image );
247
+
248
+ $settings->photo_src = $downloaded_image['url'];
249
+ $settings->photo = $downloaded_image['id'];
250
+ }
251
+
252
+ return $settings;
253
+ }
254
+
255
+
256
+ }
257
+
258
+ /**
259
+ * Kicking this off by calling 'get_instance()' method
260
+ */
261
+ Astra_Sites_Batch_Processing_Beaver_Builder::get_instance();
262
+
263
+ endif;
inc/importers/batch-processing/class-astra-sites-batch-processing-brizy.php ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Batch Processing
4
+ *
5
+ * @package Astra Sites
6
+ * @since 1.2.14
7
+ */
8
+
9
+ if ( ! class_exists( 'Astra_Sites_Batch_Processing_Brizy' ) ) :
10
+
11
+ /**
12
+ * Astra Sites Batch Processing Brizy
13
+ *
14
+ * @since 1.2.14
15
+ */
16
+ class Astra_Sites_Batch_Processing_Brizy {
17
+
18
+ /**
19
+ * Instance
20
+ *
21
+ * @since 1.2.14
22
+ * @access private
23
+ * @var object Class object.
24
+ */
25
+ private static $instance;
26
+
27
+ /**
28
+ * Initiator
29
+ *
30
+ * @since 1.2.14
31
+ * @return object initialized object of class.
32
+ */
33
+ public static function get_instance() {
34
+
35
+ if ( ! isset( self::$instance ) ) {
36
+ self::$instance = new self;
37
+ }
38
+ return self::$instance;
39
+ }
40
+
41
+ /**
42
+ * Constructor
43
+ *
44
+ * @since 1.2.14
45
+ */
46
+ public function __construct() {}
47
+
48
+ /**
49
+ * Import
50
+ *
51
+ * @since 1.2.14
52
+ * @return void
53
+ */
54
+ public function import() {
55
+
56
+ Astra_Sites_Image_Importer::log( '---- Processing WordPress Posts / Pages - for "Brizy" ----' );
57
+
58
+ if ( ! is_callable( 'Brizy_Editor_Storage_Common::instance' ) ) {
59
+ return;
60
+ }
61
+
62
+ $post_types = Brizy_Editor_Storage_Common::instance()->get( 'post-types' );
63
+ if ( empty( $post_types ) && ! is_array( $post_types ) ) {
64
+ return;
65
+ }
66
+
67
+ $post_ids = Astra_Sites_Batch_Processing::get_pages( $post_types );
68
+ if ( empty( $post_ids ) && ! is_array( $post_ids ) ) {
69
+ return;
70
+ }
71
+
72
+ foreach ( $post_ids as $post_id ) {
73
+ $is_brizy_post = get_post_meta( $post_id, 'brizy_post_uid', true );
74
+ if ( $is_brizy_post ) {
75
+ $this->import_single_post( $post_id );
76
+ }
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Update post meta.
82
+ *
83
+ * @param integer $post_id Post ID.
84
+ * @return void
85
+ */
86
+ public function import_single_post( $post_id = 0 ) {
87
+
88
+ $ids_mapping = get_option( 'astra_sites_wpforms_ids_mapping', array() );
89
+
90
+ // Empty mapping? Then return.
91
+ if ( empty( $ids_mapping ) ) {
92
+ return;
93
+ }
94
+
95
+ $json_value = null;
96
+
97
+ $post = Brizy_Editor_Post::get( (int) $post_id );
98
+ $data = $post->storage()->get( Brizy_Editor_Post::BRIZY_POST, false );
99
+
100
+ // Decode current data.
101
+ $json_value = base64_decode( $data['editor_data'] );
102
+
103
+ // Update WPForm IDs.
104
+ foreach ( $ids_mapping as $old_id => $new_id ) {
105
+ $json_value = str_replace( '[wpforms id=\"' . $old_id, '[wpforms id=\"' . $new_id, $json_value );
106
+ }
107
+
108
+ // Encode modified data.
109
+ $data['editor_data'] = base64_encode( $json_value );
110
+
111
+ $post->set_editor_data( $json_value );
112
+
113
+ $post->storage()->set( Brizy_Editor_Post::BRIZY_POST, $data );
114
+
115
+ $post->compile_page();
116
+ $post->save();
117
+ }
118
+
119
+ }
120
+
121
+ /**
122
+ * Kicking this off by calling 'get_instance()' method
123
+ */
124
+ Astra_Sites_Batch_Processing_Brizy::get_instance();
125
+
126
+ endif;
inc/importers/batch-processing/class-astra-sites-batch-processing-elementor.php CHANGED
@@ -1,93 +1,113 @@
1
- <?php
2
- /**
3
- * Elementor Importer
4
- *
5
- * @package Astra Sites
6
- */
7
-
8
- namespace Elementor\TemplateLibrary;
9
-
10
- use Elementor\Core\Base\Document;
11
- use Elementor\DB;
12
- use Elementor\Core\Settings\Page\Manager as PageSettingsManager;
13
- use Elementor\Core\Settings\Manager as SettingsManager;
14
- use Elementor\Core\Settings\Page\Model;
15
- use Elementor\Editor;
16
- use Elementor\Plugin;
17
- use Elementor\Settings;
18
- use Elementor\Utils;
19
-
20
- if ( ! defined( 'ABSPATH' ) ) {
21
- exit; // Exit if accessed directly.
22
- }
23
-
24
- /**
25
- * Elementor template library local source.
26
- *
27
- * Elementor template library local source handler class is responsible for
28
- * handling local Elementor templates saved by the user locally on his site.
29
- *
30
- * @since 1.2.13 Added compatibility for Elemetnor v2.5.0
31
- * @since 1.0.0
32
- */
33
- class Astra_Sites_Batch_Processing_Elementor extends Source_Local {
34
-
35
- /**
36
- * Import
37
- *
38
- * @since 1.0.14
39
- * @return void
40
- */
41
- public function import() {
42
-
43
- \Astra_Sites_Image_Importer::log( '---- Processing WordPress Posts / Pages - for Elementor ----' );
44
-
45
- $post_ids = \Astra_Sites_Batch_Processing::get_pages();
46
- if ( is_array( $post_ids ) ) {
47
- foreach ( $post_ids as $post_id ) {
48
- $this->import_single_post( $post_id );
49
- }
50
- }
51
-
52
- }
53
-
54
- /**
55
- * Update post meta.
56
- *
57
- * @since 1.0.14
58
- * @param integer $post_id Post ID.
59
- * @return void
60
- */
61
- public function import_single_post( $post_id = 0 ) {
62
-
63
- \Astra_Sites_Image_Importer::log( 'Post ID: ' . $post_id );
64
-
65
- if ( ! empty( $post_id ) ) {
66
-
67
- $hotlink_imported = get_post_meta( $post_id, '_astra_sites_hotlink_imported', true );
68
-
69
- if ( empty( $hotlink_imported ) ) {
70
-
71
- $data = get_post_meta( $post_id, '_elementor_data', true );
72
-
73
- if ( ! empty( $data ) ) {
74
-
75
- $data = add_magic_quotes( $data );
76
- $data = json_decode( $data, true );
77
-
78
- // Import the data.
79
- $content = $this->process_export_import_content( $content, 'on_import' );
80
-
81
- // Update processed meta.
82
- update_metadata( 'post', $post_id, '_elementor_data', $data );
83
- update_metadata( 'post', $post_id, '_astra_sites_hotlink_imported', true );
84
-
85
- // !important, Clear the cache after images import.
86
- Plugin::$instance->posts_css_manager->clear_cache();
87
-
88
- }
89
- }
90
- }
91
-
92
- }
93
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Elementor Importer
4
+ *
5
+ * @package Astra Sites
6
+ */
7
+
8
+ namespace Elementor\TemplateLibrary;
9
+
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit; // Exit if accessed directly.
12
+ }
13
+
14
+ // If plugin - 'Elementor' not exist then return.
15
+ if ( ! class_exists( '\Elementor\Plugin' ) ) {
16
+ return;
17
+ }
18
+
19
+ use Elementor\Core\Base\Document;
20
+ use Elementor\DB;
21
+ use Elementor\Core\Settings\Page\Manager as PageSettingsManager;
22
+ use Elementor\Core\Settings\Manager as SettingsManager;
23
+ use Elementor\Core\Settings\Page\Model;
24
+ use Elementor\Editor;
25
+ use Elementor\Plugin;
26
+ use Elementor\Settings;
27
+ use Elementor\Utils;
28
+
29
+ /**
30
+ * Elementor template library local source.
31
+ *
32
+ * Elementor template library local source handler class is responsible for
33
+ * handling local Elementor templates saved by the user locally on his site.
34
+ *
35
+ * @since 1.2.13 Added compatibility for Elemetnor v2.5.0
36
+ * @since 1.0.0
37
+ */
38
+ class Astra_Sites_Batch_Processing_Elementor extends Source_Local {
39
+
40
+ /**
41
+ * Import
42
+ *
43
+ * @since 1.0.14
44
+ * @return void
45
+ */
46
+ public function import() {
47
+
48
+ \Astra_Sites_Image_Importer::log( '---- Processing WordPress Posts / Pages - for Elementor ----' );
49
+
50
+ $post_types = get_option( 'elementor_cpt_support', array( 'page', 'post' ) );
51
+ if ( empty( $post_types ) && ! is_array( $post_types ) ) {
52
+ return;
53
+ }
54
+
55
+ $post_ids = \Astra_Sites_Batch_Processing::get_pages( $post_types );
56
+ if ( empty( $post_ids ) && ! is_array( $post_ids ) ) {
57
+ return;
58
+ }
59
+
60
+ foreach ( $post_ids as $post_id ) {
61
+ $is_elementor_post = get_post_meta( $post_id, '_elementor_version', true );
62
+ if ( $is_elementor_post ) {
63
+ $this->import_single_post( $post_id );
64
+ }
65
+ }
66
+ }
67
+ /**
68
+ * Update post meta.
69
+ *
70
+ * @since 1.0.14
71
+ * @param integer $post_id Post ID.
72
+ * @return void
73
+ */
74
+ public function import_single_post( $post_id = 0 ) {
75
+
76
+ \Astra_Sites_Image_Importer::log( 'Post ID: ' . $post_id );
77
+
78
+ if ( ! empty( $post_id ) ) {
79
+
80
+ $hotlink_imported = get_post_meta( $post_id, '_astra_sites_hotlink_imported', true );
81
+
82
+ if ( empty( $hotlink_imported ) ) {
83
+
84
+ $data = get_post_meta( $post_id, '_elementor_data', true );
85
+
86
+ if ( ! empty( $data ) ) {
87
+
88
+ // Update WP form IDs.
89
+ $ids_mapping = get_option( 'astra_sites_wpforms_ids_mapping', array() );
90
+ if ( $ids_mapping ) {
91
+ foreach ( $ids_mapping as $old_id => $new_id ) {
92
+ $data = str_replace( '[wpforms id=\"' . $old_id, '[wpforms id=\"' . $new_id, $data );
93
+ }
94
+ }
95
+
96
+ $data = add_magic_quotes( $data );
97
+ $data = json_decode( $data, true );
98
+
99
+ // Import the data.
100
+ $content = $this->process_export_import_content( $content, 'on_import' );
101
+
102
+ // Update processed meta.
103
+ update_metadata( 'post', $post_id, '_elementor_data', $data );
104
+ update_metadata( 'post', $post_id, '_astra_sites_hotlink_imported', true );
105
+
106
+ // !important, Clear the cache after images import.
107
+ Plugin::$instance->posts_css_manager->clear_cache();
108
+
109
+ }
110
+ }
111
+ }
112
+ }
113
+ }
inc/importers/batch-processing/class-astra-sites-batch-processing-gutenberg.php ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Batch Processing
4
+ *
5
+ * @package Astra Sites
6
+ * @since 1.2.14
7
+ */
8
+
9
+ if ( ! class_exists( 'Astra_Sites_Batch_Processing_Gutenberg' ) ) :
10
+
11
+ /**
12
+ * Astra Sites Batch Processing Brizy
13
+ *
14
+ * @since 1.2.14
15
+ */
16
+ class Astra_Sites_Batch_Processing_Gutenberg {
17
+
18
+ /**
19
+ * Instance
20
+ *
21
+ * @since 1.2.14
22
+ * @access private
23
+ * @var object Class object.
24
+ */
25
+ private static $instance;
26
+
27
+ /**
28
+ * Initiator
29
+ *
30
+ * @since 1.2.14
31
+ * @return object initialized object of class.
32
+ */
33
+ public static function get_instance() {
34
+
35
+ if ( ! isset( self::$instance ) ) {
36
+ self::$instance = new self;
37
+ }
38
+ return self::$instance;
39
+ }
40
+
41
+ /**
42
+ * Constructor
43
+ *
44
+ * @since 1.2.14
45
+ */
46
+ public function __construct() {}
47
+
48
+ /**
49
+ * Allowed tags for the batch update process.
50
+ *
51
+ * @param array $allowedposttags Array of default allowable HTML tags.
52
+ * @param string|array $context The context for which to retrieve tags. Allowed values are 'post',
53
+ * 'strip', 'data', 'entities', or the name of a field filter such as
54
+ * 'pre_user_description'.
55
+ * @return array Array of allowed HTML tags and their allowed attributes.
56
+ */
57
+ function allowed_tags_and_attributes( $allowedposttags, $context ) {
58
+
59
+ // Keep only for 'post' contenxt.
60
+ if ( 'post' === $context ) {
61
+
62
+ // <svg> tag and attributes.
63
+ $allowedposttags['svg'] = array(
64
+ 'xmlns' => true,
65
+ 'viewbox' => true,
66
+ );
67
+
68
+ // <path> tag and attributes.
69
+ $allowedposttags['path'] = array(
70
+ 'd' => true,
71
+ );
72
+ }
73
+
74
+ return $allowedposttags;
75
+ }
76
+
77
+ /**
78
+ * Import
79
+ *
80
+ * @since 1.2.14
81
+ * @return void
82
+ */
83
+ public function import() {
84
+
85
+ // Allow the SVG tags in batch update process.
86
+ add_filter( 'wp_kses_allowed_html', array( $this, 'allowed_tags_and_attributes' ), 10, 2 );
87
+
88
+ Astra_Sites_Image_Importer::log( '---- Processing WordPress Posts / Pages - for "Gutenberg" ----' );
89
+
90
+ $post_ids = Astra_Sites_Batch_Processing::get_pages( array( 'page' ) );
91
+ if ( empty( $post_ids ) && ! is_array( $post_ids ) ) {
92
+ return;
93
+ }
94
+
95
+ foreach ( $post_ids as $post_id ) {
96
+ $this->import_single_post( $post_id );
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Update post meta.
102
+ *
103
+ * @param integer $post_id Post ID.
104
+ * @return void
105
+ */
106
+ public function import_single_post( $post_id = 0 ) {
107
+
108
+ $ids_mapping = get_option( 'astra_sites_wpforms_ids_mapping', array() );
109
+
110
+ // Empty mapping? Then return.
111
+ if ( empty( $ids_mapping ) ) {
112
+ return;
113
+ }
114
+
115
+ // Post content.
116
+ $content = get_post_field( 'post_content', $post_id );
117
+
118
+ // Replace ID's.
119
+ foreach ( $ids_mapping as $old_id => $new_id ) {
120
+ $content = str_replace( '[wpforms id="' . $old_id, '[wpforms id="' . $new_id, $content );
121
+ }
122
+
123
+ // # Tweak
124
+ // Gutenberg break block markup from render. Because the '&' is updated in database with '&amp;' and it
125
+ // expects as 'u0026amp;'. So, Converted '&amp;' with 'u0026amp;'.
126
+ //
127
+ // @todo This affect for normal page content too. Detect only Gutenberg pages and process only on it.
128
+ $content = str_replace( '&amp;', 'u0026amp;', $content );
129
+
130
+ // Update content.
131
+ wp_update_post(
132
+ array(
133
+ 'ID' => $post_id,
134
+ 'post_content' => $content,
135
+ )
136
+ );
137
+ }
138
+
139
+ }
140
+
141
+ /**
142
+ * Kicking this off by calling 'get_instance()' method
143
+ */
144
+ Astra_Sites_Batch_Processing_Gutenberg::get_instance();
145
+
146
+ endif;
inc/importers/batch-processing/class-astra-sites-batch-processing-misc.php CHANGED
@@ -1,140 +1,139 @@
1
- <?php
2
- /**
3
- * Misc batch import tasks.
4
- *
5
- * @package Astra Sites
6
- * @since 1.1.6
7
- */
8
-
9
- if ( ! class_exists( 'Astra_Sites_Batch_Processing_Misc' ) ) :
10
-
11
- /**
12
- * Astra_Sites_Batch_Processing_Misc
13
- *
14
- * @since 1.1.6
15
- */
16
- class Astra_Sites_Batch_Processing_Misc {
17
-
18
- /**
19
- * Instance
20
- *
21
- * @since 1.1.6
22
- * @access private
23
- * @var object Class object.
24
- */
25
- private static $instance;
26
-
27
- /**
28
- * Initiator
29
- *
30
- * @since 1.1.6
31
- * @return object initialized object of class.
32
- */
33
- public static function get_instance() {
34
-
35
- if ( ! isset( self::$instance ) ) {
36
- self::$instance = new self;
37
- }
38
- return self::$instance;
39
- }
40
-
41
- /**
42
- * Constructor
43
- *
44
- * @since 1.1.6
45
- */
46
- public function __construct() {
47
- }
48
-
49
- /**
50
- * Import
51
- *
52
- * @since 1.1.6
53
- * @return void
54
- */
55
- public function import() {
56
-
57
- Astra_Sites_Image_Importer::log( '---- Processing MISC ----' );
58
-
59
- self::fix_nav_menus();
60
- }
61
-
62
- /**
63
- * Import Module Images.
64
- *
65
- * @return object
66
- */
67
- public static function fix_nav_menus() {
68
- // Not found site data, then return.
69
- $demo_data = get_option( 'astra_sites_import_data', array() );
70
- if ( ! isset( $demo_data['astra-post-data-mapping'] ) ) {
71
- return;
72
- }
73
-
74
- // Not found/empty XML URL, then return.
75
- $xml_url = ( isset( $demo_data['astra-site-wxr-path'] ) ) ? esc_url( $demo_data['astra-site-wxr-path'] ) : '';
76
- if ( empty( $xml_url ) ) {
77
- return;
78
- }
79
-
80
- // Not empty site URL, then return.
81
- $site_url = strpos( $xml_url, '/wp-content' );
82
- if ( false === $site_url ) {
83
- return;
84
- }
85
-
86
- // Get remote site URL.
87
- $site_url = substr( $xml_url, 0, $site_url );
88
-
89
- $post_ids = self::get_menu_post_ids();
90
- if ( is_array( $post_ids ) ) {
91
- foreach ( $post_ids as $post_id ) {
92
- Astra_Sites_Image_Importer::log( 'Post ID: ' . $post_id );
93
-
94
- $menu_url = get_post_meta( $post_id, '_menu_item_url', true );
95
-
96
- if ( $menu_url ) {
97
- $menu_url = str_replace( $site_url, site_url(), $menu_url );
98
- update_post_meta( $post_id, '_menu_item_url', $menu_url );
99
- }
100
- }
101
- }
102
- }
103
-
104
- /**
105
- * Get all post id's
106
- *
107
- * @since 1.1.6
108
- *
109
- * @return array
110
- */
111
- public static function get_menu_post_ids() {
112
-
113
- $args = array(
114
- 'post_type' => 'nav_menu_item',
115
-
116
- // Query performance optimization.
117
- 'fields' => 'ids',
118
- 'no_found_rows' => true,
119
- 'post_status' => 'any',
120
- );
121
-
122
- $query = new WP_Query( $args );
123
-
124
- // Have posts?
125
- if ( $query->have_posts() ) :
126
-
127
- return $query->posts;
128
-
129
- endif;
130
- return null;
131
- }
132
-
133
- }
134
-
135
- /**
136
- * Kicking this off by calling 'get_instance()' method
137
- */
138
- Astra_Sites_Batch_Processing_Misc::get_instance();
139
-
140
- endif;
1
+ <?php
2
+ /**
3
+ * Misc batch import tasks.
4
+ *
5
+ * @package Astra Sites
6
+ * @since 1.1.6
7
+ */
8
+
9
+ if ( ! class_exists( 'Astra_Sites_Batch_Processing_Misc' ) ) :
10
+
11
+ /**
12
+ * Astra_Sites_Batch_Processing_Misc
13
+ *
14
+ * @since 1.1.6
15
+ */
16
+ class Astra_Sites_Batch_Processing_Misc {
17
+
18
+ /**
19
+ * Instance
20
+ *
21
+ * @since 1.1.6
22
+ * @access private
23
+ * @var object Class object.
24
+ */
25
+ private static $instance;
26
+
27
+ /**
28
+ * Initiator
29
+ *
30
+ * @since 1.1.6
31
+ * @return object initialized object of class.
32
+ */
33
+ public static function get_instance() {
34
+
35
+ if ( ! isset( self::$instance ) ) {
36
+ self::$instance = new self;
37
+ }
38
+ return self::$instance;
39
+ }
40
+
41
+ /**
42
+ * Constructor
43
+ *
44
+ * @since 1.1.6
45
+ */
46
+ public function __construct() {}
47
+
48
+ /**
49
+ * Import
50
+ *
51
+ * @since 1.1.6
52
+ * @return void
53
+ */
54
+ public function import() {
55
+
56
+ Astra_Sites_Image_Importer::log( '---- Processing MISC ----' );
57
+
58
+ self::fix_nav_menus();
59
+ }
60
+
61
+ /**
62
+ * Import Module Images.
63
+ *
64
+ * @return object
65
+ */
66
+ public static function fix_nav_menus() {
67
+ // Not found site data, then return.
68
+ $demo_data = get_option( 'astra_sites_import_data', array() );
69
+ if ( ! isset( $demo_data['astra-post-data-mapping'] ) ) {
70
+ return;
71
+ }
72
+
73
+ // Not found/empty XML URL, then return.
74
+ $xml_url = ( isset( $demo_data['astra-site-wxr-path'] ) ) ? esc_url( $demo_data['astra-site-wxr-path'] ) : '';
75
+ if ( empty( $xml_url ) ) {
76
+ return;
77
+ }
78
+
79
+ // Not empty site URL, then return.
80
+ $site_url = strpos( $xml_url, '/wp-content' );
81
+ if ( false === $site_url ) {
82
+ return;
83
+ }
84
+
85
+ // Get remote site URL.
86
+ $site_url = substr( $xml_url, 0, $site_url );
87
+
88
+ $post_ids = self::get_menu_post_ids();
89
+ if ( is_array( $post_ids ) ) {
90
+ foreach ( $post_ids as $post_id ) {
91
+ Astra_Sites_Image_Importer::log( 'Post ID: ' . $post_id );
92
+
93
+ $menu_url = get_post_meta( $post_id, '_menu_item_url', true );
94
+
95
+ if ( $menu_url ) {
96
+ $menu_url = str_replace( $site_url, site_url(), $menu_url );
97
+ update_post_meta( $post_id, '_menu_item_url', $menu_url );
98
+ }
99
+ }
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Get all post id's
105
+ *
106
+ * @since 1.1.6
107
+ *
108
+ * @return array
109
+ */
110
+ public static function get_menu_post_ids() {
111
+
112
+ $args = array(
113
+ 'post_type' => 'nav_menu_item',
114
+
115
+ // Query performance optimization.
116
+ 'fields' => 'ids',
117
+ 'no_found_rows' => true,
118
+ 'post_status' => 'any',
119
+ );
120
+
121
+ $query = new WP_Query( $args );
122
+
123
+ // Have posts?
124
+ if ( $query->have_posts() ) :
125
+
126
+ return $query->posts;
127
+
128
+ endif;
129
+ return null;
130
+ }
131
+
132
+ }
133
+
134
+ /**
135
+ * Kicking this off by calling 'get_instance()' method
136
+ */
137
+ Astra_Sites_Batch_Processing_Misc::get_instance();
138
+
139
+ endif;
 
inc/importers/batch-processing/class-astra-sites-batch-processing.php CHANGED
@@ -1,204 +1,209 @@
1
- <?php
2
- /**
3
- * Batch Processing
4
- *
5
- * @package Astra Sites
6
- * @since 1.0.14
7
- */
8
-
9
- if ( ! class_exists( 'Astra_Sites_Batch_Processing' ) ) :
10
-
11
- /**
12
- * Astra_Sites_Batch_Processing
13
- *
14
- * @since 1.0.14
15
- */
16
- class Astra_Sites_Batch_Processing {
17
-
18
- /**
19
- * Instance
20
- *
21
- * @since 1.0.14
22
- * @var object Class object.
23
- * @access private
24
- */
25
- private static $instance;
26
-
27
- /**
28
- * Process All
29
- *
30
- * @since 1.0.14
31
- * @var object Class object.
32
- * @access public
33
- */
34
- public static $process_all;
35
-
36
- /**
37
- * Initiator
38
- *
39
- * @since 1.0.14
40
- * @return object initialized object of class.
41
- */
42
- public static function get_instance() {
43
- if ( ! isset( self::$instance ) ) {
44
- self::$instance = new self;
45
- }
46
- return self::$instance;
47
- }
48
-
49
- /**
50
- * Constructor
51
- *
52
- * @since 1.0.14
53
- */
54
- public function __construct() {
55
-
56
- // Core Helpers - Image.
57
- // @todo This file is required for Elementor.
58
- // Once we implement our logic for updating elementor data then we'll delete this file.
59
- require_once ABSPATH . 'wp-admin/includes/image.php';
60
-
61
- // Core Helpers - Image Downloader.
62
- require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/helpers/class-astra-sites-image-importer.php';
63
-
64
- // Core Helpers - Batch Processing.
65
- require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/helpers/class-wp-async-request.php';
66
- require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/helpers/class-wp-background-process.php';
67
- require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/helpers/class-wp-background-process-astra.php';
68
-
69
- // Prepare Widgets.
70
- require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/class-astra-sites-batch-processing-widgets.php';
71
-
72
- // Prepare Page Builders.
73
- require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/class-astra-sites-batch-processing-beaver-builder.php';
74
-
75
- // Elementor.
76
- if ( class_exists( '\Elementor\Plugin' ) ) {
77
- require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/class-astra-sites-batch-processing-elementor.php';
78
- }
79
-
80
- // Prepare Misc.
81
- require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/class-astra-sites-batch-processing-misc.php';
82
-
83
- self::$process_all = new WP_Background_Process_Astra();
84
-
85
- // Start image importing after site import complete.
86
- add_filter( 'astra_sites_image_importer_skip_image', array( $this, 'skip_image' ), 10, 2 );
87
- add_action( 'astra_sites_import_complete', array( $this, 'start_process' ) );
88
- }
89
-
90
- /**
91
- * Skip Image from Batch Processing.
92
- *
93
- * @since 1.0.14
94
- *
95
- * @param boolean $can_process Batch process image status.
96
- * @param array $attachment Batch process image input.
97
- * @return boolean
98
- */
99
- function skip_image( $can_process, $attachment ) {
100
-
101
- if ( isset( $attachment['url'] ) && ! empty( $attachment['url'] ) ) {
102
- if (
103
- strpos( $attachment['url'], 'brainstormforce.com' ) !== false ||
104
- strpos( $attachment['url'], 'wpastra.com' ) !== false ||
105
- strpos( $attachment['url'], 'sharkz.in' ) !== false ||
106
- strpos( $attachment['url'], 'websitedemos.net' ) !== false
107
- ) {
108
- return false;
109
- }
110
- }
111
-
112
- return true;
113
- }
114
-
115
- /**
116
- * Start Image Import
117
- *
118
- * @since 1.0.14
119
- *
120
- * @return void
121
- */
122
- public function start_process() {
123
-
124
- Astra_Sites_Image_Importer::log( '=================== ' . Astra_Sites_White_Label::get_instance()->page_title( ASTRA_SITES_NAME ) . ' - Importing Images for Blog name \'' . get_bloginfo( 'name' ) . '\' (' . get_current_blog_id() . ') ===================' );
125
-
126
- // Add "widget" in import [queue].
127
- if ( class_exists( 'Astra_Sites_Batch_Processing_Widgets' ) ) {
128
- self::$process_all->push_to_queue( Astra_Sites_Batch_Processing_Widgets::get_instance() );
129
- }
130
-
131
- // Add "bb-plugin" in import [queue].
132
- // Add "beaver-builder-lite-version" in import [queue].
133
- if ( is_plugin_active( 'beaver-builder-lite-version/fl-builder.php' ) || is_plugin_active( 'bb-plugin/fl-builder.php' ) ) {
134
- if ( class_exists( 'Astra_Sites_Batch_Processing_Beaver_Builder' ) ) {
135
- self::$process_all->push_to_queue( Astra_Sites_Batch_Processing_Beaver_Builder::get_instance() );
136
- }
137
- }
138
-
139
- // Add "elementor" in import [queue].
140
- // @todo Remove required `allow_url_fopen` support.
141
- if ( ini_get( 'allow_url_fopen' ) ) {
142
- if ( is_plugin_active( 'elementor/elementor.php' ) ) {
143
- if ( class_exists( '\Elementor\TemplateLibrary\Astra_Sites_Batch_Processing_Elementor' ) ) {
144
- $import = new \Elementor\TemplateLibrary\Astra_Sites_Batch_Processing_Elementor();
145
- self::$process_all->push_to_queue( $import );
146
- }
147
- }
148
- } else {
149
- Astra_Sites_Image_Importer::log( 'Couldn\'t not import image due to allow_url_fopen() is disabled!' );
150
- }
151
-
152
- // Add "astra-addon" in import [queue].
153
- if ( is_plugin_active( 'astra-addon/astra-addon.php' ) ) {
154
- if ( class_exists( 'Astra_Sites_Compatibility_Astra_Pro' ) ) {
155
- self::$process_all->push_to_queue( Astra_Sites_Compatibility_Astra_Pro::get_instance() );
156
- }
157
- }
158
-
159
- // Add "misc" in import [queue].
160
- if ( class_exists( 'Astra_Sites_Batch_Processing_Misc' ) ) {
161
- self::$process_all->push_to_queue( Astra_Sites_Batch_Processing_Misc::get_instance() );
162
- }
163
-
164
- // Dispatch Queue.
165
- self::$process_all->save()->dispatch();
166
- }
167
-
168
- /**
169
- * Get all post id's
170
- *
171
- * @since 1.0.14
172
- *
173
- * @return array
174
- */
175
- public static function get_pages() {
176
-
177
- $args = array(
178
- 'post_type' => 'any',
179
-
180
- // Query performance optimization.
181
- 'fields' => 'ids',
182
- 'no_found_rows' => true,
183
- 'post_status' => 'publish',
184
- );
185
-
186
- $query = new WP_Query( $args );
187
-
188
- // Have posts?
189
- if ( $query->have_posts() ) :
190
-
191
- return $query->posts;
192
-
193
- endif;
194
- return null;
195
- }
196
-
197
- }
198
-
199
- /**
200
- * Kicking this off by calling 'get_instance()' method
201
- */
202
- Astra_Sites_Batch_Processing::get_instance();
203
-
204
- endif;
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Batch Processing
4
+ *
5
+ * @package Astra Sites
6
+ * @since 1.0.14
7
+ */
8
+
9
+ if ( ! class_exists( 'Astra_Sites_Batch_Processing' ) ) :
10
+
11
+ /**
12
+ * Astra_Sites_Batch_Processing
13
+ *
14
+ * @since 1.0.14
15
+ */
16
+ class Astra_Sites_Batch_Processing {
17
+
18
+ /**
19
+ * Instance
20
+ *
21
+ * @since 1.0.14
22
+ * @var object Class object.
23
+ * @access private
24
+ */
25
+ private static $instance;
26
+
27
+ /**
28
+ * Process All
29
+ *
30
+ * @since 1.0.14
31
+ * @var object Class object.
32
+ * @access public
33
+ */
34
+ public static $process_all;
35
+
36
+ /**
37
+ * Initiator
38
+ *
39
+ * @since 1.0.14
40
+ * @return object initialized object of class.
41
+ */
42
+ public static function get_instance() {
43
+ if ( ! isset( self::$instance ) ) {
44
+ self::$instance = new self;
45
+ }
46
+ return self::$instance;
47
+ }
48
+
49
+ /**
50
+ * Constructor
51
+ *
52
+ * @since 1.0.14
53
+ */
54
+ public function __construct() {
55
+
56
+ // Core Helpers - Image.
57
+ // @todo This file is required for Elementor.
58
+ // Once we implement our logic for updating elementor data then we'll delete this file.
59
+ require_once ABSPATH . 'wp-admin/includes/image.php';
60
+
61
+ // Core Helpers - Image Downloader.
62
+ require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/helpers/class-astra-sites-image-importer.php';
63
+
64
+ // Core Helpers - Batch Processing.
65
+ require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/helpers/class-wp-async-request.php';
66
+ require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/helpers/class-wp-background-process.php';
67
+ require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/helpers/class-wp-background-process-astra.php';
68
+
69
+ // Prepare Widgets.
70
+ require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/class-astra-sites-batch-processing-widgets.php';
71
+
72
+ // Prepare Page Builders.
73
+ require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/class-astra-sites-batch-processing-beaver-builder.php';
74
+ require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/class-astra-sites-batch-processing-elementor.php';
75
+ require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/class-astra-sites-batch-processing-gutenberg.php';
76
+ require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/class-astra-sites-batch-processing-brizy.php';
77
+
78
+ // Prepare Misc.
79
+ require_once ASTRA_SITES_DIR . 'inc/importers/batch-processing/class-astra-sites-batch-processing-misc.php';
80
+
81
+ self::$process_all = new WP_Background_Process_Astra();
82
+
83
+ // Start image importing after site import complete.
84
+ add_filter( 'astra_sites_image_importer_skip_image', array( $this, 'skip_image' ), 10, 2 );
85
+ add_action( 'astra_sites_import_complete', array( $this, 'start_process' ) );
86
+ }
87
+
88
+ /**
89
+ * Skip Image from Batch Processing.
90
+ *
91
+ * @since 1.0.14
92
+ *
93
+ * @param boolean $can_process Batch process image status.
94
+ * @param array $attachment Batch process image input.
95
+ * @return boolean
96
+ */
97
+ function skip_image( $can_process, $attachment ) {
98
+
99
+ if ( isset( $attachment['url'] ) && ! empty( $attachment['url'] ) ) {
100
+ if (
101
+ strpos( $attachment['url'], 'brainstormforce.com' ) !== false ||
102
+ strpos( $attachment['url'], 'wpastra.com' ) !== false ||
103
+ strpos( $attachment['url'], 'sharkz.in' ) !== false ||
104
+ strpos( $attachment['url'], 'websitedemos.net' ) !== false
105
+ ) {
106
+ return false;
107
+ }
108
+ }
109
+
110
+ return true;
111
+ }
112
+
113
+ /**
114
+ * Start Image Import
115
+ *
116
+ * @since 1.0.14
117
+ *
118
+ * @return void
119
+ */
120
+ public function start_process() {
121
+
122
+ Astra_Sites_Image_Importer::log( '=================== ' . Astra_Sites_White_Label::get_instance()->page_title( ASTRA_SITES_NAME ) . ' - Importing Images for Blog name \'' . get_bloginfo( 'name' ) . '\' (' . get_current_blog_id() . ') ===================' );
123
+
124
+ // Add "widget" in import [queue].
125
+ if ( class_exists( 'Astra_Sites_Batch_Processing_Widgets' ) ) {
126
+ self::$process_all->push_to_queue( Astra_Sites_Batch_Processing_Widgets::get_instance() );
127
+ }
128
+
129
+ // Add "gutenberg" in import [queue].
130
+ self::$process_all->push_to_queue( Astra_Sites_Batch_Processing_Gutenberg::get_instance() );
131
+
132
+ // Add "brizy" in import [queue].
133
+ if ( is_plugin_active( 'brizy/brizy.php' ) ) {
134
+ self::$process_all->push_to_queue( Astra_Sites_Batch_Processing_Brizy::get_instance() );
135
+ }
136
+
137
+ // Add "bb-plugin" in import [queue].
138
+ // Add "beaver-builder-lite-version" in import [queue].
139
+ if ( is_plugin_active( 'beaver-builder-lite-version/fl-builder.php' ) || is_plugin_active( 'bb-plugin/fl-builder.php' ) ) {
140
+ self::$process_all->push_to_queue( Astra_Sites_Batch_Processing_Beaver_Builder::get_instance() );
141
+ }
142
+
143
+ // Add "elementor" in import [queue].
144
+ // @todo Remove required `allow_url_fopen` support.
145
+ if ( ini_get( 'allow_url_fopen' ) ) {
146
+ if ( is_plugin_active( 'elementor/elementor.php' ) ) {
147
+ $import = new \Elementor\TemplateLibrary\Astra_Sites_Batch_Processing_Elementor();
148
+ self::$process_all->push_to_queue( $import );
149
+ }
150
+ } else {
151
+ Astra_Sites_Image_Importer::log( 'Couldn\'t not import image due to allow_url_fopen() is disabled!' );
152
+ }
153
+
154
+ // Add "astra-addon" in import [queue].
155
+ if ( is_plugin_active( 'astra-addon/astra-addon.php' ) ) {
156
+ if ( class_exists( 'Astra_Sites_Compatibility_Astra_Pro' ) ) {
157
+ self::$process_all->push_to_queue( Astra_Sites_Compatibility_Astra_Pro::get_instance() );
158
+ }
159
+ }
160
+
161
+ // Add "misc" in import [queue].
162
+ self::$process_all->push_to_queue( Astra_Sites_Batch_Processing_Misc::get_instance() );
163
+
164
+ // Dispatch Queue.
165
+ self::$process_all->save()->dispatch();
166
+ }
167
+
168
+ /**
169
+ * Get all post id's
170
+ *
171
+ * @since 1.0.14
172
+ *
173
+ * @param array $post_types Post types.
174
+ * @return array
175
+ */
176
+ public static function get_pages( $post_types = array() ) {
177
+
178
+ if ( $post_types ) {
179
+ $args = array(
180
+ 'post_type' => $post_types,
181
+
182
+ // Query performance optimization.
183
+ 'fields' => 'ids',
184
+ 'no_found_rows' => true,
185
+ 'post_status' => 'publish',
186
+ 'posts_per_page' => -1,
187
+ );
188
+
189
+ $query = new WP_Query( $args );
190
+
191
+ // Have posts?
192
+ if ( $query->have_posts() ) :
193
+
194
+ return $query->posts;
195
+
196
+ endif;
197
+ }
198
+
199
+ return null;
200
+ }
201
+
202
+ }
203
+
204
+ /**
205
+ * Kicking this off by calling 'get_instance()' method
206
+ */
207
+ Astra_Sites_Batch_Processing::get_instance();
208
+
209
+ endif;
inc/importers/batch-processing/helpers/class-wp-async-request.php CHANGED
@@ -1,164 +1,164 @@
1
- <?php
2
- /**
3
- * WP Async Request
4
- *
5
- * @see https://github.com/A5hleyRich/wp-background-processing/
6
- * @package WP-Background-Processing
7
- */
8
-
9
- if ( ! class_exists( 'WP_Async_Request' ) ) {
10
-
11
- /**
12
- * Abstract WP_Async_Request class.
13
- *
14
- * @abstract
15
- */
16
- abstract class WP_Async_Request {
17
-
18
- /**
19
- * Prefix
20
- *
21
- * (default value: 'wp')
22
- *
23
- * @var string
24
- * @access protected
25
- */
26
- protected $prefix = 'wp';
27
-
28
- /**
29
- * Action
30
- *
31
- * (default value: 'async_request')
32
- *
33
- * @var string
34
- * @access protected
35
- */
36
- protected $action = 'async_request';
37
-
38
- /**
39
- * Identifier
40
- *
41
- * @var mixed
42
- * @access protected
43
- */
44
- protected $identifier;
45
-
46
- /**
47
- * Data
48
- *
49
- * (default value: array())
50
- *
51
- * @var array
52
- * @access protected
53
- */
54
- protected $data = array();
55
-
56
- /**
57
- * Initiate new async request
58
- */
59
- public function __construct() {
60
- $this->identifier = $this->prefix . '_' . $this->action;
61
-
62
- add_action( 'wp_ajax_' . $this->identifier, array( $this, 'maybe_handle' ) );
63
- add_action( 'wp_ajax_nopriv_' . $this->identifier, array( $this, 'maybe_handle' ) );
64
- }
65
-
66
- /**
67
- * Set data used during the request
68
- *
69
- * @param array $data Data.
70
- *
71
- * @return $this
72
- */
73
- public function data( $data ) {
74
- $this->data = $data;
75
-
76
- return $this;
77
- }
78
-
79
- /**
80
- * Dispatch the async request
81
- *
82
- * @return array|WP_Error
83
- */
84
- public function dispatch() {
85
- $url = add_query_arg( $this->get_query_args(), $this->get_query_url() );
86
- $args = $this->get_post_args();
87
-
88
- return wp_remote_post( esc_url_raw( $url ), $args );
89
- }
90
-
91
- /**
92
- * Get query args
93
- *
94
- * @return array
95
- */
96
- protected function get_query_args() {
97
- if ( property_exists( $this, 'query_args' ) ) {
98
- return $this->query_args;
99
- }
100
-
101
- return array(
102
- 'action' => $this->identifier,
103
- 'nonce' => wp_create_nonce( $this->identifier ),
104
- );
105
- }
106
-
107
- /**
108
- * Get query URL
109
- *
110
- * @return string
111
- */
112
- protected function get_query_url() {
113
- if ( property_exists( $this, 'query_url' ) ) {
114
- return $this->query_url;
115
- }
116
-
117
- return admin_url( 'admin-ajax.php' );
118
- }
119
-
120
- /**
121
- * Get post args
122
- *
123
- * @return array
124
- */
125
- protected function get_post_args() {
126
- if ( property_exists( $this, 'post_args' ) ) {
127
- return $this->post_args;
128
- }
129
-
130
- return array(
131
- 'timeout' => 0.01,
132
- 'blocking' => false,
133
- 'body' => $this->data,
134
- 'cookies' => $_COOKIE,
135
- 'sslverify' => apply_filters( 'https_local_ssl_verify', false ),
136
- );
137
- }
138
-
139
- /**
140
- * Maybe handle
141
- *
142
- * Check for correct nonce and pass to handler.
143
- */
144
- public function maybe_handle() {
145
- // Don't lock up other requests while processing.
146
- session_write_close();
147
-
148
- check_ajax_referer( $this->identifier, 'nonce' );
149
-
150
- $this->handle();
151
-
152
- wp_die();
153
- }
154
-
155
- /**
156
- * Handle
157
- *
158
- * Override this method to perform any actions required
159
- * during the async request.
160
- */
161
- abstract protected function handle();
162
-
163
- }
164
- }
1
+ <?php
2
+ /**
3
+ * WP Async Request
4
+ *
5
+ * @see https://github.com/A5hleyRich/wp-background-processing/
6
+ * @package WP-Background-Processing
7
+ */
8
+
9
+ if ( ! class_exists( 'WP_Async_Request' ) ) {
10
+
11
+ /**
12
+ * Abstract WP_Async_Request class.
13
+ *
14
+ * @abstract
15
+ */
16
+ abstract class WP_Async_Request {
17
+
18
+ /**
19
+ * Prefix
20
+ *
21
+ * (default value: 'wp')
22
+ *
23
+ * @var string
24
+ * @access protected
25
+ */
26
+ protected $prefix = 'wp';
27
+
28
+ /**
29
+ * Action
30
+ *
31
+ * (default value: 'async_request')
32
+ *
33
+ * @var string
34
+ * @access protected
35
+ */
36
+ protected $action = 'async_request';
37
+
38
+ /**
39
+ * Identifier
40
+ *
41
+ * @var mixed
42
+ * @access protected
43
+ */
44
+ protected $identifier;
45
+
46
+ /**
47
+ * Data
48
+ *
49
+ * (default value: array())
50
+ *
51
+ * @var array
52
+ * @access protected
53
+ */
54
+ protected $data = array();
55
+
56
+ /**
57
+ * Initiate new async request
58
+ */
59
+ public function __construct() {
60
+ $this->identifier = $this->prefix . '_' . $this->action;
61
+
62
+ add_action( 'wp_ajax_' . $this->identifier, array( $this, 'maybe_handle' ) );
63
+ add_action( 'wp_ajax_nopriv_' . $this->identifier, array( $this, 'maybe_handle' ) );
64
+ }
65
+
66
+ /**
67
+ * Set data used during the request
68
+ *
69
+ * @param array $data Data.
70
+ *
71
+ * @return $this
72
+ */
73
+ public function data( $data ) {
74
+ $this->data = $data;
75
+
76
+ return $this;
77
+ }
78
+
79
+ /**
80
+ * Dispatch the async request
81
+ *
82
+ * @return array|WP_Error
83
+ */
84
+ public function dispatch() {
85
+ $url = add_query_arg( $this->get_query_args(), $this->get_query_url() );
86
+ $args = $this->get_post_args();
87
+
88
+ return wp_remote_post( esc_url_raw( $url ), $args );
89
+ }
90
+
91
+ /**
92
+ * Get query args
93
+ *
94
+ * @return array
95
+ */
96
+ protected function get_query_args() {
97
+ if ( property_exists( $this, 'query_args' ) ) {
98
+ return $this->query_args;
99
+ }
100
+
101
+ return array(
102
+ 'action' => $this->identifier,
103
+ 'nonce' => wp_create_nonce( $this->identifier ),
104
+ );
105
+ }
106
+
107
+ /**
108
+ * Get query URL
109
+ *
110
+ * @return string
111
+ */
112
+ protected function get_query_url() {
113
+ if ( property_exists( $this, 'query_url' ) ) {
114
+ return $this->query_url;
115
+ }
116
+
117
+ return admin_url( 'admin-ajax.php' );
118
+ }
119
+
120
+ /**
121
+ * Get post args
122
+ *
123
+ * @return array
124
+ */
125
+ protected function get_post_args() {
126
+ if ( property_exists( $this, 'post_args' ) ) {
127
+ return $this->post_args;
128
+ }
129
+
130
+ return array(
131
+ 'timeout' => 0.01,
132
+ 'blocking' => false,
133
+ 'body' => $this->data,
134
+ 'cookies' => $_COOKIE,
135
+ 'sslverify' => apply_filters( 'https_local_ssl_verify', false ),
136
+ );
137
+ }
138
+
139
+ /**
140
+ * Maybe handle
141
+ *
142
+ * Check for correct nonce and pass to handler.
143
+ */
144
+ public function maybe_handle() {
145
+ // Don't lock up other requests while processing.
146
+ session_write_close();
147
+
148
+ check_ajax_referer( $this->identifier, 'nonce' );
149
+
150
+ $this->handle();
151
+
152
+ wp_die();
153
+ }
154
+
155
+ /**
156
+ * Handle
157
+ *
158
+ * Override this method to perform any actions required
159
+ * during the async request.
160
+ */
161
+ abstract protected function handle();
162
+
163
+ }
164
+ }
inc/importers/batch-processing/helpers/class-wp-background-process.php CHANGED
@@ -1,513 +1,513 @@
1
- <?php
2
- /**
3
- * WP Background Process
4
- *
5
- * @see https://github.com/A5hleyRich/wp-background-processing/
6
- * @package WP-Background-Processing
7
- */
8
-
9
- if ( ! class_exists( 'WP_Background_Process' ) ) {
10
-
11
- /**
12
- * Abstract WP_Background_Process class.
13
- *
14
- * @abstract
15
- * @extends WP_Async_Request
16
- */
17
- abstract class WP_Background_Process extends WP_Async_Request {
18
-
19
- /**
20
- * Action
21
- *
22
- * (default value: 'background_process')
23
- *
24
- * @var string
25
- * @access protected
26
- */
27
- protected $action = 'background_process';
28
-
29
- /**
30
- * Start time of current process.
31
- *
32
- * (default value: 0)
33
- *
34
- * @var int
35
- * @access protected
36
- */
37
- protected $start_time = 0;
38
-
39
- /**
40
- * Cron_hook_identifier
41
- *
42
- * @var mixed
43
- * @access protected
44
- */
45
- protected $cron_hook_identifier;
46
-
47
- /**
48
- * Cron_interval_identifier
49
- *
50
- * @var mixed
51
- * @access protected
52
- */
53
- protected $cron_interval_identifier;
54
-
55
- /**
56
- * Initiate new background process
57
- */
58
- public function __construct() {
59
- parent::__construct();
60
-
61
- $this->cron_hook_identifier = $this->identifier . '_cron';
62
- $this->cron_interval_identifier = $this->identifier . '_cron_interval';
63
-
64
- add_action( $this->cron_hook_identifier, array( $this, 'handle_cron_healthcheck' ) );
65
- add_filter( 'cron_schedules', array( $this, 'schedule_cron_healthcheck' ) );
66
- }
67
-
68
- /**
69
- * Dispatch
70
- *
71
- * @return mixed dispatch event.
72
- */
73
- public function dispatch() {
74
- // Schedule the cron healthcheck.
75
- $this->schedule_event();
76
-
77
- // Perform remote post.
78
- return parent::dispatch();
79
- }
80
-
81
- /**
82
- * Push to queue
83
- *
84
- * @param mixed $data Data.
85
- *
86
- * @return $this
87
- */
88
- public function push_to_queue( $data ) {
89
- $this->data[] = $data;
90
-
91
- return $this;
92
- }
93
-
94
- /**
95
- * Save queue
96
- *
97
- * @return $this
98
- */
99
- public function save() {
100
- $key = $this->generate_key();
101
-
102
- if ( ! empty( $this->data ) ) {
103
- update_site_option( $key, $this->data );
104
- }
105
-
106
- return $this;
107
- }
108
-
109
- /**
110
- * Update queue
111
- *
112
- * @param string $key Key.
113
- * @param array $data Data.
114
- *
115
- * @return $this
116
- */
117
- public function update( $key, $data ) {
118
- if ( ! empty( $data ) ) {
119
- update_site_option( $key, $data );
120
- }
121
-
122
- return $this;
123
- }
124
-
125
- /**
126
- * Delete queue
127
- *
128
- * @param string $key Key.
129
- *
130
- * @return $this
131
- */
132
- public function delete( $key ) {
133
- delete_site_option( $key );
134
-
135
- return $this;
136
- }
137
-
138
- /**
139
- * Generate key
140
- *
141
- * Generates a unique key based on microtime. Queue items are
142
- * given a unique key so that they can be merged upon save.
143
- *
144
- * @param int $length Length.
145
- *
146
- * @return string
147
- */
148
- protected function generate_key( $length = 64 ) {
149
- $unique = md5( microtime() . rand() );
150
- $prepend = $this->identifier . '_batch_';
151
-
152
- return substr( $prepend . $unique, 0, $length );
153
- }
154
-
155
- /**
156
- * Maybe process queue
157
- *
158
- * Checks whether data exists within the queue and that
159
- * the process is not already running.
160
- */
161
- public function maybe_handle() {
162
- // Don't lock up other requests while processing.
163
- session_write_close();
164
-
165
- if ( $this->is_process_running() ) {
166
- // Background process already running.
167
- wp_die();
168
- }
169
-
170
- if ( $this->is_queue_empty() ) {
171
- // No data to process.
172
- wp_die();
173
- }
174
-
175
- check_ajax_referer( $this->identifier, 'nonce' );
176
-
177
- $this->handle();
178
-
179
- wp_die();
180
- }
181
-
182
- /**
183
- * Is queue empty
184
- *
185
- * @return bool
186
- */
187
- protected function is_queue_empty() {
188
- global $wpdb;
189
-
190
- $table = $wpdb->options;
191
- $column = 'option_name';
192
-
193
- if ( is_multisite() ) {
194
- $table = $wpdb->sitemeta;
195
- $column = 'meta_key';
196
- }
197
-
198
- $key = $this->identifier . '_batch_%';
199
-
200
- $count = $wpdb->get_var(
201
- $wpdb->prepare(
202
- "
203
- SELECT COUNT(*)
204
- FROM {$table}
205
- WHERE {$column} LIKE %s
206
- ", $key
207
- )
208
- );
209
-
210
- return ( $count > 0 ) ? false : true;
211
- }
212
-
213
- /**
214
- * Is process running
215
- *
216
- * Check whether the current process is already running
217
- * in a background process.
218
- */
219
- protected function is_process_running() {
220
- if ( get_site_transient( $this->identifier . '_process_lock' ) ) {
221
- // Process already running.
222
- return true;
223
- }
224
-
225
- return false;
226
- }
227
-
228
- /**
229
- * Lock process
230
- *
231
- * Lock the process so that multiple instances can't run simultaneously.
232
- * Override if applicable, but the duration should be greater than that
233
- * defined in the time_exceeded() method.
234
- */
235
- protected function lock_process() {
236
- $this->start_time = time(); // Set start time of current process.
237
-
238
- $lock_duration = ( property_exists( $this, 'queue_lock_time' ) ) ? $this->queue_lock_time : 60; // 1 minute
239
- $lock_duration = apply_filters( $this->identifier . '_queue_lock_time', $lock_duration );
240
-
241
- set_site_transient( $this->identifier . '_process_lock', microtime(), $lock_duration );
242
- }
243
-
244
- /**
245
- * Unlock process
246
- *
247
- * Unlock the process so that other instances can spawn.
248
- *
249
- * @return $this
250
- */
251
- protected function unlock_process() {
252
- delete_site_transient( $this->identifier . '_process_lock' );
253
-
254
- return $this;
255
- }
256
-
257
- /**
258
- * Get batch
259
- *
260
- * @return stdClass Return the first batch from the queue
261
- */
262
- protected function get_batch() {
263
- global $wpdb;
264
-
265
- $table = $wpdb->options;
266
- $column = 'option_name';
267
- $key_column = 'option_id';
268
- $value_column = 'option_value';
269
-
270
- if ( is_multisite() ) {
271
- $table = $wpdb->sitemeta;
272
- $column = 'meta_key';
273
- $key_column = 'meta_id';
274
- $value_column = 'meta_value';
275
- }
276
-
277
- $key = $this->identifier . '_batch_%';
278
-
279
- $query = $wpdb->get_row(
280
- $wpdb->prepare(
281
- "
282
- SELECT *
283
- FROM {$table}
284
- WHERE {$column} LIKE %s
285
- ORDER BY {$key_column} ASC
286
- LIMIT 1
287
- ", $key
288
- )
289
- );
290
-
291
- $batch = new stdClass();
292
- $batch->key = $query->$column;
293
- $batch->data = maybe_unserialize( $query->$value_column );
294
-
295
- return $batch;
296
- }
297
-
298
- /**
299
- * Handle
300
- *
301
- * Pass each queue item to the task handler, while remaining
302
- * within server memory and time limit constraints.
303
- */
304
- protected function handle() {
305
- $this->lock_process();
306
-
307
- do {
308
- $batch = $this->get_batch();
309
-
310
- foreach ( $batch->data as $key => $value ) {
311
- $task = $this->task( $value );
312
-
313
- if ( false !== $task ) {
314
- $batch->data[ $key ] = $task;
315
- } else {
316
- unset( $batch->data[ $key ] );
317
- }
318
-
319
- if ( $this->time_exceeded() || $this->memory_exceeded() ) {
320
- // Batch limits reached.
321
- break;
322
- }
323
- }
324
-
325
- // Update or delete current batch.
326
- if ( ! empty( $batch->data ) ) {
327
- $this->update( $batch->key, $batch->data );
328
- } else {
329
- $this->delete( $batch->key );
330
- }
331
- } while ( ! $this->time_exceeded() && ! $this->memory_exceeded() && ! $this->is_queue_empty() );
332
-
333
- $this->unlock_process();
334
-
335
- // Start next batch or complete process.
336
- if ( ! $this->is_queue_empty() ) {
337
- $this->dispatch();
338
- } else {
339
- $this->complete();
340
- }
341
-
342
- wp_die();
343
- }
344
-
345
- /**
346
- * Memory exceeded
347
- *
348
- * Ensures the batch process never exceeds 90%
349
- * of the maximum WordPress memory.
350
- *
351
- * @return bool
352
- */
353
- protected function memory_exceeded() {
354
- $memory_limit = $this->get_memory_limit() * 0.9; // 90% of max memory
355
- $current_memory = memory_get_usage( true );
356
- $return = false;
357
-
358
- if ( $current_memory >= $memory_limit ) {
359
- $return = true;
360
- }
361
-
362
- return apply_filters( $this->identifier . '_memory_exceeded', $return );
363
- }
364
-
365
- /**
366
- * Get memory limit
367
- *
368
- * @return int
369
- */
370
- protected function get_memory_limit() {
371
- if ( function_exists( 'ini_get' ) ) {
372
- $memory_limit = ini_get( 'memory_limit' );
373
- } else {
374
- // Sensible default.
375
- $memory_limit = '128M';
376
- }
377
-
378
- if ( ! $memory_limit || -1 === $memory_limit ) {
379
- // Unlimited, set to 32GB.
380
- $memory_limit = '32000M';
381
- }
382
-
383
- return intval( $memory_limit ) * 1024 * 1024;
384
- }
385
-
386
- /**
387
- * Time exceeded.
388
- *
389
- * Ensures the batch never exceeds a sensible time limit.
390
- * A timeout limit of 30s is common on shared hosting.
391
- *
392
- * @return bool
393
- */
394
- protected function time_exceeded() {
395
- $finish = $this->start_time + apply_filters( $this->identifier . '_default_time_limit', 20 ); // 20 seconds
396
- $return = false;
397
-
398
- if ( time() >= $finish ) {
399
- $return = true;
400
- }
401
-
402
- return apply_filters( $this->identifier . '_time_exceeded', $return );
403
- }
404
-
405
- /**
406
- * Complete.
407
- *
408
- * Override if applicable, but ensure that the below actions are
409
- * performed, or, call parent::complete().
410
- */
411
- protected function complete() {
412
- // Unschedule the cron healthcheck.
413
- $this->clear_scheduled_event();
414
- }
415
-
416
- /**
417
- * Schedule cron healthcheck
418
- *
419
- * @access public
420
- * @param mixed $schedules Schedules.
421
- * @return mixed
422
- */
423
- public function schedule_cron_healthcheck( $schedules ) {
424
- $interval = apply_filters( $this->identifier . '_cron_interval', 5 );
425
-
426
- if ( property_exists( $this, 'cron_interval' ) ) {
427
- $interval = apply_filters( $this->identifier . '_cron_interval', $this->cron_interval_identifier );
428
- }
429
-
430
- // Adds every 5 minutes to the existing schedules.
431
- $schedules[ $this->identifier . '_cron_interval' ] = array(
432
- 'interval' => MINUTE_IN_SECONDS * $interval,
433
- 'display' => sprintf( __( 'Every %d Minutes', 'astra-sites' ), $interval ),
434
- );
435
-
436
- return $schedules;
437
- }
438
-
439
- /**
440
- * Handle cron healthcheck
441
- *
442
- * Restart the background process if not already running
443
- * and data exists in the queue.
444
- */
445
- public function handle_cron_healthcheck() {
446
- if ( $this->is_process_running() ) {
447
- // Background process already running.
448
- exit;
449
- }
450
-
451
- if ( $this->is_queue_empty() ) {
452
- // No data to process.
453
- $this->clear_scheduled_event();
454
- exit;
455
- }
456
-
457
- $this->handle();
458
-
459
- exit;
460
- }
461
-
462
- /**
463
- * Schedule event
464
- */
465
- protected function schedule_event() {
466
- if ( ! wp_next_scheduled( $this->cron_hook_identifier ) ) {
467
- wp_schedule_event( time(), $this->cron_interval_identifier, $this->cron_hook_identifier );
468
- }
469
- }
470
-
471
- /**
472
- * Clear scheduled event
473
- */
474
- protected function clear_scheduled_event() {
475
- $timestamp = wp_next_scheduled( $this->cron_hook_identifier );
476
-
477
- if ( $timestamp ) {
478
- wp_unschedule_event( $timestamp, $this->cron_hook_identifier );
479
- }
480
- }
481
-
482
- /**
483
- * Cancel Process
484
- *
485
- * Stop processing queue items, clear cronjob and delete batch.
486
- */
487
- public function cancel_process() {
488
- if ( ! $this->is_queue_empty() ) {
489
- $batch = $this->get_batch();
490
-
491
- $this->delete( $batch->key );
492
-
493
- wp_clear_scheduled_hook( $this->cron_hook_identifier );
494
- }
495
-
496
- }
497
-
498
- /**
499
- * Task
500
- *
501
- * Override this method to perform any actions required on each
502
- * queue item. Return the modified item for further processing
503
- * in the next pass through. Or, return false to remove the
504
- * item from the queue.
505
- *
506
- * @param mixed $item Queue item to iterate over.
507
- *
508
- * @return mixed
509
- */
510
- abstract protected function task( $item );
511
-
512
- }
513
- }
1
+ <?php
2
+ /**
3
+ * WP Background Process
4
+ *
5
+ * @see https://github.com/A5hleyRich/wp-background-processing/
6
+ * @package WP-Background-Processing
7
+ */
8
+
9
+ if ( ! class_exists( 'WP_Background_Process' ) ) {
10
+
11
+ /**
12
+ * Abstract WP_Background_Process class.
13
+ *
14
+ * @abstract
15
+ * @extends WP_Async_Request
16
+ */
17
+ abstract class WP_Background_Process extends WP_Async_Request {
18
+
19
+ /**
20
+ * Action
21
+ *
22
+ * (default value: 'background_process')
23
+ *
24
+ * @var string
25
+ * @access protected
26
+ */
27
+ protected $action = 'background_process';
28
+
29
+ /**
30
+ * Start time of current process.
31
+ *
32
+ * (default value: 0)
33
+ *
34
+ * @var int
35
+ * @access protected
36
+ */
37
+ protected $start_time = 0;
38
+
39
+ /**
40
+ * Cron_hook_identifier
41
+ *
42
+ * @var mixed
43
+ * @access protected
44
+ */
45
+ protected $cron_hook_identifier;
46
+
47
+ /**
48
+ * Cron_interval_identifier
49
+ *
50
+ * @var mixed
51
+ * @access protected
52
+ */
53
+ protected $cron_interval_identifier;
54
+
55
+ /**
56
+ * Initiate new background process
57
+ */
58
+ public function __construct() {
59
+ parent::__construct();
60
+
61
+ $this->cron_hook_identifier = $this->identifier . '_cron';
62
+ $this->cron_interval_identifier = $this->identifier . '_cron_interval';
63
+
64
+ add_action( $this->cron_hook_identifier, array( $this, 'handle_cron_healthcheck' ) );
65
+ add_filter( 'cron_schedules', array( $this, 'schedule_cron_healthcheck' ) );
66
+ }
67
+
68
+ /**
69
+ * Dispatch
70
+ *
71
+ * @return mixed dispatch event.
72
+ */
73
+ public function dispatch() {
74
+ // Schedule the cron healthcheck.
75
+ $this->schedule_event();
76
+
77
+ // Perform remote post.
78
+ return parent::dispatch();
79
+ }
80
+
81
+ /**
82
+ * Push to queue
83
+ *
84
+ * @param mixed $data Data.
85
+ *
86
+ * @return $this
87
+ */
88
+ public function push_to_queue( $data ) {
89
+ $this->data[] = $data;
90
+
91
+ return $this;
92
+ }
93
+
94
+ /**
95
+ * Save queue
96
+ *
97
+ * @return $this
98
+ */
99
+ public function save() {
100
+ $key = $this->generate_key();
101
+
102
+ if ( ! empty( $this->data ) ) {
103
+ update_site_option( $key, $this->data );
104
+ }
105
+
106
+ return $this;
107
+ }
108
+
109
+ /**
110
+ * Update queue
111
+ *
112
+ * @param string $key Key.
113
+ * @param array $data Data.
114
+ *
115
+ * @return $this
116
+ */
117
+ public function update( $key, $data ) {
118
+ if ( ! empty( $data ) ) {
119
+ update_site_option( $key, $data );
120
+ }
121
+
122
+ return $this;
123
+ }
124
+
125
+ /**
126
+ * Delete queue
127
+ *
128
+ * @param string $key Key.
129
+ *
130
+ * @return $this
131
+ */
132
+ public function delete( $key ) {
133
+ delete_site_option( $key );
134
+
135
+ return $this;
136
+ }
137
+
138
+ /**
139
+ * Generate key
140
+ *
141
+ * Generates a unique key based on microtime. Queue items are
142
+ * given a unique key so that they can be merged upon save.
143
+ *
144
+ * @param int $length Length.
145
+ *
146
+ * @return string
147
+ */
148
+ protected function generate_key( $length = 64 ) {
149
+ $unique = md5( microtime() . rand() );
150
+ $prepend = $this->identifier . '_batch_';
151
+
152
+ return substr( $prepend . $unique, 0, $length );
153
+ }
154
+
155
+ /**
156
+ * Maybe process queue
157
+ *
158
+ * Checks whether data exists within the queue and that
159
+ * the process is not already running.
160
+ */
161
+ public function maybe_handle() {
162
+ // Don't lock up other requests while processing.
163
+ session_write_close();
164
+
165
+ if ( $this->is_process_running() ) {
166
+ // Background process already running.
167
+ wp_die();
168
+ }
169
+
170
+ if ( $this->is_queue_empty() ) {
171
+ // No data to process.
172
+ wp_die();
173
+ }
174
+
175
+ check_ajax_referer( $this->identifier, 'nonce' );
176
+
177
+ $this->handle();
178
+
179
+ wp_die();
180
+ }
181
+
182
+ /**
183
+ * Is queue empty
184
+ *
185
+ * @return bool
186
+ */
187
+ protected function is_queue_empty() {
188
+ global $wpdb;
189
+
190
+ $table = $wpdb->options;
191
+ $column = 'option_name';
192
+
193
+ if ( is_multisite() ) {
194
+ $table = $wpdb->sitemeta;
195
+ $column = 'meta_key';
196
+ }
197
+
198
+ $key = $this->identifier . '_batch_%';
199
+
200
+ $count = $wpdb->get_var(
201
+ $wpdb->prepare(
202
+ "
203
+ SELECT COUNT(*)
204
+ FROM {$table}
205
+ WHERE {$column} LIKE %s
206
+ ", $key
207
+ )
208
+ );
209
+
210
+ return ( $count > 0 ) ? false : true;
211
+ }
212
+
213
+ /**
214
+ * Is process running
215
+ *
216
+ * Check whether the current process is already running
217
+ * in a background process.
218
+ */
219
+ protected function is_process_running() {
220
+ if ( get_site_transient( $this->identifier . '_process_lock' ) ) {
221
+ // Process already running.
222
+ return true;
223
+ }
224
+
225
+ return false;
226
+ }
227
+
228
+ /**
229
+ * Lock process
230
+ *
231
+ * Lock the process so that multiple instances can't run simultaneously.
232
+ * Override if applicable, but the duration should be greater than that
233
+ * defined in the time_exceeded() method.
234
+ */
235
+ protected function lock_process() {
236
+ $this->start_time = time(); // Set start time of current process.
237
+
238
+ $lock_duration = ( property_exists( $this, 'queue_lock_time' ) ) ? $this->queue_lock_time : 60; // 1 minute
239
+ $lock_duration = apply_filters( $this->identifier . '_queue_lock_time', $lock_duration );
240
+
241
+ set_site_transient( $this->identifier . '_process_lock', microtime(), $lock_duration );
242
+ }
243
+
244
+ /**
245
+ * Unlock process
246
+ *
247
+ * Unlock the process so that other instances can spawn.
248
+ *
249
+ * @return $this
250
+ */
251
+ protected function unlock_process() {
252
+ delete_site_transient( $this->identifier . '_process_lock' );
253
+
254
+ return $this;
255
+ }
256
+
257
+ /**
258
+ * Get batch
259
+ *
260
+ * @return stdClass Return the first batch from the queue
261
+ */
262
+ protected function get_batch() {
263
+ global $wpdb;
264
+
265
+ $table = $wpdb->options;
266
+ $column = 'option_name';
267
+ $key_column = 'option_id';
268
+ $value_column = 'option_value';
269
+
270
+ if ( is_multisite() ) {
271
+ $table = $wpdb->sitemeta;
272
+ $column = 'meta_key';
273
+ $key_column = 'meta_id';
274
+ $value_column = 'meta_value';
275
+ }
276
+
277
+ $key = $this->identifier . '_batch_%';
278
+
279
+ $query = $wpdb->get_row(
280
+ $wpdb->prepare(
281
+ "
282
+ SELECT *
283
+ FROM {$table}
284
+ WHERE {$column} LIKE %s
285
+ ORDER BY {$key_column} ASC
286
+ LIMIT 1
287
+ ", $key
288
+ )
289
+ );
290
+
291
+ $batch = new stdClass();
292
+ $batch->key = $query->$column;
293
+ $batch->data = maybe_unserialize( $query->$value_column );
294
+
295
+ return $batch;
296
+ }
297
+
298
+ /**
299
+ * Handle
300
+ *
301
+ * Pass each queue item to the task handler, while remaining
302
+ * within server memory and time limit constraints.
303
+ */
304
+ protected function handle() {
305
+ $this->lock_process();
306
+
307
+ do {
308
+ $batch = $this->get_batch();
309
+
310
+ foreach ( $batch->data as $key => $value ) {
311
+ $task = $this->task( $value );
312
+
313
+ if ( false !== $task ) {
314
+ $batch->data[ $key ] = $task;
315
+ } else {
316
+ unset( $batch->data[ $key ] );
317
+ }
318
+
319
+ if ( $this->time_exceeded() || $this->memory_exceeded() ) {
320
+ // Batch limits reached.
321
+ break;
322
+ }
323
+ }
324
+
325
+ // Update or delete current batch.
326
+ if ( ! empty( $batch->data ) ) {
327
+ $this->update( $batch->key, $batch->data );
328
+ } else {
329
+ $this->delete( $batch->key );
330
+ }
331
+ } while ( ! $this->time_exceeded() && ! $this->memory_exceeded() && ! $this->is_queue_empty() );
332
+
333
+ $this->unlock_process();
334
+
335
+ // Start next batch or complete process.
336
+ if ( ! $this->is_queue_empty() ) {
337
+ $this->dispatch();
338
+ } else {
339
+ $this->complete();
340
+ }
341
+
342
+ wp_die();
343
+ }
344
+
345
+ /**
346
+ * Memory exceeded
347
+ *
348
+ * Ensures the batch process never exceeds 90%
349
+ * of the maximum WordPress memory.
350
+ *
351
+ * @return bool
352
+ */
353
+ protected function memory_exceeded() {
354
+ $memory_limit = $this->get_memory_limit() * 0.9; // 90% of max memory
355
+ $current_memory = memory_get_usage( true );
356
+ $return = false;
357
+
358
+ if ( $current_memory >= $memory_limit ) {
359
+ $return = true;
360
+ }
361
+
362
+ return apply_filters( $this->identifier . '_memory_exceeded', $return );
363
+ }
364
+
365
+ /**
366
+ * Get memory limit
367
+ *
368
+ * @return int
369
+ */
370
+ protected function get_memory_limit() {
371
+ if ( function_exists( 'ini_get' ) ) {
372
+ $memory_limit = ini_get( 'memory_limit' );
373
+ } else {
374
+ // Sensible default.
375
+ $memory_limit = '128M';
376
+ }
377
+
378
+ if ( ! $memory_limit || -1 === $memory_limit ) {
379
+ // Unlimited, set to 32GB.
380
+ $memory_limit = '32000M';
381
+ }
382
+
383
+ return intval( $memory_limit ) * 1024 * 1024;
384
+ }
385
+
386
+ /**
387
+ * Time exceeded.
388
+ *
389
+ * Ensures the batch never exceeds a sensible time limit.
390
+ * A timeout limit of 30s is common on shared hosting.
391
+ *
392
+ * @return bool
393
+ */
394
+ protected function time_exceeded() {
395
+ $finish = $this->start_time + apply_filters( $this->identifier . '_default_time_limit', 20 ); // 20 seconds
396
+ $return = false;
397
+
398
+ if ( time() >= $finish ) {
399
+ $return = true;
400
+ }
401
+
402
+ return apply_filters( $this->identifier . '_time_exceeded', $return );
403
+ }
404
+
405
+ /**
406
+ * Complete.
407
+ *
408
+ * Override if applicable, but ensure that the below actions are
409
+ * performed, or, call parent::complete().
410
+ */
411
+ protected function complete() {
412
+ // Unschedule the cron healthcheck.
413
+ $this->clear_scheduled_event();
414
+ }
415
+
416
+ /**
417
+ * Schedule cron healthcheck
418
+ *
419
+ * @access public
420
+ * @param mixed $schedules Schedules.
421
+ * @return mixed
422
+ */
423
+ public function schedule_cron_healthcheck( $schedules ) {
424
+ $interval = apply_filters( $this->identifier . '_cron_interval', 5 );
425
+
426
+ if ( property_exists( $this, 'cron_interval' ) ) {
427
+ $interval = apply_filters( $this->identifier . '_cron_interval', $this->cron_interval_identifier );
428
+ }
429
+
430
+ // Adds every 5 minutes to the existing schedules.
431
+ $schedules[ $this->identifier . '_cron_interval' ] = array(
432
+ 'interval' => MINUTE_IN_SECONDS * $interval,
433
+ 'display' => sprintf( __( 'Every %d Minutes', 'astra-sites' ), $interval ),
434
+ );
435
+
436
+ return $schedules;
437
+ }
438
+
439
+ /**
440
+ * Handle cron healthcheck
441
+ *
442
+ * Restart the background process if not already running
443
+ * and data exists in the queue.
444
+ */
445
+ public function handle_cron_healthcheck() {
446
+ if ( $this->is_process_running() ) {
447
+ // Background process already running.
448
+ exit;
449
+ }
450
+
451
+ if ( $this->is_queue_empty() ) {
452
+ // No data to process.
453
+ $this->clear_scheduled_event();
454
+ exit;
455
+ }
456
+
457
+ $this->handle();
458
+
459
+ exit;
460
+ }
461
+
462
+ /**
463
+ * Schedule event
464
+ */
465
+ protected function schedule_event() {
466
+ if ( ! wp_next_scheduled( $this->cron_hook_identifier ) ) {
467
+ wp_schedule_event( time(), $this->cron_interval_identifier, $this->cron_hook_identifier );
468
+ }
469
+ }
470
+
471
+ /**
472
+ * Clear scheduled event
473
+ */
474
+ protected function clear_scheduled_event() {
475
+ $timestamp = wp_next_scheduled( $this->cron_hook_identifier );
476
+
477
+ if ( $timestamp ) {
478
+ wp_unschedule_event( $timestamp, $this->cron_hook_identifier );
479
+ }
480
+ }
481
+
482
+ /**
483
+ * Cancel Process
484
+ *
485
+ * Stop processing queue items, clear cronjob and delete batch.
486
+ */
487
+ public function cancel_process() {
488
+ if ( ! $this->is_queue_empty() ) {
489
+ $batch = $this->get_batch();
490
+
491
+ $this->delete( $batch->key );
492
+
493
+ wp_clear_scheduled_hook( $this->cron_hook_identifier );
494
+ }
495
+
496
+ }
497
+
498
+ /**
499
+ * Task
500
+ *
501
+ * Override this method to perform any actions required on each
502
+ * queue item. Return the modified item for further processing
503
+ * in the next pass through. Or, return false to remove the
504
+ * item from the queue.
505
+ *
506
+ * @param mixed $item Queue item to iterate over.
507
+ *
508
+ * @return mixed
509
+ */
510
+ abstract protected function task( $item );
511
+
512
+ }
513
+ }
inc/importers/class-astra-site-options-import.php CHANGED
@@ -1,284 +1,287 @@
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
- * Site Options
42
- *
43
- * @since 1.0.2
44
- *
45
- * @return array List of defined array.
46
- */
47
- private static function site_options() {
48
- return array(
49
- 'custom_logo',
50
- 'nav_menu_locations',
51
- 'show_on_front',
52
- 'page_on_front',
53
- 'page_for_posts',
54
-
55
- // Plugin: SiteOrigin Widgets Bundle.
56
- 'siteorigin_widgets_active',
57
-
58
- // Plugin: Elementor.
59
- 'elementor_container_width',
60
- 'elementor_cpt_support',
61
- 'elementor_css_print_method',
62
- 'elementor_default_generic_fonts',
63
- 'elementor_disable_color_schemes',
64
- 'elementor_disable_typography_schemes',
65
- 'elementor_editor_break_lines',
66
- 'elementor_exclude_user_roles',
67
- 'elementor_global_image_lightbox',
68
- 'elementor_page_title_selector',
69
- 'elementor_scheme_color',
70
- 'elementor_scheme_color-picker',
71
- 'elementor_scheme_typography',
72
- 'elementor_space_between_widgets',
73
- 'elementor_stretched_section_container',
74
-
75
- // Plugin: Beaver Builder.
76
- '_fl_builder_enabled_icons',
77
- '_fl_builder_enabled_modules',
78
- '_fl_builder_post_types',
79
- '_fl_builder_color_presets',
80
- '_fl_builder_services',
81
- '_fl_builder_settings',
82
- '_fl_builder_user_access',
83
- '_fl_builder_enabled_templates',
84
-
85
- // Plugin: WooCommerce.
86
- // Pages.
87
- 'woocommerce_shop_page_title',
88
- 'woocommerce_cart_page_title',
89
- 'woocommerce_checkout_page_title',
90
- 'woocommerce_myaccount_page_title',
91
- 'woocommerce_edit_address_page_title',
92
- 'woocommerce_view_order_page_title',
93
- 'woocommerce_change_password_page_title',
94
- 'woocommerce_logout_page_title',
95
- 'woocommerce_enable_guest_checkout',
96
- 'woocommerce_enable_checkout_login_reminder',
97
- 'woocommerce_enable_signup_and_login_from_checkout',
98
- 'woocommerce_enable_myaccount_registration',
99
- 'woocommerce_registration_generate_username',
100
-
101
- // Categories.
102
- 'woocommerce_product_cat',
103
- );
104
- }
105
-
106
- /**
107
- * Import site options.
108
- *
109
- * @since 1.0.2 Updated option if exist in defined option array 'site_options()'.
110
- *
111
- * @since 1.0.0
112
- *
113
- * @param (Array) $options Array of site options to be imported from the demo.
114
- */
115
- public function import_options( $options = array() ) {
116
-
117
- if ( ! isset( $options ) ) {
118
- return;
119
- }
120
-
121
- foreach ( $options as $option_name => $option_value ) {
122
-
123
- // Is option exist in defined array site_options()?
124
- if ( null !== $option_value ) {
125
-
126
- // Is option exist in defined array site_options()?
127
- if ( in_array( $option_name, self::site_options() ) ) {
128
-
129
- switch ( $option_name ) {
130
-
131
- // Set WooCommerce page ID by page Title.
132
- case 'woocommerce_shop_page_title':
133
- case 'woocommerce_cart_page_title':
134
- case 'woocommerce_checkout_page_title':
135
- case 'woocommerce_myaccount_page_title':
136
- case 'woocommerce_edit_address_page_title':
137
- case 'woocommerce_view_order_page_title':
138
- case 'woocommerce_change_password_page_title':
139
- case 'woocommerce_logout_page_title':
140
- $this->update_woocommerce_page_id_by_option_value( $option_name, $option_value );
141
- break;
142
-
143
- case 'page_for_posts':
144
- case 'page_on_front':
145
- $this->update_page_id_by_option_value( $option_name, $option_value );
146
- break;
147
-
148
- // nav menu locations.
149
- case 'nav_menu_locations':
150
- $this->set_nav_menu_locations( $option_value );
151
- break;
152
-
153
- // import WooCommerce category images.
154
- case 'woocommerce_product_cat':
155
- $this->set_woocommerce_product_cat( $option_value );
156
- break;
157
-
158
- // insert logo.
159
- case 'custom_logo':
160
- $this->insert_logo( $option_value );
161
- break;
162
-
163
- default:
164
- update_option( $option_name, $option_value );
165
- break;
166
- }
167
- }
168
- }
169
- }
170
- }
171
-
172
- /**
173
- * Update post option
174
- *
175
- * @since 1.0.2
176
- *
177
- * @param string $option_name Option name.
178
- * @param mixed $option_value Option value.
179
- * @return void
180
- */
181
- private function update_page_id_by_option_value( $option_name, $option_value ) {
182
- $page = get_page_by_title( $option_value );
183
- if ( is_object( $page ) ) {
184
- update_option( $option_name, $page->ID );
185
- }
186
- }
187
-
188
- /**
189
- * Update WooCommerce page ids.
190
- *
191
- * @since 1.1.6
192
- *
193
- * @param string $option_name Option name.
194
- * @param mixed $option_value Option value.
195
- * @return void
196
- */
197
- private function update_woocommerce_page_id_by_option_value( $option_name, $option_value ) {
198
- $option_name = str_replace( '_title', '_id', $option_name );
199
- $this->update_page_id_by_option_value( $option_name, $option_value );
200
- }
201
-
202
- /**
203
- * In WP nav menu is stored as ( 'menu_location' => 'menu_id' );
204
- * In export we send 'menu_slug' like ( 'menu_location' => 'menu_slug' );
205
- * In import we set 'menu_id' from menu slug like ( 'menu_location' => 'menu_id' );
206
- *
207
- * @since 1.0.0
208
- * @param array $nav_menu_locations Array of nav menu locations.
209
- */
210
- private function set_nav_menu_locations( $nav_menu_locations = array() ) {
211
-
212
- $menu_locations = array();
213
-
214
- // Update menu locations.
215
- if ( isset( $nav_menu_locations ) ) {
216
-
217
- foreach ( $nav_menu_locations as $menu => $value ) {
218
-
219
- $term = get_term_by( 'slug', $value, 'nav_menu' );
220
-
221
- if ( is_object( $term ) ) {
222
- $menu_locations[ $menu ] = $term->term_id;
223
- }
224
- }
225
-
226
- set_theme_mod( 'nav_menu_locations', $menu_locations );
227
- }
228
- }
229
-
230
- /**
231
- * Set WooCommerce category images.
232
- *
233
- * @since 1.1.4
234
- *
235
- * @param array $cats Array of categories.
236
- */
237
- private function set_woocommerce_product_cat( $cats = array() ) {
238
-
239
- $menu_locations = array();
240
-
241
- if ( isset( $cats ) ) {
242
-
243
- foreach ( $cats as $key => $cat ) {
244
-
245
- if ( ! empty( $cat['slug'] ) && ! empty( $cat['thumbnail_src'] ) ) {
246
-
247
- $image = (object) Astra_Sites_Helper::_sideload_image( $cat['thumbnail_src'] );
248
-
249
- if ( ! is_wp_error( $image ) ) {
250
-
251
- if ( isset( $image->attachment_id ) && ! empty( $image->attachment_id ) ) {
252
-
253
- $term = get_term_by( 'slug', $cat['slug'], 'product_cat' );
254
-
255
- if ( is_object( $term ) ) {
256
- update_term_meta( $term->term_id, 'thumbnail_id', $image->attachment_id );
257
- }
258
- }
259
- }
260
- }
261
- }
262
- }
263
- }
264
-
265
- /**
266
- * Insert Logo By URL
267
- *
268
- * @since 1.0.0
269
- * @param string $image_url Logo URL.
270
- * @return void
271
- */
272
- private function insert_logo( $image_url = '' ) {
273
-
274
- $data = (object) Astra_Sites_Helper::_sideload_image( $image_url );
275
-
276
- if ( ! is_wp_error( $data ) ) {
277
-
278
- if ( isset( $data->attachment_id ) && ! empty( $data->attachment_id ) ) {
279
- set_theme_mod( 'custom_logo', $data->attachment_id );
280
- }
281
- }
282
- }
283
-
284
- }
 
 
 
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
+ * Site Options
42
+ *
43
+ * @since 1.0.2
44
+ *
45
+ * @return array List of defined array.
46
+ */
47
+ private static function site_options() {
48
+ return array(
49
+ 'custom_logo',
50
+ 'nav_menu_locations',
51
+ 'show_on_front',
52
+ 'page_on_front',
53
+ 'page_for_posts',
54
+
55
+ // Plugin: SiteOrigin Widgets Bundle.
56
+ 'siteorigin_widgets_active',
57
+
58
+ // Plugin: Elementor.
59
+ 'elementor_container_width',
60
+ 'elementor_cpt_support',
61
+ 'elementor_css_print_method',
62
+ 'elementor_default_generic_fonts',
63
+ 'elementor_disable_color_schemes',
64
+ 'elementor_disable_typography_schemes',
65
+ 'elementor_editor_break_lines',
66
+ 'elementor_exclude_user_roles',
67
+ 'elementor_global_image_lightbox',
68
+ 'elementor_page_title_selector',
69
+ 'elementor_scheme_color',
70
+ 'elementor_scheme_color-picker',
71
+ 'elementor_scheme_typography',
72
+ 'elementor_space_between_widgets',
73
+ 'elementor_stretched_section_container',
74
+
75
+ // Plugin: Beaver Builder.
76
+ '_fl_builder_enabled_icons',
77
+ '_fl_builder_enabled_modules',
78
+ '_fl_builder_post_types',
79
+ '_fl_builder_color_presets',
80
+ '_fl_builder_services',
81
+ '_fl_builder_settings',
82
+ '_fl_builder_user_access',
83
+ '_fl_builder_enabled_templates',
84
+
85
+ // Plugin: WooCommerce.
86
+ // Pages.
87
+ 'woocommerce_shop_page_title',
88
+ 'woocommerce_cart_page_title',
89
+ 'woocommerce_checkout_page_title',
90
+ 'woocommerce_myaccount_page_title',
91
+ 'woocommerce_edit_address_page_title',
92
+ 'woocommerce_view_order_page_title',
93
+ 'woocommerce_change_password_page_title',
94
+ 'woocommerce_logout_page_title',
95
+ 'woocommerce_enable_guest_checkout',
96
+ 'woocommerce_enable_checkout_login_reminder',
97
+ 'woocommerce_enable_signup_and_login_from_checkout',
98
+ 'woocommerce_enable_myaccount_registration',
99
+ 'woocommerce_registration_generate_username',
100
+
101
+ // Plugin: WPForms.
102
+ 'wpforms_settings',
103
+
104
+ // Categories.
105
+ 'woocommerce_product_cat',
106
+ );
107
+ }
108
+
109
+ /**
110
+ * Import site options.
111
+ *
112
+ * @since 1.0.2 Updated option if exist in defined option array 'site_options()'.
113
+ *
114
+ * @since 1.0.0
115
+ *
116
+ * @param (Array) $options Array of site options to be imported from the demo.
117
+ */
118
+ public function import_options( $options = array() ) {
119
+
120
+ if ( ! isset( $options ) ) {
121
+ return;
122
+ }
123
+
124
+ foreach ( $options as $option_name => $option_value ) {
125
+
126
+ // Is option exist in defined array site_options()?
127
+ if ( null !== $option_value ) {
128
+
129
+ // Is option exist in defined array site_options()?
130
+ if ( in_array( $option_name, self::site_options() ) ) {
131
+
132
+ switch ( $option_name ) {
133
+
134
+ // Set WooCommerce page ID by page Title.
135
+ case 'woocommerce_shop_page_title':
136
+ case 'woocommerce_cart_page_title':
137
+ case 'woocommerce_checkout_page_title':
138
+ case 'woocommerce_myaccount_page_title':
139
+ case 'woocommerce_edit_address_page_title':
140
+ case 'woocommerce_view_order_page_title':
141
+ case 'woocommerce_change_password_page_title':
142
+ case 'woocommerce_logout_page_title':
143
+ $this->update_woocommerce_page_id_by_option_value( $option_name, $option_value );
144
+ break;
145
+
146
+ case 'page_for_posts':
147
+ case 'page_on_front':
148
+ $this->update_page_id_by_option_value( $option_name, $option_value );
149
+ break;
150
+
151
+ // nav menu locations.
152
+ case 'nav_menu_locations':
153
+ $this->set_nav_menu_locations( $option_value );
154
+ break;
155
+
156
+ // import WooCommerce category images.
157
+ case 'woocommerce_product_cat':
158
+ $this->set_woocommerce_product_cat( $option_value );
159
+ break;
160
+
161
+ // insert logo.
162
+ case 'custom_logo':
163
+ $this->insert_logo( $option_value );
164
+ break;
165
+
166
+ default:
167
+ update_option( $option_name, $option_value );
168
+ break;
169
+ }
170
+ }
171
+ }
172
+ }
173
+ }
174
+
175
+ /**
176
+ * Update post option
177
+ *
178
+ * @since 1.0.2
179
+ *
180
+ * @param string $option_name Option name.
181
+ * @param mixed $option_value Option value.
182
+ * @return void
183
+ */
184
+ private function update_page_id_by_option_value( $option_name, $option_value ) {
185
+ $page = get_page_by_title( $option_value );
186
+ if ( is_object( $page ) ) {
187
+ update_option( $option_name, $page->ID );
188
+ }
189
+ }
190
+
191
+ /**
192
+ * Update WooCommerce page ids.
193
+ *
194
+ * @since 1.1.6
195
+ *
196
+ * @param string $option_name Option name.
197
+ * @param mixed $option_value Option value.
198
+ * @return void
199
+ */
200
+ private function update_woocommerce_page_id_by_option_value( $option_name, $option_value ) {
201
+ $option_name = str_replace( '_title', '_id', $option_name );
202
+ $this->update_page_id_by_option_value( $option_name, $option_value );
203
+ }
204
+
205
+ /**
206
+ * In WP nav menu is stored as ( 'menu_location' => 'menu_id' );
207
+ * In export we send 'menu_slug' like ( 'menu_location' => 'menu_slug' );
208
+ * In import we set 'menu_id' from menu slug like ( 'menu_location' => 'menu_id' );
209
+ *
210
+ * @since 1.0.0
211
+ * @param array $nav_menu_locations Array of nav menu locations.
212
+ */
213
+ private function set_nav_menu_locations( $nav_menu_locations = array() ) {
214
+
215
+ $menu_locations = array();
216
+
217
+ // Update menu locations.
218
+ if ( isset( $nav_menu_locations ) ) {
219
+
220
+ foreach ( $nav_menu_locations as $menu => $value ) {
221
+
222
+ $term = get_term_by( 'slug', $value, 'nav_menu' );
223
+
224
+ if ( is_object( $term ) ) {
225
+ $menu_locations[ $menu ] = $term->term_id;
226
+ }
227
+ }
228
+
229
+ set_theme_mod( 'nav_menu_locations', $menu_locations );
230
+ }
231
+ }
232
+
233
+ /**
234
+ * Set WooCommerce category images.
235
+ *
236
+ * @since 1.1.4
237
+ *
238
+ * @param array $cats Array of categories.
239
+ */
240
+ private function set_woocommerce_product_cat( $cats = array() ) {
241
+
242
+ $menu_locations = array();
243
+
244
+ if ( isset( $cats ) ) {
245
+
246
+ foreach ( $cats as $key => $cat ) {
247
+
248
+ if ( ! empty( $cat['slug'] ) && ! empty( $cat['thumbnail_src'] ) ) {
249
+
250
+ $image = (object) Astra_Sites_Helper::_sideload_image( $cat['thumbnail_src'] );
251
+
252
+ if ( ! is_wp_error( $image ) ) {
253
+
254
+ if ( isset( $image->attachment_id ) && ! empty( $image->attachment_id ) ) {
255
+
256
+ $term = get_term_by( 'slug', $cat['slug'], 'product_cat' );
257
+
258
+ if ( is_object( $term ) ) {
259
+ update_term_meta( $term->term_id, 'thumbnail_id', $image->attachment_id );
260
+ }
261
+ }
262
+ }
263
+ }
264
+ }
265
+ }
266
+ }
267
+
268
+ /**
269
+ * Insert Logo By URL
270
+ *
271
+ * @since 1.0.0
272
+ * @param string $image_url Logo URL.
273
+ * @return void
274
+ */
275
+ private function insert_logo( $image_url = '' ) {
276
+
277
+ $data = (object) Astra_Sites_Helper::_sideload_image( $image_url );
278
+
279
+ if ( ! is_wp_error( $data ) ) {
280
+
281
+ if ( isset( $data->attachment_id ) && ! empty( $data->attachment_id ) ) {
282
+ set_theme_mod( 'custom_logo', $data->attachment_id );
283
+ }
284
+ }
285
+ }
286
+
287
+ }
inc/importers/class-astra-sites-helper.php CHANGED
@@ -1,310 +1,311 @@
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
- add_filter( 'wie_import_data', array( $this, 'custom_menu_widget' ) );
47
- add_filter( 'wp_prepare_attachment_for_js', array( $this, 'add_svg_image_support' ), 10, 3 );
48
- }
49
-
50
- /**
51
- * Add svg image support
52
- *
53
- * @since 1.1.5
54
- *
55
- * @param array $response Attachment response.
56
- * @param object $attachment Attachment object.
57
- * @param array $meta Attachment meta data.
58
- */
59
- function add_svg_image_support( $response, $attachment, $meta ) {
60
- if ( ! function_exists( 'simplexml_load_file' ) ) {
61
- return $response;
62
- }
63
-
64
- if ( ! empty( $response['sizes'] ) ) {
65
- return $response;
66
- }
67
-
68
- if ( 'image/svg+xml' !== $response['mime'] ) {
69
- return $response;
70
- }
71
-
72
- $svg_path = get_attached_file( $attachment->ID );
73
-
74
- $dimensions = self::get_svg_dimensions( $svg_path );
75
-
76
- $response['sizes'] = array(
77
- 'full' => array(
78
- 'url' => $response['url'],
79
- 'width' => $dimensions->width,
80
- 'height' => $dimensions->height,
81
- 'orientation' => $dimensions->width > $dimensions->height ? 'landscape' : 'portrait',
82
- ),
83
- );
84
-
85
- return $response;
86
- }
87
-
88
- /**
89
- * Get SVG Dimensions
90
- *
91
- * @since 1.1.5
92
- *
93
- * @param string $svg SVG file path.
94
- * @return array Return SVG file height & width for valid SVG file.
95
- */
96
- public static function get_svg_dimensions( $svg ) {
97
-
98
- $svg = simplexml_load_file( $svg );
99
-
100
- if ( false === $svg ) {
101
- $width = '0';
102
- $height = '0';
103
- } else {
104
- $attributes = $svg->attributes();
105
- $width = (string) $attributes->width;
106
- $height = (string) $attributes->height;
107
- }
108
-
109
- return (object) array(
110
- 'width' => $width,
111
- 'height' => $height,
112
- );
113
- }
114
-
115
- /**
116
- * Custom Menu Widget
117
- *
118
- * In widget export we set the nav menu slug instead of ID.
119
- * So, In import process we check get menu id by slug and set
120
- * it in import widget process.
121
- *
122
- * @since 1.0.7
123
- *
124
- * @param object $all_sidebars Widget data.
125
- * @return object Set custom menu id by slug.
126
- */
127
- function custom_menu_widget( $all_sidebars ) {
128
-
129
- // Get current menu ID & Slugs.
130
- $menu_locations = array();
131
- $nav_menus = (object) wp_get_nav_menus();
132
- if ( isset( $nav_menus ) ) {
133
- foreach ( $nav_menus as $menu_key => $menu ) {
134
- if ( is_object( $menu ) ) {
135
- $menu_locations[ $menu->term_id ] = $menu->slug;
136
- }
137
- }
138
- }
139
-
140
- // Import widget data.
141
- $all_sidebars = (object) $all_sidebars;
142
- foreach ( $all_sidebars as $widgets_key => $widgets ) {
143
- foreach ( $widgets as $widget_key => $widget ) {
144
-
145
- // Found slug in current menu list.
146
- if ( isset( $widget->nav_menu ) ) {
147
- $menu_id = array_search( $widget->nav_menu, $menu_locations );
148
- if ( ! empty( $menu_id ) ) {
149
- $all_sidebars->$widgets_key->$widget_key->nav_menu = $menu_id;
150
- }
151
- }
152
- }
153
- }
154
-
155
- return $all_sidebars;
156
- }
157
-
158
- /**
159
- * Download File Into Uploads Directory
160
- *
161
- * @param string $file Download File URL.
162
- * @return array Downloaded file data.
163
- */
164
- public static function download_file( $file = '' ) {
165
-
166
- // Gives us access to the download_url() and wp_handle_sideload() functions.
167
- require_once( ABSPATH . 'wp-admin/includes/file.php' );
168
-
169
- $timeout_seconds = 5;
170
-
171
- // Download file to temp dir.
172
- $temp_file = download_url( $file, $timeout_seconds );
173
-
174
- // WP Error.
175
- if ( is_wp_error( $temp_file ) ) {
176
- return array(
177
- 'success' => false,
178
- 'data' => $temp_file->get_error_message(),
179
- );
180
- }
181
-
182
- // Array based on $_FILE as seen in PHP file uploads.
183
- $file_args = array(
184
- 'name' => basename( $file ),
185
- 'tmp_name' => $temp_file,
186
- 'error' => 0,
187
- 'size' => filesize( $temp_file ),
188
- );
189
-
190
- $overrides = array(
191
-
192
- // Tells WordPress to not look for the POST form
193
- // fields that would normally be present as
194
- // we downloaded the file from a remote server, so there
195
- // will be no form fields
196
- // Default is true.
197
- 'test_form' => false,
198
-
199
- // Setting this to false lets WordPress allow empty files, not recommended.
200
- // Default is true.
201
- 'test_size' => true,
202
-
203
- // A properly uploaded file will pass this test. There should be no reason to override this one.
204
- 'test_upload' => true,
205
-
206
- 'mimes' => array(
207
- 'xml' => 'text/xml',
208
- ),
209
- );
210
-
211
- // Move the temporary file into the uploads directory.
212
- $results = wp_handle_sideload( $file_args, $overrides );
213
-
214
- if ( isset( $results['error'] ) ) {
215
- return array(
216
- 'success' => false,
217
- 'data' => $results,
218
- );
219
- }
220
-
221
- // Success.
222
- return array(
223
- 'success' => true,
224
- 'data' => $results,
225
- );
226
- }
227
-
228
- /**
229
- * Downloads an image from the specified URL.
230
- *
231
- * Taken from the core media_sideload_image() function and
232
- * modified to return an array of data instead of html.
233
- *
234
- * @since 1.0.10
235
- *
236
- * @param string $file The image file path.
237
- * @return array An array of image data.
238
- */
239
- static public function _sideload_image( $file ) {
240
- $data = new stdClass();
241
-
242
- if ( ! function_exists( 'media_handle_sideload' ) ) {
243
- require_once( ABSPATH . 'wp-admin/includes/media.php' );
244
- require_once( ABSPATH . 'wp-admin/includes/file.php' );
245
- require_once( ABSPATH . 'wp-admin/includes/image.php' );
246
- }
247
-
248
- if ( ! empty( $file ) ) {
249
-
250
- // Set variables for storage, fix file filename for query strings.
251
- preg_match( '/[^\?]+\.(jpe?g|jpe|svg|gif|png)\b/i', $file, $matches );
252
- $file_array = array();
253
- $file_array['name'] = basename( $matches[0] );
254
-
255
- // Download file to temp location.
256
- $file_array['tmp_name'] = download_url( $file );
257
-
258
- // If error storing temporarily, return the error.
259
- if ( is_wp_error( $file_array['tmp_name'] ) ) {
260
- return $file_array['tmp_name'];
261
- }
262
-
263
- // Do the validation and storage stuff.
264
- $id = media_handle_sideload( $file_array, 0 );
265
-
266
- // If error storing permanently, unlink.
267
- if ( is_wp_error( $id ) ) {
268
- unlink( $file_array['tmp_name'] );
269
- return $id;
270
- }
271
-
272
- // Build the object to return.
273
- $meta = wp_get_attachment_metadata( $id );
274
- $data->attachment_id = $id;
275
- $data->url = wp_get_attachment_url( $id );
276
- $data->thumbnail_url = wp_get_attachment_thumb_url( $id );
277
- $data->height = $meta['height'];
278
- $data->width = $meta['width'];
279
- }
280
-
281
- return $data;
282
- }
283
-
284
- /**
285
- * Checks to see whether a string is an image url or not.
286
- *
287
- * @since 1.0.10
288
- *
289
- * @param string $string The string to check.
290
- * @return bool Whether the string is an image url or not.
291
- */
292
- static public function _is_image_url( $string = '' ) {
293
- if ( is_string( $string ) ) {
294
-
295
- if ( preg_match( '/\.(jpg|jpeg|png|gif)/i', $string ) ) {
296
- return true;
297
- }
298
- }
299
-
300
- return false;
301
- }
302
-
303
- }
304
-
305
- /**
306
- * Kicking this off by calling 'get_instance()' method
307
- */
308
- Astra_Sites_Helper::get_instance();
309
-
310
- endif;
 
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
+ add_filter( 'wie_import_data', array( $this, 'custom_menu_widget' ) );
47
+ add_filter( 'wp_prepare_attachment_for_js', array( $this, 'add_svg_image_support' ), 10, 3 );
48
+ }
49
+
50
+ /**
51
+ * Add svg image support
52
+ *
53
+ * @since 1.1.5
54
+ *
55
+ * @param array $response Attachment response.
56
+ * @param object $attachment Attachment object.
57
+ * @param array $meta Attachment meta data.
58
+ */
59
+ function add_svg_image_support( $response, $attachment, $meta ) {
60
+ if ( ! function_exists( 'simplexml_load_file' ) ) {
61
+ return $response;
62
+ }
63
+
64
+ if ( ! empty( $response['sizes'] ) ) {
65
+ return $response;
66
+ }
67
+
68
+ if ( 'image/svg+xml' !== $response['mime'] ) {
69
+ return $response;
70
+ }
71
+
72
+ $svg_path = get_attached_file( $attachment->ID );
73
+
74
+ $dimensions = self::get_svg_dimensions( $svg_path );
75
+
76
+ $response['sizes'] = array(
77
+ 'full' => array(
78
+ 'url' => $response['url'],
79
+ 'width' => $dimensions->width,
80
+ 'height' => $dimensions->height,
81
+ 'orientation' => $dimensions->width > $dimensions->height ? 'landscape' : 'portrait',
82
+ ),
83
+ );
84
+
85
+ return $response;
86
+ }
87
+
88
+ /**
89
+ * Get SVG Dimensions
90
+ *
91
+ * @since 1.1.5
92
+ *
93
+ * @param string $svg SVG file path.
94
+ * @return array Return SVG file height & width for valid SVG file.
95
+ */
96
+ public static function get_svg_dimensions( $svg ) {
97
+
98
+ $svg = simplexml_load_file( $svg );
99
+
100
+ if ( false === $svg ) {
101
+ $width = '0';
102
+ $height = '0';
103
+ } else {
104
+ $attributes = $svg->attributes();
105
+ $width = (string) $attributes->width;
106
+ $height = (string) $attributes->height;
107
+ }
108
+
109
+ return (object) array(
110
+ 'width' => $width,
111
+ 'height' => $height,
112
+ );
113
+ }
114
+
115
+ /**
116
+ * Custom Menu Widget
117
+ *
118
+ * In widget export we set the nav menu slug instead of ID.
119
+ * So, In import process we check get menu id by slug and set
120
+ * it in import widget process.
121
+ *
122
+ * @since 1.0.7
123
+ *
124
+ * @param object $all_sidebars Widget data.
125
+ * @return object Set custom menu id by slug.
126
+ */
127
+ function custom_menu_widget( $all_sidebars ) {
128
+
129
+ // Get current menu ID & Slugs.
130
+ $menu_locations = array();
131
+ $nav_menus = (object) wp_get_nav_menus();
132
+ if ( isset( $nav_menus ) ) {
133
+ foreach ( $nav_menus as $menu_key => $menu ) {
134
+ if ( is_object( $menu ) ) {
135
+ $menu_locations[ $menu->term_id ] = $menu->slug;
136
+ }
137
+ }
138
+ }
139
+
140
+ // Import widget data.
141
+ $all_sidebars = (object) $all_sidebars;
142
+ foreach ( $all_sidebars as $widgets_key => $widgets ) {
143
+ foreach ( $widgets as $widget_key => $widget ) {
144
+
145
+ // Found slug in current menu list.
146
+ if ( isset( $widget->nav_menu ) ) {
147
+ $menu_id = array_search( $widget->nav_menu, $menu_locations );
148
+ if ( ! empty( $menu_id ) ) {
149
+ $all_sidebars->$widgets_key->$widget_key->nav_menu = $menu_id;
150
+ }
151
+ }
152
+ }
153
+ }
154
+
155
+ return $all_sidebars;
156
+ }
157
+
158
+ /**
159
+ * Download File Into Uploads Directory
160
+ *
161
+ * @param string $file Download File URL.
162
+ * @return array Downloaded file data.
163
+ */
164
+ public static function download_file( $file = '' ) {
165
+
166
+ // Gives us access to the download_url() and wp_handle_sideload() functions.
167
+ require_once( ABSPATH . 'wp-admin/includes/file.php' );
168
+
169
+ $timeout_seconds = 5;
170
+
171
+ // Download file to temp dir.
172
+ $temp_file = download_url( $file, $timeout_seconds );
173
+
174
+ // WP Error.
175
+ if ( is_wp_error( $temp_file ) ) {
176
+ return array(
177
+ 'success' => false,
178
+ 'data' => $temp_file->get_error_message(),
179
+ );
180
+ }
181
+
182
+ // Array based on $_FILE as seen in PHP file uploads.
183
+ $file_args = array(
184
+ 'name' => basename( $file ),
185
+ 'tmp_name' => $temp_file,
186
+ 'error' => 0,
187
+ 'size' => filesize( $temp_file ),
188
+ );
189
+
190
+ $overrides = array(
191
+
192
+ // Tells WordPress to not look for the POST form
193
+ // fields that would normally be present as
194
+ // we downloaded the file from a remote server, so there
195
+ // will be no form fields
196
+ // Default is true.
197
+ 'test_form' => false,
198
+
199
+ // Setting this to false lets WordPress allow empty files, not recommended.
200
+ // Default is true.
201
+ 'test_size' => true,
202
+
203
+ // A properly uploaded file will pass this test. There should be no reason to override this one.
204
+ 'test_upload' => true,
205
+
206
+ 'mimes' => array(
207
+ 'xml' => 'text/xml',
208
+ 'json' => 'text/plain',
209
+ ),
210
+ );
211
+
212
+ // Move the temporary file into the uploads directory.
213
+ $results = wp_handle_sideload( $file_args, $overrides );
214
+
215
+ if ( isset( $results['error'] ) ) {
216
+ return array(
217
+ 'success' => false,
218
+ 'data' => $results,
219
+ );
220
+ }
221
+
222
+ // Success.
223
+ return array(
224
+ 'success' => true,
225
+ 'data' => $results,
226
+ );
227
+ }
228
+
229
+ /**
230
+ * Downloads an image from the specified URL.
231
+ *
232
+ * Taken from the core media_sideload_image() function and
233
+ * modified to return an array of data instead of html.
234
+ *
235
+ * @since 1.0.10
236
+ *
237
+ * @param string $file The image file path.
238
+ * @return array An array of image data.
239
+ */
240
+ static public function _sideload_image( $file ) {
241
+ $data = new stdClass();
242
+
243
+ if ( ! function_exists( 'media_handle_sideload' ) ) {
244
+ require_once( ABSPATH . 'wp-admin/includes/media.php' );
245
+ require_once( ABSPATH . 'wp-admin/includes/file.php' );
246
+ require_once( ABSPATH . 'wp-admin/includes/image.php' );
247
+ }
248
+
249
+ if ( ! empty( $file ) ) {
250
+
251
+ // Set variables for storage, fix file filename for query strings.
252
+ preg_match( '/[^\?]+\.(jpe?g|jpe|svg|gif|png)\b/i', $file, $matches );
253
+ $file_array = array();
254
+ $file_array['name'] = basename( $matches[0] );
255
+
256
+ // Download file to temp location.
257
+ $file_array['tmp_name'] = download_url( $file );
258
+
259
+ // If error storing temporarily, return the error.
260
+ if ( is_wp_error( $file_array['tmp_name'] ) ) {
261
+ return $file_array['tmp_name'];
262
+ }
263
+
264
+ // Do the validation and storage stuff.
265
+ $id = media_handle_sideload( $file_array, 0 );
266
+
267
+ // If error storing permanently, unlink.
268
+ if ( is_wp_error( $id ) ) {
269
+ unlink( $file_array['tmp_name'] );
270
+ return $id;
271
+ }
272
+
273
+ // Build the object to return.
274
+ $meta = wp_get_attachment_metadata( $id );
275
+ $data->attachment_id = $id;
276
+ $data->url = wp_get_attachment_url( $id );
277
+ $data->thumbnail_url = wp_get_attachment_thumb_url( $id );
278
+ $data->height = $meta['height'];
279
+ $data->width = $meta['width'];
280
+ }
281
+
282
+ return $data;
283
+ }
284
+
285
+ /**
286
+ * Checks to see whether a string is an image url or not.
287
+ *
288
+ * @since 1.0.10
289
+ *
290
+ * @param string $string The string to check.
291
+ * @return bool Whether the string is an image url or not.
292
+ */
293
+ static public function _is_image_url( $string = '' ) {
294
+ if ( is_string( $string ) ) {
295
+
296
+ if ( preg_match( '/\.(jpg|jpeg|png|gif)/i', $string ) ) {
297
+ return true;
298
+ }
299
+ }
300
+
301
+ return false;
302
+ }
303
+
304
+ }
305
+
306
+ /**
307
+ * Kicking this off by calling 'get_instance()' method
308
+ */
309
+ Astra_Sites_Helper::get_instance();
310
+
311
+ endif;
inc/importers/class-widgets-importer.php CHANGED
@@ -1,278 +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
- }
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
+ }
inc/importers/wxr-importer/class-astra-wxr-importer.php CHANGED
@@ -1,368 +1,378 @@
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
-
47
- require_once ABSPATH . '/wp-admin/includes/class-wp-importer.php';
48
- require_once ASTRA_SITES_DIR . 'inc/importers/wxr-importer/class-logger.php';
49
- require_once ASTRA_SITES_DIR . 'inc/importers/wxr-importer/class-wp-importer-logger-serversentevents.php';
50
- require_once ASTRA_SITES_DIR . 'inc/importers/wxr-importer/class-wxr-importer.php';
51
- require_once ASTRA_SITES_DIR . 'inc/importers/wxr-importer/class-wxr-import-info.php';
52
-
53
- add_filter( 'upload_mimes', array( $this, 'custom_upload_mimes' ) );
54
- add_action( 'wp_ajax_astra-wxr-import', array( $this, 'sse_import' ) );
55
- add_filter( 'wxr_importer.pre_process.user', '__return_null' );
56
- add_filter( 'wp_check_filetype_and_ext', array( $this, 'real_mime_type_for_xml' ), 10, 4 );
57
- add_filter( 'wxr_importer.pre_process.post', array( $this, 'gutenberg_content_fix' ), 10, 4 );
58
- }
59
-
60
- /**
61
- * Gutenberg Content Data Fix
62
- *
63
- * Gutenberg encode the page content. In import process the encoded characterless e.g. <, > are
64
- * decoded into HTML tag and it break the Gutenberg render markup.
65
- *
66
- * Note: We have not check the post is created with Gutenberg or not. We have imported other sites
67
- * and confirm that this works for every other page builders too.
68
- *
69
- * @since 1.2.12
70
- *
71
- * @param array $data Post data. (Return empty to skip.).
72
- * @param array $meta Meta data.
73
- * @param array $comments Comments on the post.
74
- * @param array $terms Terms on the post.
75
- */
76
- function gutenberg_content_fix( $data, $meta, $comments, $terms ) {
77
- if ( isset( $data['post_content'] ) ) {
78
- $data['post_content'] = wp_slash( $data['post_content'] );
79
- }
80
- return $data;
81
- }
82
-
83
- /**
84
- * Different MIME type of different PHP version
85
- *
86
- * Filters the "real" file type of the given file.
87
- *
88
- * @since 1.2.9
89
- *
90
- * @param array $defaults File data array containing 'ext', 'type', and
91
- * 'proper_filename' keys.
92
- * @param string $file Full path to the file.
93
- * @param string $filename The name of the file (may differ from $file due to
94
- * $file being in a tmp directory).
95
- * @param array $mimes Key is the file extension with value as the mime type.
96
- */
97
- function real_mime_type_for_xml( $defaults, $file, $filename, $mimes ) {
98
-
99
- // Set EXT and real MIME type only for the file name `wxr.xml`.
100
- if ( 'wxr.xml' == $filename ) {
101
- $defaults['ext'] = 'xml';
102
- $defaults['type'] = 'text/xml';
103
- }
104
-
105
- return $defaults;
106
- }
107
-
108
- /**
109
- * Constructor.
110
- *
111
- * @since 1.1.0
112
- */
113
- function sse_import() {
114
-
115
- // Start the event stream.
116
- header( 'Content-Type: text/event-stream, charset=UTF-8' );
117
-
118
- // Turn off PHP output compression.
119
- $previous = error_reporting( error_reporting() ^ E_WARNING );
120
- ini_set( 'output_buffering', 'off' );
121
- ini_set( 'zlib.output_compression', false );
122
- error_reporting( $previous );
123
-
124
- if ( $GLOBALS['is_nginx'] ) {
125
- // Setting this header instructs Nginx to disable fastcgi_buffering
126
- // and disable gzip for this request.
127
- header( 'X-Accel-Buffering: no' );
128
- header( 'Content-Encoding: none' );
129
- }
130
-
131
- $xml_url = urldecode( $_REQUEST['xml_url'] );
132
- if ( empty( $xml_url ) ) {
133
- exit;
134
- }
135
-
136
- // 2KB padding for IE
137
- echo ':' . str_repeat( ' ', 2048 ) . "\n\n";
138
-
139
- // Time to run the import!
140
- set_time_limit( 0 );
141
-
142
- // Ensure we're not buffered.
143
- wp_ob_end_flush_all();
144
- flush();
145
-
146
- // Are we allowed to create users?
147
- add_filter( 'wxr_importer.pre_process.user', '__return_null' );
148
-
149
- // Keep track of our progress.
150
- add_action( 'wxr_importer.processed.post', array( $this, 'imported_post' ), 10, 2 );
151
- add_action( 'wxr_importer.process_failed.post', array( $this, 'imported_post' ), 10, 2 );
152
- add_action( 'wxr_importer.process_already_imported.post', array( $this, 'already_imported_post' ), 10, 2 );
153
- add_action( 'wxr_importer.process_skipped.post', array( $this, 'already_imported_post' ), 10, 2 );
154
- add_action( 'wxr_importer.processed.comment', array( $this, 'imported_comment' ) );
155
- add_action( 'wxr_importer.process_already_imported.comment', array( $this, 'imported_comment' ) );
156
- add_action( 'wxr_importer.processed.term', array( $this, 'imported_term' ) );
157
- add_action( 'wxr_importer.process_failed.term', array( $this, 'imported_term' ) );
158
- add_action( 'wxr_importer.process_already_imported.term', array( $this, 'imported_term' ) );
159
- add_action( 'wxr_importer.processed.user', array( $this, 'imported_user' ) );
160
- add_action( 'wxr_importer.process_failed.user', array( $this, 'imported_user' ) );
161
- // Flush once more.
162
- flush();
163
-
164
- $importer = $this->get_importer();
165
- $response = $importer->import( $xml_url );
166
-
167
- // Let the browser know we're done.
168
- $complete = array(
169
- 'action' => 'complete',
170
- 'error' => false,
171
- );
172
- if ( is_wp_error( $response ) ) {
173
- $complete['error'] = $response->get_error_message();
174
- }
175
-
176
- $this->emit_sse_message( $complete );
177
- exit;
178
- }
179
-
180
- /**
181
- * Add .xml files as supported format in the uploader.
182
- *
183
- * @since 1.1.5 Added SVG file support.
184
- *
185
- * @since 1.0.0
186
- *
187
- * @param array $mimes Already supported mime types.
188
- */
189
- public function custom_upload_mimes( $mimes ) {
190
-
191
- // Allow SVG files.
192
- $mimes['svg'] = 'image/svg+xml';
193
- $mimes['svgz'] = 'image/svg+xml';
194
-
195
- // Allow XML files.
196
- $mimes['xml'] = 'text/xml';
197
-
198
- return $mimes;
199
- }
200
-
201
- /**
202
- * Start the xml import.
203
- *
204
- * @since 1.0.0
205
- *
206
- * @param (String) $path Absolute path to the XML file.
207
- */
208
- public function get_xml_data( $path ) {
209
-
210
- $args = array(
211
- 'action' => 'astra-wxr-import',
212
- 'id' => '1',
213
- 'xml_url' => $path,
214
- );
215
- $url = add_query_arg( urlencode_deep( $args ), admin_url( 'admin-ajax.php' ) );
216
-
217
- $data = $this->get_data( $path );
218
-
219
- return array(
220
- 'count' => array(
221
- 'posts' => $data->post_count,
222
- 'media' => $data->media_count,
223
- 'users' => count( $data->users ),
224
- 'comments' => $data->comment_count,
225
- 'terms' => $data->term_count,
226
- ),
227
- 'url' => $url,
228
- 'strings' => array(
229
- 'complete' => __( 'Import complete!', 'astra-sites' ),
230
- ),
231
- );
232
- }
233
-
234
- /**
235
- * Get XML data.
236
- *
237
- * @since 1.1.0
238
- * @param string $url Downloaded XML file absolute URL.
239
- * @return array XML file data.
240
- */
241
- function get_data( $url ) {
242
- $importer = $this->get_importer();
243
- $data = $importer->get_preliminary_information( $url );
244
- if ( is_wp_error( $data ) ) {
245
- return $data;
246
- }
247
- return $data;
248
- }
249
-
250
- /**
251
- * Get Importer
252
- *
253
- * @since 1.1.0
254
- * @return object Importer object.
255
- */
256
- public function get_importer() {
257
- $options = apply_filters(
258
- 'astra_sites_xml_import_options',
259
- array(
260
- 'fetch_attachments' => true,
261
- 'default_author' => get_current_user_id(),
262
- )
263
- );
264
-
265
- $importer = new WXR_Importer( $options );
266
- $logger = new WP_Importer_Logger_ServerSentEvents();
267
-
268
- $importer->set_logger( $logger );
269
- return $importer;
270
- }
271
-
272
- /**
273
- * Send message when a post has been imported.
274
- *
275
- * @since 1.1.0
276
- * @param int $id Post ID.
277
- * @param array $data Post data saved to the DB.
278
- */
279
- public function imported_post( $id, $data ) {
280
- $this->emit_sse_message(
281
- array(
282
- 'action' => 'updateDelta',
283
- 'type' => ( 'attachment' === $data['post_type'] ) ? 'media' : 'posts',
284
- 'delta' => 1,
285
- )
286
- );
287
- }
288
-
289
- /**
290
- * Send message when a post is marked as already imported.
291
- *
292
- * @since 1.1.0
293
- * @param array $data Post data saved to the DB.
294
- */
295
- public function already_imported_post( $data ) {
296
- $this->emit_sse_message(
297
- array(
298
- 'action' => 'updateDelta',
299
- 'type' => ( 'attachment' === $data['post_type'] ) ? 'media' : 'posts',
300
- 'delta' => 1,
301
- )
302
- );
303
- }
304
-
305
- /**
306
- * Send message when a comment has been imported.
307
- *
308
- * @since 1.1.0
309
- */
310
- public function imported_comment() {
311
- $this->emit_sse_message(
312
- array(
313
- 'action' => 'updateDelta',
314
- 'type' => 'comments',
315
- 'delta' => 1,
316
- )
317
- );
318
- }
319
-
320
- /**
321
- * Send message when a term has been imported.
322
- *
323
- * @since 1.1.0
324
- */
325
- public function imported_term() {
326
- $this->emit_sse_message(
327
- array(
328
- 'action' => 'updateDelta',
329
- 'type' => 'terms',
330
- 'delta' => 1,
331
- )
332
- );
333
- }
334
-
335
- /**
336
- * Send message when a user has been imported.
337
- *
338
- * @since 1.1.0
339
- */
340
- public function imported_user() {
341
- $this->emit_sse_message(
342
- array(
343
- 'action' => 'updateDelta',
344
- 'type' => 'users',
345
- 'delta' => 1,
346
- )
347
- );
348
- }
349
-
350
- /**
351
- * Emit a Server-Sent Events message.
352
- *
353
- * @since 1.1.0
354
- * @param mixed $data Data to be JSON-encoded and sent in the message.
355
- */
356
- public function emit_sse_message( $data ) {
357
- echo "event: message\n";
358
- echo 'data: ' . wp_json_encode( $data ) . "\n\n";
359
-
360
- // Extra padding.
361
- echo ':' . str_repeat( ' ', 2048 ) . "\n\n";
362
-
363
- flush();
364
- }
365
-
366
- }
367
-
368
- Astra_WXR_Importer::instance();
 
 
 
 
 
 
 
 
 
 
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
+
47
+ require_once ABSPATH . '/wp-admin/includes/class-wp-importer.php';
48
+ require_once ASTRA_SITES_DIR . 'inc/importers/wxr-importer/class-logger.php';
49
+ require_once ASTRA_SITES_DIR . 'inc/importers/wxr-importer/class-wp-importer-logger-serversentevents.php';
50
+ require_once ASTRA_SITES_DIR . 'inc/importers/wxr-importer/class-wxr-importer.php';
51
+ require_once ASTRA_SITES_DIR . 'inc/importers/wxr-importer/class-wxr-import-info.php';
52
+
53
+ add_filter( 'upload_mimes', array( $this, 'custom_upload_mimes' ) );
54
+ add_action( 'wp_ajax_astra-wxr-import', array( $this, 'sse_import' ) );
55
+ add_filter( 'wxr_importer.pre_process.user', '__return_null' );
56
+ add_filter( 'wp_check_filetype_and_ext', array( $this, 'real_mime_type_for_xml' ), 10, 5 );
57
+ add_filter( 'wxr_importer.pre_process.post', array( $this, 'gutenberg_content_fix' ), 10, 4 );
58
+ }
59
+
60
+ /**
61
+ * Gutenberg Content Data Fix
62
+ *
63
+ * Gutenberg encode the page content. In import process the encoded characterless e.g. <, > are
64
+ * decoded into HTML tag and it break the Gutenberg render markup.
65
+ *
66
+ * Note: We have not check the post is created with Gutenberg or not. We have imported other sites
67
+ * and confirm that this works for every other page builders too.
68
+ *
69
+ * @since 1.2.12
70
+ *
71
+ * @param array $data Post data. (Return empty to skip.).
72
+ * @param array $meta Meta data.
73
+ * @param array $comments Comments on the post.
74
+ * @param array $terms Terms on the post.
75
+ */
76
+ function gutenberg_content_fix( $data, $meta, $comments, $terms ) {
77
+ if ( isset( $data['post_content'] ) ) {
78
+ $data['post_content'] = wp_slash( $data['post_content'] );
79
+ }
80
+ return $data;
81
+ }
82
+
83
+ /**
84
+ * Different MIME type of different PHP version
85
+ *
86
+ * Filters the "real" file type of the given file.
87
+ *
88
+ * @since 1.2.9
89
+ *
90
+ * @param array $defaults File data array containing 'ext', 'type', and
91
+ * 'proper_filename' keys.
92
+ * @param string $file Full path to the file.
93
+ * @param string $filename The name of the file (may differ from $file due to
94
+ * $file being in a tmp directory).
95
+ * @param array $mimes Key is the file extension with value as the mime type.
96
+ * @param string $real_mime Real MIME type of the uploaded file.
97
+ */
98
+ function real_mime_type_for_xml( $defaults, $file, $filename, $mimes, $real_mime ) {
99
+
100
+ // Set EXT and real MIME type only for the file name `wxr.xml`.
101
+ if ( 'wxr.xml' == $filename ) {
102
+ $defaults['ext'] = 'xml';
103
+ $defaults['type'] = 'text/xml';
104
+ }
105
+
106
+ // Set EXT and real MIME type only for the file name `wpforms.json`.
107
+ if ( 'wpforms.json' == $filename ) {
108
+ $defaults['ext'] = 'json';
109
+ $defaults['type'] = 'text/plain';
110
+ }
111
+
112
+ return $defaults;
113
+ }
114
+
115
+ /**
116
+ * Constructor.
117
+ *
118
+ * @since 1.1.0
119
+ */
120
+ function sse_import() {
121
+
122
+ // Start the event stream.
123
+ header( 'Content-Type: text/event-stream, charset=UTF-8' );
124
+
125
+ // Turn off PHP output compression.
126
+ $previous = error_reporting( error_reporting() ^ E_WARNING );
127
+ ini_set( 'output_buffering', 'off' );
128
+ ini_set( 'zlib.output_compression', false );
129
+ error_reporting( $previous );
130
+
131
+ if ( $GLOBALS['is_nginx'] ) {
132
+ // Setting this header instructs Nginx to disable fastcgi_buffering
133
+ // and disable gzip for this request.
134
+ header( 'X-Accel-Buffering: no' );
135
+ header( 'Content-Encoding: none' );
136
+ }
137
+
138
+ $xml_url = urldecode( $_REQUEST['xml_url'] );
139
+ if ( empty( $xml_url ) ) {
140
+ exit;
141
+ }
142
+
143
+ // 2KB padding for IE
144
+ echo ':' . str_repeat( ' ', 2048 ) . "\n\n";
145
+
146
+ // Time to run the import!
147
+ set_time_limit( 0 );
148
+
149
+ // Ensure we're not buffered.
150
+ wp_ob_end_flush_all();
151
+ flush();
152
+
153
+ // Are we allowed to create users?
154
+ add_filter( 'wxr_importer.pre_process.user', '__return_null' );
155
+
156
+ // Keep track of our progress.
157
+ add_action( 'wxr_importer.processed.post', array( $this, 'imported_post' ), 10, 2 );
158
+ add_action( 'wxr_importer.process_failed.post', array( $this, 'imported_post' ), 10, 2 );
159
+ add_action( 'wxr_importer.process_already_imported.post', array( $this, 'already_imported_post' ), 10, 2 );
160
+ add_action( 'wxr_importer.process_skipped.post', array( $this, 'already_imported_post' ), 10, 2 );
161
+ add_action( 'wxr_importer.processed.comment', array( $this, 'imported_comment' ) );
162
+ add_action( 'wxr_importer.process_already_imported.comment', array( $this, 'imported_comment' ) );
163
+ add_action( 'wxr_importer.processed.term', array( $this, 'imported_term' ) );
164
+ add_action( 'wxr_importer.process_failed.term', array( $this, 'imported_term' ) );
165
+ add_action( 'wxr_importer.process_already_imported.term', array( $this, 'imported_term' ) );
166
+ add_action( 'wxr_importer.processed.user', array( $this, 'imported_user' ) );
167
+ add_action( 'wxr_importer.process_failed.user', array( $this, 'imported_user' ) );
168
+ // Flush once more.
169
+ flush();
170
+
171
+ $importer = $this->get_importer();
172
+ $response = $importer->import( $xml_url );
173
+
174
+ // Let the browser know we're done.
175
+ $complete = array(
176
+ 'action' => 'complete',
177
+ 'error' => false,
178
+ );
179
+ if ( is_wp_error( $response ) ) {
180
+ $complete['error'] = $response->get_error_message();
181
+ }
182
+
183
+ $this->emit_sse_message( $complete );
184
+ exit;
185
+ }
186
+
187
+ /**
188
+ * Add .xml files as supported format in the uploader.
189
+ *
190
+ * @since 1.1.5 Added SVG file support.
191
+ *
192
+ * @since 1.0.0
193
+ *
194
+ * @param array $mimes Already supported mime types.
195
+ */
196
+ public function custom_upload_mimes( $mimes ) {
197
+
198
+ // Allow SVG files.
199
+ $mimes['svg'] = 'image/svg+xml';
200
+ $mimes['svgz'] = 'image/svg+xml';
201
+
202
+ // Allow XML files.
203
+ $mimes['xml'] = 'text/xml';
204
+
205
+ // Allow JSON files.
206
+ $mimes['json'] = 'application/json';
207
+
208
+ return $mimes;
209
+ }
210
+
211
+ /**
212
+ * Start the xml import.
213
+ *
214
+ * @since 1.0.0
215
+ *
216
+ * @param (String) $path Absolute path to the XML file.
217
+ */
218
+ public function get_xml_data( $path ) {
219
+
220
+ $args = array(
221
+ 'action' => 'astra-wxr-import',
222
+ 'id' => '1',
223
+ 'xml_url' => $path,
224
+ );
225
+ $url = add_query_arg( urlencode_deep( $args ), admin_url( 'admin-ajax.php' ) );
226
+
227
+ $data = $this->get_data( $path );
228
+
229
+ return array(
230
+ 'count' => array(
231
+ 'posts' => $data->post_count,
232
+ 'media' => $data->media_count,
233
+ 'users' => count( $data->users ),
234
+ 'comments' => $data->comment_count,
235
+ 'terms' => $data->term_count,
236
+ ),
237
+ 'url' => $url,
238
+ 'strings' => array(
239
+ 'complete' => __( 'Import complete!', 'astra-sites' ),
240
+ ),
241
+ );
242
+ }
243
+
244
+ /**
245
+ * Get XML data.
246
+ *
247
+ * @since 1.1.0
248
+ * @param string $url Downloaded XML file absolute URL.
249
+ * @return array XML file data.
250
+ */
251
+ function get_data( $url ) {
252
+ $importer = $this->get_importer();
253
+ $data = $importer->get_preliminary_information( $url );
254
+ if ( is_wp_error( $data ) ) {
255
+ return $data;
256
+ }
257
+ return $data;
258
+ }
259
+
260
+ /**
261
+ * Get Importer
262
+ *
263
+ * @since 1.1.0
264
+ * @return object Importer object.
265
+ */
266
+ public function get_importer() {
267
+ $options = apply_filters(
268
+ 'astra_sites_xml_import_options',
269
+ array(
270
+ 'fetch_attachments' => true,
271
+ 'default_author' => get_current_user_id(),
272
+ )
273
+ );
274
+
275
+ $importer = new WXR_Importer( $options );
276
+ $logger = new WP_Importer_Logger_ServerSentEvents();
277
+
278
+ $importer->set_logger( $logger );
279
+ return $importer;
280
+ }
281
+
282
+ /**
283
+ * Send message when a post has been imported.
284
+ *
285
+ * @since 1.1.0
286
+ * @param int $id Post ID.
287
+ * @param array $data Post data saved to the DB.
288
+ */
289
+ public function imported_post( $id, $data ) {
290
+ $this->emit_sse_message(
291
+ array(
292
+ 'action' => 'updateDelta',
293
+ 'type' => ( 'attachment' === $data['post_type'] ) ? 'media' : 'posts',
294
+ 'delta' => 1,
295
+ )
296
+ );
297
+ }
298
+
299
+ /**
300
+ * Send message when a post is marked as already imported.
301
+ *
302
+ * @since 1.1.0
303
+ * @param array $data Post data saved to the DB.
304
+ */
305
+ public function already_imported_post( $data ) {
306
+ $this->emit_sse_message(
307
+ array(
308
+ 'action' => 'updateDelta',
309
+ 'type' => ( 'attachment' === $data['post_type'] ) ? 'media' : 'posts',
310
+ 'delta' => 1,
311
+ )
312
+ );
313
+ }
314
+
315
+ /**
316
+ * Send message when a comment has been imported.
317
+ *
318
+ * @since 1.1.0
319
+ */
320
+ public function imported_comment() {
321
+ $this->emit_sse_message(
322
+ array(
323
+ 'action' => 'updateDelta',
324
+ 'type' => 'comments',
325
+ 'delta' => 1,
326
+ )
327
+ );
328
+ }
329
+
330
+ /**
331
+ * Send message when a term has been imported.
332
+ *
333
+ * @since 1.1.0
334
+ */
335
+ public function imported_term() {
336
+ $this->emit_sse_message(
337
+ array(
338
+ 'action' => 'updateDelta',
339
+ 'type' => 'terms',
340
+ 'delta' => 1,
341
+ )
342
+ );
343
+ }
344
+
345
+ /**
346
+ * Send message when a user has been imported.
347
+ *
348
+ * @since 1.1.0
349
+ */
350
+ public function imported_user() {
351
+ $this->emit_sse_message(
352
+ array(
353
+ 'action' => 'updateDelta',
354
+ 'type' => 'users',
355
+ 'delta' => 1,
356
+ )
357
+ );
358
+ }
359
+
360
+ /**
361
+ * Emit a Server-Sent Events message.
362
+ *
363
+ * @since 1.1.0
364
+ * @param mixed $data Data to be JSON-encoded and sent in the message.
365
+ */
366
+ public function emit_sse_message( $data ) {
367
+ echo "event: message\n";
368
+ echo 'data: ' . wp_json_encode( $data ) . "\n\n";
369
+
370
+ // Extra padding.
371
+ echo ':' . str_repeat( ' ', 2048 ) . "\n\n";
372
+
373
+ flush();
374
+ }
375
+
376
+ }
377
+
378
+ Astra_WXR_Importer::instance();
inc/importers/wxr-importer/class-logger.php CHANGED
@@ -1,142 +1,142 @@
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
- if( ! class_exists( 'WP_Importer_Logger' ) ) :
21
- class WP_Importer_Logger {
22
- /**
23
- * System is unusable.
24
- *
25
- * @param string $message
26
- * @param array $context
27
- * @return null
28
- */
29
- public function emergency( $message, array $context = array() ) {
30
- return $this->log( 'emergency', $message, $context );
31
- }
32
-
33
- /**
34
- * Action must be taken immediately.
35
- *
36
- * Example: Entire website down, database unavailable, etc. This should
37
- * trigger the SMS alerts and wake you up.
38
- *
39
- * @param string $message
40
- * @param array $context
41
- * @return null
42
- */
43
- public function alert( $message, array $context = array() ) {
44
- return $this->log( 'alert', $message, $context );
45
- }
46
-
47
- /**
48
- * Critical conditions.
49
- *
50
- * Example: Application component unavailable, unexpected exception.
51
- *
52
- * @param string $message
53
- * @param array $context
54
- * @return null
55
- */
56
- public function critical( $message, array $context = array() ) {
57
- return $this->log( 'critical', $message, $context );
58
- }
59
-
60
- /**
61
- * Runtime errors that do not require immediate action but should typically
62
- * be logged and monitored.
63
- *
64
- * @param string $message
65
- * @param array $context
66
- * @return null
67
- */
68
- public function error( $message, array $context = array() ) {
69
- return $this->log( 'error', $message, $context );
70
- }
71
-
72
- /**
73
- * Exceptional occurrences that are not errors.
74
- *
75
- * Example: Use of deprecated APIs, poor use of an API, undesirable things
76
- * that are not necessarily wrong.
77
- *
78
- * @param string $message
79
- * @param array $context
80
- * @return null
81
- */
82
- public function warning( $message, array $context = array() ) {
83
- return $this->log( 'warning', $message, $context );
84
- }
85
-
86
- /**
87
- * Normal but significant events.
88
- *
89
- * @param string $message
90
- * @param array $context
91
- * @return null
92
- */
93
- public function notice( $message, array $context = array() ) {
94
- return $this->log( 'notice', $message, $context );
95
- }
96
-
97
- /**
98
- * Interesting events.
99
- *
100
- * Example: User logs in, SQL logs.
101
- *
102
- * @param string $message
103
- * @param array $context
104
- * @return null
105
- */
106
- public function info( $message, array $context = array() ) {
107
- return $this->log( 'info', $message, $context );
108
- }
109
-
110
- /**
111
- * Detailed debug information.
112
- *
113
- * @param string $message
114
- * @param array $context
115
- * @return null
116
- */
117
- public function debug( $message, array $context = array() ) {
118
- return $this->log( 'debug', $message, $context );
119
- }
120
-
121
- /**
122
- * Logs with an arbitrary level.
123
- *
124
- * @param mixed $level
125
- * @param string $message
126
- * @param array $context
127
- * @return null
128
- */
129
- public function log( $level, $message, array $context = array() ) {
130
-
131
- // Log
132
- do_action( 'astra_sites_import_xml_log', $level, $message, $context );
133
-
134
- $this->messages[] = array(
135
- 'timestamp' => time(),
136
- 'level' => $level,
137
- 'message' => $message,
138
- 'context' => $context,
139
- );
140
- }
141
- }
142
- endif;
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
+ if( ! class_exists( 'WP_Importer_Logger' ) ) :
21
+ class WP_Importer_Logger {
22
+ /**
23
+ * System is unusable.
24
+ *
25
+ * @param string $message
26
+ * @param array $context
27
+ * @return null
28
+ */
29
+ public function emergency( $message, array $context = array() ) {
30
+ return $this->log( 'emergency', $message, $context );
31
+ }
32
+
33
+ /**
34
+ * Action must be taken immediately.
35
+ *
36
+ * Example: Entire website down, database unavailable, etc. This should
37
+ * trigger the SMS alerts and wake you up.
38
+ *
39
+ * @param string $message
40
+ * @param array $context
41
+ * @return null
42
+ */
43
+ public function alert( $message, array $context = array() ) {
44
+ return $this->log( 'alert', $message, $context );
45
+ }
46
+
47
+ /**
48
+ * Critical conditions.
49
+ *
50
+ * Example: Application component unavailable, unexpected exception.
51
+ *
52
+ * @param string $message
53
+ * @param array $context
54
+ * @return null
55
+ */
56
+ public function critical( $message, array $context = array() ) {
57
+ return $this->log( 'critical', $message, $context );
58
+ }
59
+
60
+ /**
61
+ * Runtime errors that do not require immediate action but should typically
62
+ * be logged and monitored.
63
+ *
64
+ * @param string $message
65
+ * @param array $context
66
+ * @return null
67
+ */
68
+ public function error( $message, array $context = array() ) {
69
+ return $this->log( 'error', $message, $context );
70
+ }
71
+
72
+ /**
73
+ * Exceptional occurrences that are not errors.
74
+ *
75
+ * Example: Use of deprecated APIs, poor use of an API, undesirable things
76
+ * that are not necessarily wrong.
77
+ *
78
+ * @param string $message
79
+ * @param array $context
80
+ * @return null
81
+ */
82
+ public function warning( $message, array $context = array() ) {
83
+ return $this->log( 'warning', $message, $context );
84
+ }
85
+
86
+ /**
87
+ * Normal but significant events.
88
+ *
89
+ * @param string $message
90
+ * @param array $context
91
+ * @return null
92
+ */
93
+ public function notice( $message, array $context = array() ) {
94
+ return $this->log( 'notice', $message, $context );
95
+ }
96
+
97
+ /**
98
+ * Interesting events.
99
+ *
100
+ * Example: User logs in, SQL logs.
101
+ *
102
+ * @param string $message
103
+ * @param array $context
104
+ * @return null
105
+ */
106
+ public function info( $message, array $context = array() ) {
107
+ return $this->log( 'info', $message, $context );
108
+ }
109
+
110
+ /**
111
+ * Detailed debug information.
112
+ *
113
+ * @param string $message
114
+ * @param array $context
115
+ * @return null
116
+ */
117
+ public function debug( $message, array $context = array() ) {
118
+ return $this->log( 'debug', $message, $context );
119
+ }
120
+
121
+ /**
122
+ * Logs with an arbitrary level.
123
+ *
124
+ * @param mixed $level
125
+ * @param string $message
126
+ * @param array $context
127
+ * @return null
128
+ */
129
+ public function log( $level, $message, array $context = array() ) {
130
+
131
+ // Log
132
+ do_action( 'astra_sites_import_xml_log', $level, $message, $context );
133
+
134
+ $this->messages[] = array(
135
+ 'timestamp' => time(),
136
+ 'level' => $level,
137
+ 'message' => $message,
138
+ 'context' => $context,
139
+ );
140
+ }
141
+ }
142
+ endif;
inc/importers/wxr-importer/class-wp-importer-logger-serversentevents.php CHANGED
@@ -1,46 +1,46 @@
1
- <?php
2
-
3
- if ( ! class_exists( 'WP_Importer_Logger_ServerSentEvents' ) && class_exists( 'WP_Importer_Logger' ) ) {
4
-
5
- class WP_Importer_Logger_ServerSentEvents extends WP_Importer_Logger {
6
-
7
- /**
8
- * Logs with an arbitrary level.
9
- *
10
- * @param mixed $level
11
- * @param string $message
12
- * @param array $context
13
- * @return null
14
- */
15
- public function log( $level, $message, array $context = array() ) {
16
-
17
- // Log
18
- do_action( 'astra_sites_import_xml_log', $level, $message, $context );
19
-
20
- $data = compact( 'level', 'message' );
21
-
22
- switch ( $level ) {
23
- case 'emergency':
24
- case 'alert':
25
- case 'critical':
26
- case 'error':
27
- case 'warning':
28
- case 'notice':
29
- case 'info':
30
- echo "event: log\n";
31
- echo 'data: ' . wp_json_encode( $data ) . "\n\n";
32
- flush();
33
- break;
34
-
35
- case 'debug':
36
- if ( defined( 'IMPORT_DEBUG' ) && IMPORT_DEBUG ) {
37
- echo "event: log\n";
38
- echo 'data: ' . wp_json_encode( $data ) . "\n\n";
39
- flush();
40
- break;
41
- }
42
- break;
43
- }
44
- }
45
- }
46
- }
1
+ <?php
2
+
3
+ if ( ! class_exists( 'WP_Importer_Logger_ServerSentEvents' ) && class_exists( 'WP_Importer_Logger' ) ) {
4
+
5
+ class WP_Importer_Logger_ServerSentEvents extends WP_Importer_Logger {
6
+
7
+ /**
8
+ * Logs with an arbitrary level.
9
+ *
10
+ * @param mixed $level
11
+ * @param string $message
12
+ * @param array $context
13
+ * @return null
14
+ */
15
+ public function log( $level, $message, array $context = array() ) {
16
+
17
+ // Log
18
+ do_action( 'astra_sites_import_xml_log', $level, $message, $context );
19
+
20
+ $data = compact( 'level', 'message' );
21
+
22
+ switch ( $level ) {
23
+ case 'emergency':
24
+ case 'alert':
25
+ case 'critical':
26
+ case 'error':
27
+ case 'warning':
28
+ case 'notice':
29
+ case 'info':
30
+ echo "event: log\n";
31
+ echo 'data: ' . wp_json_encode( $data ) . "\n\n";
32
+ flush();
33
+ break;
34
+
35
+ case 'debug':
36
+ if ( defined( 'IMPORT_DEBUG' ) && IMPORT_DEBUG ) {
37
+ echo "event: log\n";
38
+ echo 'data: ' . wp_json_encode( $data ) . "\n\n";
39
+ flush();
40
+ break;
41
+ }
42
+ break;
43
+ }
44
+ }
45
+ }
46
+ }
inc/importers/wxr-importer/class-wxr-import-info.php CHANGED
@@ -1,21 +1,21 @@
1
- <?php
2
-
3
- if ( ! class_exists( 'WXR_Import_Info' ) ) {
4
-
5
- class WXR_Import_Info {
6
- public $home;
7
- public $siteurl;
8
-
9
- public $title;
10
-
11
- public $users = array();
12
- public $post_count = 0;
13
- public $media_count = 0;
14
- public $comment_count = 0;
15
- public $term_count = 0;
16
-
17
- public $generator = '';
18
- public $version;
19
- }
20
-
21
  }
1
+ <?php
2
+
3
+ if ( ! class_exists( 'WXR_Import_Info' ) ) {
4
+
5
+ class WXR_Import_Info {
6
+ public $home;
7
+ public $siteurl;
8
+
9
+ public $title;
10
+
11
+ public $users = array();
12
+ public $post_count = 0;
13
+ public $media_count = 0;
14
+ public $comment_count = 0;
15
+ public $term_count = 0;
16
+
17
+ public $generator = '';
18
+ public $version;
19
+ }
20
+
21
  }
inc/importers/wxr-importer/class-wxr-importer.php CHANGED
@@ -1,2301 +1,2301 @@
1
- <?php
2
-
3
- if( ! class_exists( 'WXR_Importer' ) && class_exists( 'WP_Importer' ) ) :
4
- class WXR_Importer extends WP_Importer {
5
- /**
6
- * Maximum supported WXR version
7
- */
8
- const MAX_WXR_VERSION = 1.2;
9
-
10
- /**
11
- * Regular expression for checking if a post references an attachment
12
- *
13
- * Note: This is a quick, weak check just to exclude text-only posts. More
14
- * vigorous checking is done later to verify.
15
- */
16
- const REGEX_HAS_ATTACHMENT_REFS = '!
17
- (
18
- # Match anything with an image or attachment class
19
- class=[\'"].*?\b(wp-image-\d+|attachment-[\w\-]+)\b
20
- |
21
- # Match anything that looks like an upload URL
22
- src=[\'"][^\'"]*(
23
- [0-9]{4}/[0-9]{2}/[^\'"]+\.(jpg|jpeg|png|gif)
24
- |
25
- content/uploads[^\'"]+
26
- )[\'"]
27
- )!ix';
28
-
29
- /**
30
- * Version of WXR we're importing.
31
- *
32
- * Defaults to 1.0 for compatibility. Typically overridden by a
33
- * `<wp:wxr_version>` tag at the start of the file.
34
- *
35
- * @var string
36
- */
37
- protected $version = '1.0';
38
-
39
- // information to import from WXR file
40
- protected $categories = array();
41
- protected $tags = array();
42
- protected $base_url = '';
43
-
44
- // TODO: REMOVE THESE
45
- protected $processed_terms = array();
46
- protected $processed_posts = array();
47
- protected $processed_menu_items = array();
48
- protected $menu_item_orphans = array();
49
- protected $missing_menu_items = array();
50
-
51
- // NEW STYLE
52
- protected $mapping = array();
53
- protected $requires_remapping = array();
54
- protected $exists = array();
55
- protected $user_slug_override = array();
56
-
57
- protected $url_remap = array();
58
- protected $featured_images = array();
59
-
60
- /**
61
- * Logger instance.
62
- *
63
- * @var WP_Importer_Logger
64
- */
65
- protected $logger;
66
-
67
- /**
68
- * Constructor
69
- *
70
- * @param array $options {
71
- * @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.)
72
- * @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.)
73
- * @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.)
74
- * @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.)
75
- * @var bool $fetch_attachments Fetch attachments from the remote server. (True fetches and creates attachment posts, false skips attachments. Default is false.)
76
- * @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.)
77
- * @var int $default_author User ID to use if author is missing or invalid. (Default is null, which leaves posts unassigned.)
78
- * }
79
- */
80
- public function __construct( $options = array() ) {
81
- // Initialize some important variables
82
- $empty_types = array(
83
- 'post' => array(),
84
- 'comment' => array(),
85
- 'term' => array(),
86
- 'user' => array(),
87
- );
88
-
89
- $this->mapping = $empty_types;
90
- $this->mapping['user_slug'] = array();
91
- $this->mapping['term_id'] = array();
92
- $this->requires_remapping = $empty_types;
93
- $this->exists = $empty_types;
94
-
95
- $this->options = wp_parse_args( $options, array(
96
- 'prefill_existing_posts' => true,
97
- 'prefill_existing_comments' => true,
98
- 'prefill_existing_terms' => true,
99
- 'update_attachment_guids' => false,
100
- 'fetch_attachments' => false,
101
- 'aggressive_url_search' => false,
102
- 'default_author' => null,
103
- ) );
104
- }
105
-
106
- public function set_logger( $logger ) {
107
- $this->logger = $logger;
108
- }
109
-
110
- /**
111
- * Get a stream reader for the file.
112
- *
113
- * @param string $file Path to the XML file.
114
- * @return XMLReader|WP_Error Reader instance on success, error otherwise.
115
- */
116
- protected function get_reader( $file ) {
117
- // Avoid loading external entities for security
118
- $old_value = null;
119
- if ( function_exists( 'libxml_disable_entity_loader' ) ) {
120
- // $old_value = libxml_disable_entity_loader( true );
121
- }
122
-
123
- $reader = new XMLReader();
124
- $status = $reader->open( $file );
125
-
126
- if ( ! is_null( $old_value ) ) {
127
- // libxml_disable_entity_loader( $old_value );
128
- }
129
-
130
- if ( ! $status ) {
131
- return new WP_Error( 'wxr_importer.cannot_parse', __( 'Could not open the file for parsing', 'wordpress-importer' ) );
132
- }
133
-
134
- return $reader;
135
- }
136
-
137
- /**
138
- * The main controller for the actual import stage.
139
- *
140
- * @param string $file Path to the WXR file for importing
141
- */
142
- public function get_preliminary_information( $file ) {
143
- // Let's run the actual importer now, woot
144
- $reader = $this->get_reader( $file );
145
- if ( is_wp_error( $reader ) ) {
146
- return $reader;
147
- }
148
-
149
- // Set the version to compatibility mode first
150
- $this->version = '1.0';
151
-
152
- // Start parsing!
153
- $data = new WXR_Import_Info();
154
- while ( $reader->read() ) {
155
- // Only deal with element opens
156
- if ( $reader->nodeType !== XMLReader::ELEMENT ) {
157
- continue;
158
- }
159
-
160
- switch ( $reader->name ) {
161
- case 'wp:wxr_version':
162
- // Upgrade to the correct version
163
- $this->version = $reader->readString();
164
-
165
- if ( version_compare( $this->version, self::MAX_WXR_VERSION, '>' ) ) {
166
- $this->logger->warning( sprintf(
167
- __( 'This WXR file (version %1$s) is newer than the importer (version %2$s) and may not be supported. Please consider updating.', 'wordpress-importer' ),
168
- $this->version,
169
- self::MAX_WXR_VERSION
170
- ) );
171
- }
172
-
173
- // Handled everything in this node, move on to the next
174
- $reader->next();
175
- break;
176
-
177
- case 'generator':
178
- $data->generator = $reader->readString();
179
- $reader->next();
180
- break;
181
-
182
- case 'title':
183
- $data->title = $reader->readString();
184
- $reader->next();
185
- break;
186
-
187
- case 'wp:base_site_url':
188
- $data->siteurl = $reader->readString();
189
- $reader->next();
190
- break;
191
-
192
- case 'wp:base_blog_url':
193
- $data->home = $reader->readString();
194
- $reader->next();
195
- break;
196
-
197
- case 'wp:author':
198
- $node = $reader->expand();
199
-
200
- $parsed = $this->parse_author_node( $node );
201
- if ( is_wp_error( $parsed ) ) {
202
- $this->log_error( $parsed );
203
-
204
- // Skip the rest of this post
205
- $reader->next();
206
- break;
207
- }
208
-
209
- $data->users[] = $parsed;
210
-
211
- // Handled everything in this node, move on to the next
212
- $reader->next();
213
- break;
214
-
215
- case 'item':
216
- $node = $reader->expand();
217
- $parsed = $this->parse_post_node( $node );
218
- if ( is_wp_error( $parsed ) ) {
219
- $this->log_error( $parsed );
220
-
221
- // Skip the rest of this post
222
- $reader->next();
223
- break;
224
- }
225
-
226
- if ( $parsed['data']['post_type'] === 'attachment' ) {
227
- $data->media_count++;
228
- } else {
229
- $data->post_count++;
230
- }
231
- $data->comment_count += count( $parsed['comments'] );
232
-
233
- // Handled everything in this node, move on to the next
234
- $reader->next();
235
- break;
236
-
237
- case 'wp:category':
238
- case 'wp:tag':
239
- case 'wp:term':
240
- $data->term_count++;
241
-
242
- // Handled everything in this node, move on to the next
243
- $reader->next();
244
- break;
245
- }// End switch().
246
- }// End while().
247
-
248
- $data->version = $this->version;
249
-
250
- return $data;
251
- }
252
-
253
- /**
254
- * The main controller for the actual import stage.
255
- *
256
- * @param string $file Path to the WXR file for importing
257
- */
258
- public function parse_authors( $file ) {
259
- // Let's run the actual importer now, woot
260
- $reader = $this->get_reader( $file );
261
- if ( is_wp_error( $reader ) ) {
262
- return $reader;
263
- }
264
-
265
- // Set the version to compatibility mode first
266
- $this->version = '1.0';
267
-
268
- // Start parsing!
269
- $authors = array();
270
- while ( $reader->read() ) {
271
- // Only deal with element opens
272
- if ( $reader->nodeType !== XMLReader::ELEMENT ) {
273
- continue;
274
- }
275
-
276
- switch ( $reader->name ) {
277
- case 'wp:wxr_version':
278
- // Upgrade to the correct version
279
- $this->version = $reader->readString();
280
-
281
- if ( version_compare( $this->version, self::MAX_WXR_VERSION, '>' ) ) {
282
- $this->logger->warning( sprintf(
283
- __( 'This WXR file (version %1$s) is newer than the importer (version %2$s) and may not be supported. Please consider updating.', 'wordpress-importer' ),
284
- $this->version,
285
- self::MAX_WXR_VERSION
286
- ) );
287
- }
288
-
289
- // Handled everything in this node, move on to the next
290
- $reader->next();
291
- break;
292
-
293
- case 'wp:author':
294
- $node = $reader->expand();
295
-
296
- $parsed = $this->parse_author_node( $node );
297
- if ( is_wp_error( $parsed ) ) {
298
- $this->log_error( $parsed );
299
-
300
- // Skip the rest of this post
301
- $reader->next();
302
- break;
303
- }
304
-
305
- $authors[] = $parsed;
306
-
307
- // Handled everything in this node, move on to the next
308
- $reader->next();
309
- break;
310
- }
311
- }// End while().
312
-
313
- return $authors;
314
- }
315
-
316
- /**
317
- * The main controller for the actual import stage.
318
- *
319
- * @param string $file Path to the WXR file for importing
320
- */
321
- public function import( $file ) {
322
- add_filter( 'import_post_meta_key', array( $this, 'is_valid_meta_key' ) );
323
- add_filter( 'http_request_timeout', array( &$this, 'bump_request_timeout' ) );
324
-
325
- $result = $this->import_start( $file );
326
- if ( is_wp_error( $result ) ) {
327
- return $result;
328
- }
329
-
330
- // Let's run the actual importer now, woot
331
- $reader = $this->get_reader( $file );
332
- if ( is_wp_error( $reader ) ) {
333
- return $reader;
334
- }
335
-
336
- // Set the version to compatibility mode first
337
- $this->version = '1.0';
338
-
339
- // Reset other variables
340
- $this->base_url = '';
341
-
342
- // Start parsing!
343
- while ( $reader->read() ) {
344
- // Only deal with element opens
345
- if ( $reader->nodeType !== XMLReader::ELEMENT ) {
346
- continue;
347
- }
348
-
349
- switch ( $reader->name ) {
350
- case 'wp:wxr_version':
351
- // Upgrade to the correct version
352
- $this->version = $reader->readString();
353
-
354
- if ( version_compare( $this->version, self::MAX_WXR_VERSION, '>' ) ) {
355
- $this->logger->warning( sprintf(
356
- __( 'This WXR file (version %1$s) is newer than the importer (version %2$s) and may not be supported. Please consider updating.', 'wordpress-importer' ),
357
- $this->version,
358
- self::MAX_WXR_VERSION
359
- ) );
360
- }
361
-
362
- // Handled everything in this node, move on to the next
363
- $reader->next();
364
- break;
365
-
366
- case 'wp:base_site_url':
367
- $this->base_url = $reader->readString();
368
-
369
- // Handled everything in this node, move on to the next
370
- $reader->next();
371
- break;
372
-
373
- case 'item':
374
- $node = $reader->expand();
375
- $parsed = $this->parse_post_node( $node );
376
- if ( is_wp_error( $parsed ) ) {
377
- $this->log_error( $parsed );
378
-
379
- // Skip the rest of this post
380
- $reader->next();
381
- break;
382
- }
383
-
384
- $this->process_post( $parsed['data'], $parsed['meta'], $parsed['comments'], $parsed['terms'] );
385
-
386
- // Handled everything in this node, move on to the next
387
- $reader->next();
388
- break;
389
-
390
- case 'wp:author':
391
- $node = $reader->expand();
392
-
393
- $parsed = $this->parse_author_node( $node );
394
- if ( is_wp_error( $parsed ) ) {
395
- $this->log_error( $parsed );
396
-
397
- // Skip the rest of this post
398
- $reader->next();
399
- break;
400
- }
401
-
402
- $status = $this->process_author( $parsed['data'], $parsed['meta'] );
403
- if ( is_wp_error( $status ) ) {
404
- $this->log_error( $status );
405
- }
406
-
407
- // Handled everything in this node, move on to the next
408
- $reader->next();
409
- break;
410
-
411
- case 'wp:category':
412
- $node = $reader->expand();
413
-
414
- $parsed = $this->parse_term_node( $node, 'category' );
415
- if ( is_wp_error( $parsed ) ) {
416
- $this->log_error( $parsed );
417
-
418
- // Skip the rest of this post
419
- $reader->next();
420
- break;
421
- }
422
-
423
- $status = $this->process_term( $parsed['data'], $parsed['meta'] );
424
-
425
- // Handled everything in this node, move on to the next
426
- $reader->next();
427
- break;
428
-
429
- case 'wp:tag':
430
- $node = $reader->expand();
431
-
432
- $parsed = $this->parse_term_node( $node, 'tag' );
433
- if ( is_wp_error( $parsed ) ) {
434
- $this->log_error( $parsed );
435
-
436
- // Skip the rest of this post
437
- $reader->next();
438
- break;
439
- }
440
-
441
- $status = $this->process_term( $parsed['data'], $parsed['meta'] );
442
-
443
- // Handled everything in this node, move on to the next
444
- $reader->next();
445
- break;
446
-
447
- case 'wp:term':
448
- $node = $reader->expand();
449
-
450
- $parsed = $this->parse_term_node( $node );
451
- if ( is_wp_error( $parsed ) ) {
452
- $this->log_error( $parsed );
453
-
454
- // Skip the rest of this post
455
- $reader->next();
456
- break;
457
- }
458
-
459
- $status = $this->process_term( $parsed['data'], $parsed['meta'] );
460
-
461
- // Handled everything in this node, move on to the next
462
- $reader->next();
463
- break;
464
-
465
- default:
466
- // Skip this node, probably handled by something already
467
- break;
468
- }// End switch().
469
- }// End while().
470
-
471
- // Now that we've done the main processing, do any required
472
- // post-processing and remapping.
473
- $this->post_process();
474
-
475
- if ( $this->options['aggressive_url_search'] ) {
476
- $this->replace_attachment_urls_in_content();
477
- }
478
- // $this->remap_featured_images();
479
- $this->import_end();
480
- }
481
-
482
- /**
483
- * Log an error instance to the logger.
484
- *
485
- * @param WP_Error $error Error instance to log.
486
- */
487
- protected function log_error( WP_Error $error ) {
488
- $this->logger->warning( $error->get_error_message() );
489
-
490
- // Log the data as debug info too
491
- $data = $error->get_error_data();
492
- if ( ! empty( $data ) ) {
493
- $this->logger->debug( var_export( $data, true ) );
494
- }
495
- }
496
-
497
- /**
498
- * Parses the WXR file and prepares us for the task of processing parsed data
499
- *
500
- * @param string $file Path to the WXR file for importing
501
- */
502
- protected function import_start( $file ) {
503
- if ( ! is_file( $file ) ) {
504
- return new WP_Error( 'wxr_importer.file_missing', __( 'The file does not exist, please try again.', 'wordpress-importer' ) );
505
- }
506
-
507
- // Suspend bunches of stuff in WP core
508
- wp_defer_term_counting( true );
509
- wp_defer_comment_counting( true );
510
- wp_suspend_cache_invalidation( true );
511
-
512
- // Prefill exists calls if told to
513
- if ( $this->options['prefill_existing_posts'] ) {
514
- $this->prefill_existing_posts();
515
- }
516
- if ( $this->options['prefill_existing_comments'] ) {
517
- $this->prefill_existing_comments();
518
- }
519
- if ( $this->options['prefill_existing_terms'] ) {
520
- $this->prefill_existing_terms();
521
- }
522
-
523
- /**
524
- * Begin the import.
525
- *
526
- * Fires before the import process has begun. If you need to suspend
527
- * caching or heavy processing on hooks, do so here.
528
- */
529
- do_action( 'import_start' );
530
- }
531
-
532
- /**
533
- * Performs post-import cleanup of files and the cache
534
- */
535
- protected function import_end() {
536
- // Re-enable stuff in core
537
- wp_suspend_cache_invalidation( false );
538
- wp_cache_flush();
539
- foreach ( get_taxonomies() as $tax ) {
540
- delete_option( "{$tax}_children" );
541
- _get_term_hierarchy( $tax );
542
- }
543
-
544
- wp_defer_term_counting( false );
545
- wp_defer_comment_counting( false );
546
-
547
- /**
548
- * Complete the import.
549
- *
550
- * Fires after the import process has finished. If you need to update
551
- * your cache or re-enable processing, do so here.
552
- */
553
- do_action( 'import_end' );
554
- }
555
-
556
- /**
557
- * Set the user mapping.
558
- *
559
- * @param array $mapping List of map arrays (containing `old_slug`, `old_id`, `new_id`)
560
- */
561
- public function set_user_mapping( $mapping ) {
562
- foreach ( $mapping as $map ) {
563
- if ( empty( $map['old_slug'] ) || empty( $map['old_id'] ) || empty( $map['new_id'] ) ) {
564
- $this->logger->warning( __( 'Invalid author mapping', 'wordpress-importer' ) );
565
- $this->logger->debug( var_export( $map, true ) );
566
- continue;
567
- }
568
-
569
- $old_slug = $map['old_slug'];
570
- $old_id = $map['old_id'];
571
- $new_id = $map['new_id'];
572
-
573
- $this->mapping['user'][ $old_id ] = $new_id;
574
- $this->mapping['user_slug'][ $old_slug ] = $new_id;
575
- }
576
- }
577
-
578
- /**
579
- * Set the user slug overrides.
580
- *
581
- * Allows overriding the slug in the import with a custom/renamed version.
582
- *
583
- * @param string[] $overrides Map of old slug to new slug.
584
- */
585
- public function set_user_slug_overrides( $overrides ) {
586
- foreach ( $overrides as $original => $renamed ) {
587
- $this->user_slug_override[ $original ] = $renamed;
588
- }
589
- }
590
-
591
- /**
592
- * Parse a post node into post data.
593
- *
594
- * @param DOMElement $node Parent node of post data (typically `item`).
595
- * @return array|WP_Error Post data array on success, error otherwise.
596
- */
597
- protected function parse_post_node( $node ) {
598
- $data = array();
599
- $meta = array();
600
- $comments = array();
601
- $terms = array();
602
-
603
- foreach ( $node->childNodes as $child ) {
604
- // We only care about child elements
605
- if ( $child->nodeType !== XML_ELEMENT_NODE ) {
606
- continue;
607
- }
608
-
609
- switch ( $child->tagName ) {
610
- case 'wp:post_type':
611
- $data['post_type'] = $child->textContent;
612
- break;
613
-
614
- case 'title':
615
- $data['post_title'] = $child->textContent;
616
- break;
617
-
618
- case 'guid':
619
- $data['guid'] = $child->textContent;
620
- break;
621
-
622
- case 'dc:creator':
623
- $data['post_author'] = $child->textContent;
624
- break;
625
-
626
- case 'content:encoded':
627
- $data['post_content'] = $child->textContent;
628
- break;
629
-
630
- case 'excerpt:encoded':
631
- $data['post_excerpt'] = $child->textContent;
632
- break;
633
-
634
- case 'wp:post_id':
635
- $data['post_id'] = $child->textContent;
636
- break;
637
-
638
- case 'wp:post_date':
639
- $data['post_date'] = $child->textContent;
640
- break;
641
-
642
- case 'wp:post_date_gmt':
643
- $data['post_date_gmt'] = $child->textContent;
644
- break;
645
-
646
- case 'wp:comment_status':
647
- $data['comment_status'] = $child->textContent;
648
- break;
649
-
650
- case 'wp:ping_status':
651
- $data['ping_status'] = $child->textContent;
652
- break;
653
-
654
- case 'wp:post_name':
655
- $data['post_name'] = $child->textContent;
656
- break;
657
-
658
- case 'wp:status':
659
- $data['post_status'] = $child->textContent;
660
-
661
- if ( $data['post_status'] === 'auto-draft' ) {
662
- // Bail now
663
- return new WP_Error(
664
- 'wxr_importer.post.cannot_import_draft',
665
- __( 'Cannot import auto-draft posts' ),
666
- $data
667
- );
668
- }
669
- break;
670
-
671
- case 'wp:post_parent':
672
- $data['post_parent'] = $child->textContent;
673
- break;
674
-
675
- case 'wp:menu_order':
676
- $data['menu_order'] = $child->textContent;
677
- break;
678
-
679
- case 'wp:post_password':
680
- $data['post_password'] = $child->textContent;
681
- break;
682
-
683
- case 'wp:is_sticky':
684
- $data['is_sticky'] = $child->textContent;
685
- break;
686
-
687
- case 'wp:attachment_url':
688
- $data['attachment_url'] = $child->textContent;
689
- break;
690
-
691
- case 'wp:postmeta':
692
- $meta_item = $this->parse_meta_node( $child );
693
- if ( ! empty( $meta_item ) ) {
694
- $meta[] = $meta_item;
695
- }
696
- break;
697
-
698
- case 'wp:comment':
699
- $comment_item = $this->parse_comment_node( $child );
700
- if ( ! empty( $comment_item ) ) {
701
- $comments[] = $comment_item;
702
- }
703
- break;
704
-
705
- case 'category':
706
- $term_item = $this->parse_category_node( $child );
707
- if ( ! empty( $term_item ) ) {
708
- $terms[] = $term_item;
709
- }
710
- break;
711
- }// End switch().
712
- }// End foreach().
713
-
714
- return compact( 'data', 'meta', 'comments', 'terms' );
715
- }
716
-
717
- /**
718
- * Create new posts based on import information
719
- *
720
- * Posts marked as having a parent which doesn't exist will become top level items.
721
- * Doesn't create a new post if: the post type doesn't exist, the given post ID
722
- * is already noted as imported or a post with the same title and date already exists.
723
- * Note that new/updated terms, comments and meta are imported for the last of the above.
724
- */
725
- protected function process_post( $data, $meta, $comments, $terms ) {
726
- /**
727
- * Pre-process post data.
728
- *
729
- * @param array $data Post data. (Return empty to skip.)
730
- * @param array $meta Meta data.
731
- * @param array $comments Comments on the post.
732
- * @param array $terms Terms on the post.
733
- */
734
- $data = apply_filters( 'wxr_importer.pre_process.post', $data, $meta, $comments, $terms );
735
- if ( empty( $data ) ) {
736
- return false;
737
- }
738
-
739
- $original_id = isset( $data['post_id'] ) ? (int) $data['post_id'] : 0;
740
- $parent_id = isset( $data['post_parent'] ) ? (int) $data['post_parent'] : 0;
741
- $author_id = isset( $data['post_author'] ) ? (int) $data['post_author'] : 0;
742
-
743
- // Have we already processed this?
744
- if ( isset( $this->mapping['post'][ $original_id ] ) ) {
745
- return;
746
- }
747
-
748
- $post_type_object = get_post_type_object( $data['post_type'] );
749
-
750
- // Is this type even valid?
751
- if ( ! $post_type_object ) {
752
- $this->logger->warning( sprintf(
753
- __( 'Failed to import "%1$s": Invalid post type %2$s', 'wordpress-importer' ),
754
- $data['post_title'],
755
- $data['post_type']
756
- ) );
757
- return false;
758
- }
759
-
760
- $post_exists = $this->post_exists( $data );
761
- if ( $post_exists ) {
762
- $this->logger->info( sprintf(
763
- __( '%1$s "%2$s" already exists.', 'wordpress-importer' ),
764
- $post_type_object->labels->singular_name,
765
- $data['post_title']
766
- ) );
767
-
768
- /**
769
- * Post processing already imported.
770
- *
771
- * @param array $data Raw data imported for the post.
772
- */
773
- do_action( 'wxr_importer.process_already_imported.post', $data );
774
-
775
- // Even though this post already exists, new comments might need importing
776
- $this->process_comments( $comments, $original_id, $data, $post_exists );
777
-
778
- return false;
779
- }
780
-
781
- // Map the parent post, or mark it as one we need to fix
782
- $requires_remapping = false;
783
- if ( $parent_id ) {
784
- if ( isset( $this->mapping['post'][ $parent_id ] ) ) {
785
- $data['post_parent'] = $this->mapping['post'][ $parent_id ];
786
- } else {
787
- $meta[] = array(
788
- 'key' => '_wxr_import_parent',
789
- 'value' => $parent_id,
790
- );
791
- $requires_remapping = true;
792
-
793
- $data['post_parent'] = 0;
794
- }
795
- }
796
-
797
- // Map the author, or mark it as one we need to fix
798
- $author = sanitize_user( $data['post_author'], true );
799
- if ( empty( $author ) ) {
800
- // Missing or invalid author, use default if available.
801
- $data['post_author'] = $this->options['default_author'];
802
- } elseif ( isset( $this->mapping['user_slug'][ $author ] ) ) {
803
- $data['post_author'] = $this->mapping['user_slug'][ $author ];
804
- } else {
805
- $meta[] = array(
806
- 'key' => '_wxr_import_user_slug',
807
- 'value' => $author,
808
- );
809
- $requires_remapping = true;
810
-
811
- $data['post_author'] = (int) get_current_user_id();
812
- }
813
-
814
- // Does the post look like it contains attachment images?
815
- if ( preg_match( self::REGEX_HAS_ATTACHMENT_REFS, $data['post_content'] ) ) {
816
- $meta[] = array(
817
- 'key' => '_wxr_import_has_attachment_refs',
818
- 'value' => true,
819
- );
820
- $requires_remapping = true;
821
- }
822
-
823
- // Whitelist to just the keys we allow
824
- $postdata = array(
825
- 'import_id' => $data['post_id'],
826
- );
827
- $allowed = array(
828
- 'post_author' => true,
829
- 'post_date' => true,
830
- 'post_date_gmt' => true,
831
- 'post_content' => true,
832
- 'post_excerpt' => true,
833
- 'post_title' => true,
834
- 'post_status' => true,
835
- 'post_name' => true,
836
- 'comment_status' => true,
837
- 'ping_status' => true,
838
- 'guid' => true,
839
- 'post_parent' => true,
840
- 'menu_order' => true,
841
- 'post_type' => true,
842
- 'post_password' => true,
843
- );
844
- foreach ( $data as $key => $value ) {
845
- if ( ! isset( $allowed[ $key ] ) ) {
846
- continue;
847
- }
848
-
849
- $postdata[ $key ] = $data[ $key ];
850
- }
851
-
852
- $postdata = apply_filters( 'wp_import_post_data_processed', $postdata, $data );
853
-
854
- if ( 'attachment' === $postdata['post_type'] ) {
855
- if ( ! $this->options['fetch_attachments'] ) {
856
- $this->logger->notice( sprintf(
857
- __( 'Skipping attachment "%s", fetching attachments disabled' ),
858
- $data['post_title']
859
- ) );
860
- /**
861
- * Post processing skipped.
862
- *
863
- * @param array $data Raw data imported for the post.
864
- * @param array $meta Raw meta data, already processed by {@see process_post_meta}.
865
- */
866
- do_action( 'wxr_importer.process_skipped.post', $data, $meta );
867
- return false;
868
- }
869
- $remote_url = ! empty( $data['attachment_url'] ) ? $data['attachment_url'] : $data['guid'];
870
- $post_id = $this->process_attachment( $postdata, $meta, $remote_url );
871
- } else {
872
- $post_id = wp_insert_post( $postdata, true );
873
- do_action( 'wp_import_insert_post', $post_id, $original_id, $postdata, $data );
874
- }
875
-
876
- if ( is_wp_error( $post_id ) ) {
877
- $this->logger->error( sprintf(
878
- __( 'Failed to import "%1$s" (%2$s)', 'wordpress-importer' ),
879
- $data['post_title'],
880
- $post_type_object->labels->singular_name
881
- ) );
882
- $this->logger->debug( $post_id->get_error_message() );
883
-
884
- /**
885
- * Post processing failed.
886
- *
887
- * @param WP_Error $post_id Error object.
888
- * @param array $data Raw data imported for the post.
889
- * @param array $meta Raw meta data, already processed by {@see process_post_meta}.
890
- * @param array $comments Raw comment data, already processed by {@see process_comments}.
891
- * @param array $terms Raw term data, already processed.
892
- */
893
- do_action( 'wxr_importer.process_failed.post', $post_id, $data, $meta, $comments, $terms );
894
- return false;
895
- }
896
-
897
- // Ensure stickiness is handled correctly too
898
- if ( $data['is_sticky'] === '1' ) {
899
- stick_post( $post_id );
900
- }
901
-
902
- // map pre-import ID to local ID
903
- $this->mapping['post'][ $original_id ] = (int) $post_id;
904
- if ( $requires_remapping ) {
905
- $this->requires_remapping['post'][ $post_id ] = true;
906
- }
907
- $this->mark_post_exists( $data, $post_id );
908
-
909
- $this->logger->info( sprintf(
910
- __( 'Imported "%1$s" (%2$s)', 'wordpress-importer' ),
911
- $data['post_title'],
912
- $post_type_object->labels->singular_name
913
- ) );
914
- $this->logger->debug( sprintf(
915
- __( 'Post %1$d remapped to %2$d', 'wordpress-importer' ),
916
- $original_id,
917
- $post_id
918
- ) );
919
-
920
- // Handle the terms too
921
- $terms = apply_filters( 'wp_import_post_terms', $terms, $post_id, $data );
922
-
923
- if ( ! empty( $terms ) ) {
924
- $term_ids = array();
925
- foreach ( $terms as $term ) {
926
- $taxonomy = $term['taxonomy'];
927
- $key = sha1( $taxonomy . ':' . $term['slug'] );
928
-
929
- if ( isset( $this->mapping['term'][ $key ] ) ) {
930
- $term_ids[ $taxonomy ][] = (int) $this->mapping['term'][ $key ];
931
- } else {
932
- $meta[] = array(
933
- 'key' => '_wxr_import_term',
934
- 'value' => $term,
935
- );
936
- $requires_remapping = true;
937
- }
938
- }
939
-
940
- foreach ( $term_ids as $tax => $ids ) {
941
- $tt_ids = wp_set_post_terms( $post_id, $ids, $tax );
942
- do_action( 'wp_import_set_post_terms', $tt_ids, $ids, $tax, $post_id, $data );
943
- }
944
- }
945
-
946
- $this->process_comments( $comments, $post_id, $data );
947
- $this->process_post_meta( $meta, $post_id, $data );
948
-
949
- if ( 'nav_menu_item' === $data['post_type'] ) {
950
- $this->process_menu_item_meta( $post_id, $data, $meta );
951
- }
952
-
953
- /**
954
- * Post processing completed.
955
- *
956
- * @param int $post_id New post ID.
957
- * @param array $data Raw data imported for the post.
958
- * @param array $meta Raw meta data, already processed by {@see process_post_meta}.
959
- * @param array $comments Raw comment data, already processed by {@see process_comments}.
960
- * @param array $terms Raw term data, already processed.
961
- */
962
- do_action( 'wxr_importer.processed.post', $post_id, $data, $meta, $comments, $terms );
963
- }
964
-
965
- /**
966
- * Attempt to create a new menu item from import data
967
- *
968
- * Fails for draft, orphaned menu items and those without an associated nav_menu
969
- * or an invalid nav_menu term. If the post type or term object which the menu item
970
- * represents doesn't exist then the menu item will not be imported (waits until the
971
- * end of the import to retry again before discarding).
972
- *
973
- * @param array $item Menu item details from WXR file
974
- */
975
- protected function process_menu_item_meta( $post_id, $data, $meta ) {
976
-
977
- $item_type = get_post_meta( $post_id, '_menu_item_type', true );
978
- $original_object_id = get_post_meta( $post_id, '_menu_item_object_id', true );
979
- $object_id = null;
980
-
981
- $this->logger->debug( sprintf( 'Processing menu item %s', $item_type ) );
982
-
983
- $requires_remapping = false;
984
- switch ( $item_type ) {
985
- case 'taxonomy':
986
- if ( isset( $this->mapping['term_id'][ $original_object_id ] ) ) {
987
- $object_id = $this->mapping['term_id'][ $original_object_id ];
988
- } else {
989
- add_post_meta( $post_id, '_wxr_import_menu_item', wp_slash( $original_object_id ) );
990
- $requires_remapping = true;
991
- }
992
- break;
993
-
994
- case 'post_type':
995
- if ( isset( $this->mapping['post'][ $original_object_id ] ) ) {
996
- $object_id = $this->mapping['post'][ $original_object_id ];
997
- } else {
998
- add_post_meta( $post_id, '_wxr_import_menu_item', wp_slash( $original_object_id ) );
999
- $requires_remapping = true;
1000
- }
1001
- break;
1002
-
1003
- case 'custom':
1004
- // Custom refers to itself, wonderfully easy.
1005
- $object_id = $post_id;
1006
- break;
1007
-
1008
- default:
1009
- // associated object is missing or not imported yet, we'll retry later
1010
- $this->missing_menu_items[] = $item;
1011
- $this->logger->debug( 'Unknown menu item type' );
1012
- break;
1013
- }
1014
-
1015
- if ( $requires_remapping ) {
1016
- $this->requires_remapping['post'][ $post_id ] = true;
1017
- }
1018
-
1019
- if ( empty( $object_id ) ) {
1020
- // Nothing needed here.
1021
- return;
1022
- }
1023
-
1024
- $this->logger->debug( sprintf( 'Menu item %d mapped to %d', $original_object_id, $object_id ) );
1025
- update_post_meta( $post_id, '_menu_item_object_id', wp_slash( $object_id ) );
1026
- }
1027
-
1028
- /**
1029
- * If fetching attachments is enabled then attempt to create a new attachment
1030
- *
1031
- * @param array $post Attachment post details from WXR
1032
- * @param string $url URL to fetch attachment from
1033
- * @return int|WP_Error Post ID on success, WP_Error otherwise
1034
- */
1035
- protected function process_attachment( $post, $meta, $remote_url ) {
1036
- // try to use _wp_attached file for upload folder placement to ensure the same location as the export site
1037
- // e.g. location is 2003/05/image.jpg but the attachment post_date is 2010/09, see media_handle_upload()
1038
- $post['upload_date'] = $post['post_date'];
1039
- foreach ( $meta as $meta_item ) {
1040
- if ( $meta_item['key'] !== '_wp_attached_file' ) {
1041
- continue;
1042
- }
1043
-
1044
- if ( preg_match( '%^[0-9]{4}/[0-9]{2}%', $meta_item['value'], $matches ) ) {
1045
- $post['upload_date'] = $matches[0];
1046
- }
1047
- break;
1048
- }
1049
-
1050
- // if the URL is absolute, but does not contain address, then upload it assuming base_site_url
1051
- if ( preg_match( '|^/[\w\W]+$|', $remote_url ) ) {
1052
- $remote_url = rtrim( $this->base_url, '/' ) . $remote_url;
1053
- }
1054
-
1055
- $upload = $this->fetch_remote_file( $remote_url, $post );
1056
- if ( is_wp_error( $upload ) ) {
1057
- return $upload;
1058
- }
1059
-
1060
- $info = wp_check_filetype( $upload['file'] );
1061
- if ( ! $info ) {
1062
- return new WP_Error( 'attachment_processing_error', __( 'Invalid file type', 'wordpress-importer' ) );
1063
- }
1064
-
1065
- $post['post_mime_type'] = $info['type'];
1066
-
1067
- // WP really likes using the GUID for display. Allow updating it.
1068
- // See https://core.trac.wordpress.org/ticket/33386
1069
- if ( $this->options['update_attachment_guids'] ) {
1070
- $post['guid'] = $upload['url'];
1071
- }
1072
-
1073
- // as per wp-admin/includes/upload.php
1074
- $post_id = wp_insert_attachment( $post, $upload['file'] );
1075
- if ( is_wp_error( $post_id ) ) {
1076
- return $post_id;
1077
- }
1078
-
1079
- $attachment_metadata = wp_generate_attachment_metadata( $post_id, $upload['file'] );
1080
- wp_update_attachment_metadata( $post_id, $attachment_metadata );
1081
-
1082
- // Map this image URL later if we need to
1083
- $this->url_remap[ $remote_url ] = $upload['url'];
1084
-
1085
- // If we have a HTTPS URL, ensure the HTTP URL gets replaced too
1086
- if ( substr( $remote_url, 0, 8 ) === 'https://' ) {
1087
- $insecure_url = 'http' . substr( $remote_url, 5 );
1088
- $this->url_remap[ $insecure_url ] = $upload['url'];
1089
- }
1090
-
1091
- if ( $this->options['aggressive_url_search'] ) {
1092
- // remap resized image URLs, works by stripping the extension and remapping the URL stub.
1093
- /*
1094
- if ( preg_match( '!^image/!', $info['type'] ) ) {
1095
- $parts = pathinfo( $remote_url );
1096
- $name = basename( $parts['basename'], ".{$parts['extension']}" ); // PATHINFO_FILENAME in PHP 5.2
1097
-
1098
- $parts_new = pathinfo( $upload['url'] );
1099
- $name_new = basename( $parts_new['basename'], ".{$parts_new['extension']}" );
1100
-
1101
- $this->url_remap[$parts['dirname'] . '/' . $name] = $parts_new['dirname'] . '/' . $name_new;
1102
- }*/
1103
- }
1104
-
1105
- return $post_id;
1106
- }
1107
-
1108
- /**
1109
- * Parse a meta node into meta data.
1110
- *
1111
- * @param DOMElement $node Parent node of meta data (typically `wp:postmeta` or `wp:commentmeta`).
1112
- * @return array|null Meta data array on success, or null on error.
1113
- */
1114
- protected function parse_meta_node( $node ) {
1115
- foreach ( $node->childNodes as $child ) {
1116
- // We only care about child elements
1117
- if ( $child->nodeType !== XML_ELEMENT_NODE ) {
1118
- continue;
1119
- }
1120
-
1121
- switch ( $child->tagName ) {
1122
- case 'wp:meta_key':
1123
- $key = $child->textContent;
1124
- break;
1125
-
1126
- case 'wp:meta_value':
1127
- $value = $child->textContent;
1128
- break;
1129
- }
1130
- }
1131
-
1132
- if ( empty( $key ) || empty( $value ) ) {
1133
- return null;
1134
- }
1135
-
1136
- return compact( 'key', 'value' );
1137
- }
1138
-
1139
- /**
1140
- * Process and import post meta items.
1141
- *
1142
- * @param array $meta List of meta data arrays
1143
- * @param int $post_id Post to associate with
1144
- * @param array $post Post data
1145
- * @return int|WP_Error Number of meta items imported on success, error otherwise.
1146
- */
1147
- protected function process_post_meta( $meta, $post_id, $post ) {
1148
- if ( empty( $meta ) ) {
1149
- return true;
1150
- }
1151
-
1152
- foreach ( $meta as $meta_item ) {
1153
- /**
1154
- * Pre-process post meta data.
1155
- *
1156
- * @param array $meta_item Meta data. (Return empty to skip.)
1157
- * @param int $post_id Post the meta is attached to.
1158
- */
1159
- $meta_item = apply_filters( 'wxr_importer.pre_process.post_meta', $meta_item, $post_id );
1160
- if ( empty( $meta_item ) ) {
1161
- return false;
1162
- }
1163
-
1164
- $key = apply_filters( 'import_post_meta_key', $meta_item['key'], $post_id, $post );
1165
- $value = false;
1166
-
1167
- if ( '_edit_last' === $key ) {
1168
- $value = intval( $meta_item['value'] );
1169
- if ( ! isset( $this->mapping['user'][ $value ] ) ) {
1170
- // Skip!
1171
- continue;
1172
- }
1173
-
1174
- $value = $this->mapping['user'][ $value ];
1175
- }
1176
-
1177
- if ( $key ) {
1178
- // export gets meta straight from the DB so could have a serialized string
1179
- if ( ! $value ) {
1180
- $value = maybe_unserialize( $meta_item['value'] );
1181
- }
1182
-
1183
- add_post_meta( $post_id, $key, $value );
1184
- do_action( 'import_post_meta', $post_id, $key, $value );
1185
-
1186
- // if the post has a featured image, take note of this in case of remap
1187
- if ( '_thumbnail_id' === $key ) {
1188
- $this->featured_images[ $post_id ] = (int) $value;
1189
- }
1190
- }
1191
- }// End foreach().
1192
-
1193
- return true;
1194
- }
1195
-
1196
- /**
1197
- * Parse a comment node into comment data.
1198
- *
1199
- * @param DOMElement $node Parent node of comment data (typically `wp:comment`).
1200
- * @return array Comment data array.
1201
- */
1202
- protected function parse_comment_node( $node ) {
1203
- $data = array(
1204
- 'commentmeta' => array(),
1205
- );
1206
-
1207
- foreach ( $node->childNodes as $child ) {
1208
- // We only care about child elements
1209
- if ( $child->nodeType !== XML_ELEMENT_NODE ) {
1210
- continue;
1211
- }
1212
-
1213
- switch ( $child->tagName ) {
1214
- case 'wp:comment_id':
1215
- $data['comment_id'] = $child->textContent;
1216
- break;
1217
- case 'wp:comment_author':
1218
- $data['comment_author'] = $child->textContent;
1219
- break;
1220
-
1221
- case 'wp:comment_author_email':
1222
- $data['comment_author_email'] = $child->textContent;
1223
- break;
1224
-
1225
- case 'wp:comment_author_IP':
1226
- $data['comment_author_IP'] = $child->textContent;
1227
- break;
1228
-
1229
- case 'wp:comment_author_url':
1230
- $data['comment_author_url'] = $child->textContent;
1231
- break;
1232
-
1233
- case 'wp:comment_user_id':
1234
- $data['comment_user_id'] = $child->textContent;
1235
- break;
1236
-
1237
- case 'wp:comment_date':
1238
- $data['comment_date'] = $child->textContent;
1239
- break;
1240
-
1241
- case 'wp:comment_date_gmt':
1242
- $data['comment_date_gmt'] = $child->textContent;
1243
- break;
1244
-
1245
- case 'wp:comment_content':
1246
- $data['comment_content'] = $child->textContent;
1247
- break;
1248
-
1249
- case 'wp:comment_approved':
1250
- $data['comment_approved'] = $child->textContent;
1251
- break;
1252
-
1253
- case 'wp:comment_type':
1254
- $data['comment_type'] = $child->textContent;
1255
- break;
1256
-
1257
- case 'wp:comment_parent':
1258
- $data['comment_parent'] = $child->textContent;
1259
- break;
1260
-
1261
- case 'wp:commentmeta':
1262
- $meta_item = $this->parse_meta_node( $child );
1263
- if ( ! empty( $meta_item ) ) {
1264
- $data['commentmeta'][] = $meta_item;
1265
- }
1266
- break;
1267
- }// End switch().
1268
- }// End foreach().
1269
-
1270
- return $data;
1271
- }
1272
-
1273
- /**
1274
- * Process and import comment data.
1275
- *
1276
- * @param array $comments List of comment data arrays.
1277
- * @param int $post_id Post to associate with.
1278
- * @param array $post Post data.
1279
- * @return int|WP_Error Number of comments imported on success, error otherwise.
1280
- */
1281
- protected function process_comments( $comments, $post_id, $post, $post_exists = false ) {
1282
-
1283
- $comments = apply_filters( 'wp_import_post_comments', $comments, $post_id, $post );
1284
- if ( empty( $comments ) ) {
1285
- return 0;
1286
- }
1287
-
1288
- $num_comments = 0;
1289
-
1290
- // Sort by ID to avoid excessive remapping later
1291
- usort( $comments, array( $this, 'sort_comments_by_id' ) );
1292
-
1293
- foreach ( $comments as $key => $comment ) {
1294
- /**
1295
- * Pre-process comment data
1296
- *
1297
- * @param array $comment Comment data. (Return empty to skip.)
1298
- * @param int $post_id Post the comment is attached to.
1299
- */
1300
- $comment = apply_filters( 'wxr_importer.pre_process.comment', $comment, $post_id );
1301
- if ( empty( $comment ) ) {
1302
- return false;
1303
- }
1304
-
1305
- $original_id = isset( $comment['comment_id'] ) ? (int) $comment['comment_id'] : 0;
1306
- $parent_id = isset( $comment['comment_parent'] ) ? (int) $comment['comment_parent'] : 0;
1307
- $author_id = isset( $comment['comment_user_id'] ) ? (int) $comment['comment_user_id'] : 0;
1308
-
1309
- // if this is a new post we can skip the comment_exists() check
1310
- // TODO: Check comment_exists for performance
1311
- if ( $post_exists ) {
1312
- $existing = $this->comment_exists( $comment );
1313
- if ( $existing ) {
1314
-
1315
- /**
1316
- * Comment processing already imported.
1317
- *
1318
- * @param array $comment Raw data imported for the comment.
1319
- */
1320
- do_action( 'wxr_importer.process_already_imported.comment', $comment );
1321
-
1322
- $this->mapping['comment'][ $original_id ] = $existing;
1323
- continue;
1324
- }
1325
- }
1326
-
1327
- // Remove meta from the main array
1328
- $meta = isset( $comment['commentmeta'] ) ? $comment['commentmeta'] : array();
1329
- unset( $comment['commentmeta'] );
1330
-
1331
- // Map the parent comment, or mark it as one we need to fix
1332
- $requires_remapping = false;
1333
- if ( $parent_id ) {
1334
- if ( isset( $this->mapping['comment'][ $parent_id ] ) ) {
1335
- $comment['comment_parent'] = $this->mapping['comment'][ $parent_id ];
1336
- } else {
1337
- // Prepare for remapping later
1338
- $meta[] = array(
1339
- 'key' => '_wxr_import_parent',
1340
- 'value' => $parent_id,
1341
- );
1342
- $requires_remapping = true;
1343
-
1344
- // Wipe the parent for now
1345
- $comment['comment_parent'] = 0;
1346
- }
1347
- }
1348
-
1349
- // Map the author, or mark it as one we need to fix
1350
- if ( $author_id ) {
1351
- if ( isset( $this->mapping['user'][ $author_id ] ) ) {
1352
- $comment['user_id'] = $this->mapping['user'][ $author_id ];
1353
- } else {
1354
- // Prepare for remapping later
1355
- $meta[] = array(
1356
- 'key' => '_wxr_import_user',
1357
- 'value' => $author_id,
1358
- );
1359
- $requires_remapping = true;
1360
-
1361
- // Wipe the user for now
1362
- $comment['user_id'] = 0;
1363
- }
1364
- }
1365
-
1366
- // Run standard core filters
1367
- $comment['comment_post_ID'] = $post_id;
1368
- $comment = wp_filter_comment( $comment );
1369
-
1370
- // wp_insert_comment expects slashed data
1371
- $comment_id = wp_insert_comment( wp_slash( $comment ) );
1372
- $this->mapping['comment'][ $original_id ] = $comment_id;
1373
- if ( $requires_remapping ) {
1374
- $this->requires_remapping['comment'][ $comment_id ] = true;
1375
- }
1376
- $this->mark_comment_exists( $comment, $comment_id );
1377
-
1378
- /**
1379
- * Comment has been imported.
1380
- *
1381
- * @param int $comment_id New comment ID
1382
- * @param array $comment Comment inserted (`comment_id` item refers to the original ID)
1383
- * @param int $post_id Post parent of the comment
1384
- * @param array $post Post data
1385
- */
1386
- do_action( 'wp_import_insert_comment', $comment_id, $comment, $post_id, $post );
1387
-
1388
- // Process the meta items
1389
- foreach ( $meta as $meta_item ) {
1390
- $value = maybe_unserialize( $meta_item['value'] );
1391
- add_comment_meta( $comment_id, wp_slash( $meta_item['key'] ), wp_slash( $value ) );
1392
- }
1393
-
1394
- /**
1395
- * Post processing completed.
1396
- *
1397
- * @param int $post_id New post ID.
1398
- * @param array $comment Raw data imported for the comment.
1399
- * @param array $meta Raw meta data, already processed by {@see process_post_meta}.
1400
- * @param array $post_id Parent post ID.
1401
- */
1402
- do_action( 'wxr_importer.processed.comment', $comment_id, $comment, $meta, $post_id );
1403
-
1404
- $num_comments++;
1405
- }// End foreach().
1406
-
1407
- return $num_comments;
1408
- }
1409
-
1410
- protected function parse_category_node( $node ) {
1411
- $data = array(
1412
- // Default taxonomy to "category", since this is a `<category>` tag
1413
- 'taxonomy' => 'category',
1414
- );
1415
- $meta = array();
1416
-
1417
- if ( $node->hasAttribute( 'domain' ) ) {
1418
- $data['taxonomy'] = $node->getAttribute( 'domain' );
1419
- }
1420
- if ( $node->hasAttribute( 'nicename' ) ) {
1421
- $data['slug'] = $node->getAttribute( 'nicename' );
1422
- }
1423
-
1424
- $data['name'] = $node->textContent;
1425
-
1426
- if ( empty( $data['slug'] ) ) {
1427
- return null;
1428
- }
1429
-
1430
- // Just for extra compatibility
1431
- if ( $data['taxonomy'] === 'tag' ) {
1432
- $data['taxonomy'] = 'post_tag';
1433
- }
1434
-
1435
- return $data;
1436
- }
1437
-
1438
- /**
1439
- * Callback for `usort` to sort comments by ID
1440
- *
1441
- * @param array $a Comment data for the first comment
1442
- * @param array $b Comment data for the second comment
1443
- * @return int
1444
- */
1445
- public static function sort_comments_by_id( $a, $b ) {
1446
- if ( empty( $a['comment_id'] ) ) {
1447
- return 1;
1448
- }
1449
-
1450
- if ( empty( $b['comment_id'] ) ) {
1451
- return -1;
1452
- }
1453
-
1454
- return $a['comment_id'] - $b['comment_id'];
1455
- }
1456
-
1457
- protected function parse_author_node( $node ) {
1458
- $data = array();
1459
- $meta = array();
1460
- foreach ( $node->childNodes as $child ) {
1461
- // We only care about child elements
1462
- if ( $child->nodeType !== XML_ELEMENT_NODE ) {
1463
- continue;
1464
- }
1465
-
1466
- switch ( $child->tagName ) {
1467
- case 'wp:author_login':
1468
- $data['user_login'] = $child->textContent;
1469
- break;
1470
-
1471
- case 'wp:author_id':
1472
- $data['ID'] = $child->textContent;
1473
- break;
1474
-
1475
- case 'wp:author_email':
1476
- $data['user_email'] = $child->textContent;
1477
- break;
1478
-
1479
- case 'wp:author_display_name':
1480
- $data['display_name'] = $child->textContent;
1481
- break;
1482
-
1483
- case 'wp:author_first_name':
1484
- $data['first_name'] = $child->textContent;
1485
- break;
1486
-
1487
- case 'wp:author_last_name':
1488
- $data['last_name'] = $child->textContent;
1489
- break;
1490
- }
1491
- }
1492
-
1493
- return compact( 'data', 'meta' );
1494
- }
1495
-
1496
- protected function process_author( $data, $meta ) {
1497
- /**
1498
- * Pre-process user data.
1499
- *
1500
- * @param array $data User data. (Return empty to skip.)
1501
- * @param array $meta Meta data.
1502
- */
1503
- $data = apply_filters( 'wxr_importer.pre_process.user', $data, $meta );
1504
- if ( empty( $data ) ) {
1505
- return false;
1506
- }
1507
-
1508
- // Have we already handled this user?
1509
- $original_id = isset( $data['ID'] ) ? $data['ID'] : 0;
1510
- $original_slug = $data['user_login'];
1511
-
1512
- if ( isset( $this->mapping['user'][ $original_id ] ) ) {
1513
- $existing = $this->mapping['user'][ $original_id ];
1514
-
1515
- // Note the slug mapping if we need to too
1516
- if ( ! isset( $this->mapping['user_slug'][ $original_slug ] ) ) {
1517
- $this->mapping['user_slug'][ $original_slug ] = $existing;
1518
- }
1519
-
1520
- return false;
1521
- }
1522
-
1523
- if ( isset( $this->mapping['user_slug'][ $original_slug ] ) ) {
1524
- $existing = $this->mapping['user_slug'][ $original_slug ];
1525
-
1526
- // Ensure we note the mapping too
1527
- $this->mapping['user'][ $original_id ] = $existing;
1528
-
1529
- return false;
1530
- }
1531
-
1532
- // Allow overriding the user's slug
1533
- $login = $original_slug;
1534
- if ( isset( $this->user_slug_override[ $login ] ) ) {
1535
- $login = $this->user_slug_override[ $login ];
1536
- }
1537
-
1538
- $userdata = array(
1539
- 'user_login' => sanitize_user( $login, true ),
1540
- 'user_pass' => wp_generate_password(),
1541
- );
1542
-
1543
- $allowed = array(
1544
- 'user_email' => true,
1545
- 'display_name' => true,
1546
- 'first_name' => true,
1547
- 'last_name' => true,
1548
- );
1549
- foreach ( $data as $key => $value ) {
1550
- if ( ! isset( $allowed[ $key ] ) ) {
1551
- continue;
1552
- }
1553
-
1554
- $userdata[ $key ] = $data[ $key ];
1555
- }
1556
-
1557
- $user_id = wp_insert_user( wp_slash( $userdata ) );
1558
- if ( is_wp_error( $user_id ) ) {
1559
- $this->logger->error( sprintf(
1560
- __( 'Failed to import user "%s"', 'wordpress-importer' ),
1561
- $userdata['user_login']
1562
- ) );
1563
- $this->logger->debug( $user_id->get_error_message() );
1564
-
1565
- /**
1566
- * User processing failed.
1567
- *
1568
- * @param WP_Error $user_id Error object.
1569
- * @param array $userdata Raw data imported for the user.
1570
- */
1571
- do_action( 'wxr_importer.process_failed.user', $user_id, $userdata );
1572
- return false;
1573
- }
1574
-
1575
- if ( $original_id ) {
1576
- $this->mapping['user'][ $original_id ] = $user_id;
1577
- }
1578
- $this->mapping['user_slug'][ $original_slug ] = $user_id;
1579
-
1580
- $this->logger->info( sprintf(
1581
- __( 'Imported user "%s"', 'wordpress-importer' ),
1582
- $userdata['user_login']
1583
- ) );
1584
- $this->logger->debug( sprintf(
1585
- __( 'User %1$d remapped to %2$d', 'wordpress-importer' ),
1586
- $original_id,
1587
- $user_id
1588
- ) );
1589
-
1590
- // TODO: Implement meta handling once WXR includes it
1591
- /**
1592
- * User processing completed.
1593
- *
1594
- * @param int $user_id New user ID.
1595
- * @param array $userdata Raw data imported for the user.
1596
- */
1597
- do_action( 'wxr_importer.processed.user', $user_id, $userdata );
1598
- }
1599
-
1600
- protected function parse_term_node( $node, $type = 'term' ) {
1601
- $data = array();
1602
- $meta = array();
1603
-
1604
- $tag_name = array(
1605
- 'id' => 'wp:term_id',
1606
- 'taxonomy' => 'wp:term_taxonomy',
1607
- 'slug' => 'wp:term_slug',
1608
- 'parent' => 'wp:term_parent',
1609
- 'name' => 'wp:term_name',
1610
- 'description' => 'wp:term_description',
1611
- );
1612
- $taxonomy = null;
1613
-
1614
- // Special casing!
1615
- switch ( $type ) {
1616
- case 'category':
1617
- $tag_name['slug'] = 'wp:category_nicename';
1618
- $tag_name['parent'] = 'wp:category_parent';
1619
- $tag_name['name'] = 'wp:cat_name';
1620
- $tag_name['description'] = 'wp:category_description';
1621
- $tag_name['taxonomy'] = null;
1622
-
1623
- $data['taxonomy'] = 'category';
1624
- break;
1625
-
1626
- case 'tag':
1627
- $tag_name['slug'] = 'wp:tag_slug';
1628
- $tag_name['parent'] = null;
1629
- $tag_name['name'] = 'wp:tag_name';
1630
- $tag_name['description'] = 'wp:tag_description';
1631
- $tag_name['taxonomy'] = null;
1632
-
1633
- $data['taxonomy'] = 'post_tag';
1634
- break;
1635
- }
1636
-
1637
- foreach ( $node->childNodes as $child ) {
1638
- // We only care about child elements
1639
- if ( $child->nodeType !== XML_ELEMENT_NODE ) {
1640
- continue;
1641
- }
1642
-
1643
- $key = array_search( $child->tagName, $tag_name );
1644
- if ( $key ) {
1645
- $data[ $key ] = $child->textContent;
1646
- }
1647
- }
1648
-
1649
- if ( empty( $data['taxonomy'] ) ) {
1650
- return null;
1651
- }
1652
-
1653
- // Compatibility with WXR 1.0
1654
- if ( $data['taxonomy'] === 'tag' ) {
1655
- $data['taxonomy'] = 'post_tag';
1656
- }
1657
-
1658
- return compact( 'data', 'meta' );
1659
- }
1660
-
1661
- protected function process_term( $data, $meta ) {
1662
- /**
1663
- * Pre-process term data.
1664
- *
1665
- * @param array $data Term data. (Return empty to skip.)
1666
- * @param array $meta Meta data.
1667
- */
1668
- $data = apply_filters( 'wxr_importer.pre_process.term', $data, $meta );
1669
- if ( empty( $data ) ) {
1670
- return false;
1671
- }
1672
-
1673
- $original_id = isset( $data['id'] ) ? (int) $data['id'] : 0;
1674
- $parent_id = isset( $data['parent'] ) ? (int) $data['parent'] : 0;
1675
-
1676
- $mapping_key = sha1( $data['taxonomy'] . ':' . $data['slug'] );
1677
- $existing = $this->term_exists( $data );
1678
- if ( $existing ) {
1679
-
1680
- /**
1681
- * Term processing already imported.
1682
- *
1683
- * @param array $data Raw data imported for the term.
1684
- */
1685
- do_action( 'wxr_importer.process_already_imported.term', $data );
1686
-
1687
- $this->mapping['term'][ $mapping_key ] = $existing;
1688
- $this->mapping['term_id'][ $original_id ] = $existing;
1689
- return false;
1690
- }
1691
-
1692
- // WP really likes to repeat itself in export files
1693
- if ( isset( $this->mapping['term'][ $mapping_key ] ) ) {
1694
- return false;
1695
- }
1696
-
1697
- $termdata = array();
1698
- $allowed = array(
1699
- 'slug' => true,
1700
- 'description' => true,
1701
- );
1702
-
1703
- // Map the parent comment, or mark it as one we need to fix
1704
- // TODO: add parent mapping and remapping
1705
- /*
1706
- $requires_remapping = false;
1707
- if ( $parent_id ) {
1708
- if ( isset( $this->mapping['term'][ $parent_id ] ) ) {
1709
- $data['parent'] = $this->mapping['term'][ $parent_id ];
1710
- } else {
1711
- // Prepare for remapping later
1712
- $meta[] = array( 'key' => '_wxr_import_parent', 'value' => $parent_id );
1713
- $requires_remapping = true;
1714
-
1715
- // Wipe the parent for now
1716
- $data['parent'] = 0;
1717
- }
1718
- }*/
1719
-
1720
- foreach ( $data as $key => $value ) {
1721
- if ( ! isset( $allowed[ $key ] ) ) {
1722
- continue;
1723
- }
1724
-
1725
- $termdata[ $key ] = $data[ $key ];
1726
- }
1727
-
1728
- $result = wp_insert_term( $data['name'], $data['taxonomy'], $termdata );
1729
- if ( is_wp_error( $result ) ) {
1730
- $this->logger->warning( sprintf(
1731
- __( 'Failed to import %1$s %2$s', 'wordpress-importer' ),
1732
- $data['taxonomy'],
1733
- $data['name']
1734
- ) );
1735
- $this->logger->debug( $result->get_error_message() );
1736
- do_action( 'wp_import_insert_term_failed', $result, $data );
1737
-
1738
- /**
1739
- * Term processing failed.
1740
- *
1741
- * @param WP_Error $result Error object.
1742
- * @param array $data Raw data imported for the term.
1743
- * @param array $meta Meta data supplied for the term.
1744
- */
1745
- do_action( 'wxr_importer.process_failed.term', $result, $data, $meta );
1746
- return false;
1747
- }
1748
-
1749
- $term_id = $result['term_id'];
1750
-
1751
- $this->mapping['term'][ $mapping_key ] = $term_id;
1752
- $this->mapping['term_id'][ $original_id ] = $term_id;
1753
-
1754
- $this->logger->info( sprintf(
1755
- __( 'Imported "%1$s" (%2$s)', 'wordpress-importer' ),
1756
- $data['name'],
1757
- $data['taxonomy']
1758
- ) );
1759
- $this->logger->debug( sprintf(
1760
- __( 'Term %1$d remapped to %2$d', 'wordpress-importer' ),
1761
- $original_id,
1762
- $term_id
1763
- ) );
1764
-
1765
- do_action( 'wp_import_insert_term', $term_id, $data );
1766
-
1767
- /**
1768
- * Term processing completed.
1769
- *
1770
- * @param int $term_id New term ID.
1771
- * @param array $data Raw data imported for the term.
1772
- */
1773
- do_action( 'wxr_importer.processed.term', $term_id, $data );
1774
- }
1775
-
1776
- /**
1777
- * Attempt to download a remote file attachment
1778
- *
1779
- * @param string $url URL of item to fetch
1780
- * @param array $post Attachment details
1781
- * @return array|WP_Error Local file location details on success, WP_Error otherwise
1782
- */
1783
- protected function fetch_remote_file( $url, $post ) {
1784
- // extract the file name and extension from the url
1785
- $file_name = basename( $url );
1786
-
1787
- // get placeholder file in the upload dir with a unique, sanitized filename
1788
- $upload = wp_upload_bits( $file_name, 0, '', $post['upload_date'] );
1789
- if ( $upload['error'] ) {
1790
- return new WP_Error( 'upload_dir_error', $upload['error'] );
1791
- }
1792
-
1793
- // fetch the remote url and write it to the placeholder file
1794
- $response = wp_remote_get( $url, array(
1795
- 'stream' => true,
1796
- 'filename' => $upload['file'],
1797
- ) );
1798
-
1799
- // request failed
1800
- if ( is_wp_error( $response ) ) {
1801
- unlink( $upload['file'] );
1802
- return $response;
1803
- }
1804
-
1805
- $code = (int) wp_remote_retrieve_response_code( $response );
1806
-
1807
- // make sure the fetch was successful
1808
- if ( $code !== 200 ) {
1809
- unlink( $upload['file'] );
1810
- return new WP_Error(
1811
- 'import_file_error',
1812
- sprintf(
1813
- __( 'Remote server returned %1$d %2$s for %3$s', 'wordpress-importer' ),
1814
- $code,
1815
- get_status_header_desc( $code ),
1816
- $url
1817
- )
1818
- );
1819
- }
1820
-
1821
- $filesize = filesize( $upload['file'] );
1822
- $headers = wp_remote_retrieve_headers( $response );
1823
-
1824
- if ( isset( $headers['content-length'] ) && $filesize !== (int) $headers['content-length'] ) {
1825
- unlink( $upload['file'] );
1826
- return new WP_Error( 'import_file_error', __( 'Remote file is incorrect size', 'wordpress-importer' ) );
1827
- }
1828
-
1829
- if ( 0 === $filesize ) {
1830
- unlink( $upload['file'] );
1831
- return new WP_Error( 'import_file_error', __( 'Zero size file downloaded', 'wordpress-importer' ) );
1832
- }
1833
-
1834
- $max_size = (int) $this->max_attachment_size();
1835
- if ( ! empty( $max_size ) && $filesize > $max_size ) {
1836
- unlink( $upload['file'] );
1837
- $message = sprintf( __( 'Remote file is too large, limit is %s', 'wordpress-importer' ), size_format( $max_size ) );
1838
- return new WP_Error( 'import_file_error', $message );
1839
- }
1840
-
1841
- return $upload;
1842
- }
1843
-
1844
- protected function post_process() {
1845
- // Time to tackle any left-over bits
1846
- if ( ! empty( $this->requires_remapping['post'] ) ) {
1847
- $this->post_process_posts( $this->requires_remapping['post'] );
1848
- }
1849
- if ( ! empty( $this->requires_remapping['comment'] ) ) {
1850
- $this->post_process_comments( $this->requires_remapping['comment'] );
1851
- }
1852
- }
1853
-
1854
- protected function post_process_posts( $todo ) {
1855
- foreach ( $todo as $post_id => $_ ) {
1856
- $this->logger->debug( sprintf(
1857
- // Note: title intentionally not used to skip extra processing
1858
- // for when debug logging is off
1859
- __( 'Running post-processing for post %d', 'wordpress-importer' ),
1860
- $post_id
1861
- ) );
1862
-
1863
- $data = array();
1864
-
1865
- $parent_id = get_post_meta( $post_id, '_wxr_import_parent', true );
1866
- if ( ! empty( $parent_id ) ) {
1867
- // Have we imported the parent now?
1868
- if ( isset( $this->mapping['post'][ $parent_id ] ) ) {
1869
- $data['post_parent'] = $this->mapping['post'][ $parent_id ];
1870
- } else {
1871
- $this->logger->warning( sprintf(
1872
- __( 'Could not find the post parent for "%1$s" (post #%2$d)', 'wordpress-importer' ),
1873
- get_the_title( $post_id ),
1874
- $post_id
1875
- ) );
1876
- $this->logger->debug( sprintf(
1877
- __( 'Post %1$d was imported with parent %2$d, but could not be found', 'wordpress-importer' ),
1878
- $post_id,
1879
- $parent_id
1880
- ) );
1881
- }
1882
- }
1883
-
1884
- $author_slug = get_post_meta( $post_id, '_wxr_import_user_slug', true );
1885
- if ( ! empty( $author_slug ) ) {
1886
- // Have we imported the user now?
1887
- if ( isset( $this->mapping['user_slug'][ $author_slug ] ) ) {
1888
- $data['post_author'] = $this->mapping['user_slug'][ $author_slug ];
1889
- } else {
1890
- $this->logger->warning( sprintf(
1891
- __( 'Could not find the author for "%1$s" (post #%2$d)', 'wordpress-importer' ),
1892
- get_the_title( $post_id ),
1893
- $post_id
1894
- ) );
1895
- $this->logger->debug( sprintf(
1896
- __( 'Post %1$d was imported with author "%2$s", but could not be found', 'wordpress-importer' ),
1897
- $post_id,
1898
- $author_slug
1899
- ) );
1900
- }
1901
- }
1902
-
1903
- $has_attachments = get_post_meta( $post_id, '_wxr_import_has_attachment_refs', true );
1904
- if ( ! empty( $has_attachments ) ) {
1905
- $post = get_post( $post_id );
1906
- $content = $post->post_content;
1907
-
1908
- // Replace all the URLs we've got
1909
- $new_content = str_replace( array_keys( $this->url_remap ), $this->url_remap, $content );
1910
- if ( $new_content !== $content ) {
1911
- $data['post_content'] = $new_content;
1912
- }
1913
- }
1914
-
1915
- if ( get_post_type( $post_id ) === 'nav_menu_item' ) {
1916
- $this->post_process_menu_item( $post_id );
1917
- }
1918
-
1919
- // Do we have updates to make?
1920
- if ( empty( $data ) ) {
1921
- $this->logger->debug( sprintf(
1922
- __( 'Post %d was marked for post-processing, but none was required.', 'wordpress-importer' ),
1923
- $post_id
1924
- ) );
1925
- continue;
1926
- }
1927
-
1928
- // Run the update
1929
- $data['ID'] = $post_id;
1930
- $result = wp_update_post( $data, true );
1931
- if ( is_wp_error( $result ) ) {
1932
- $this->logger->warning( sprintf(
1933
- __( 'Could not update "%1$s" (post #%2$d) with mapped data', 'wordpress-importer' ),
1934
- get_the_title( $post_id ),
1935
- $post_id
1936
- ) );
1937
- $this->logger->debug( $result->get_error_message() );
1938
- continue;
1939
- }
1940
-
1941
- // Clear out our temporary meta keys
1942
- delete_post_meta( $post_id, '_wxr_import_parent' );
1943
- delete_post_meta( $post_id, '_wxr_import_user_slug' );
1944
- delete_post_meta( $post_id, '_wxr_import_has_attachment_refs' );
1945
- }// End foreach().
1946
- }
1947
-
1948
- protected function post_process_menu_item( $post_id ) {
1949
- $menu_object_id = get_post_meta( $post_id, '_wxr_import_menu_item', true );
1950
- if ( empty( $menu_object_id ) ) {
1951
- // No processing needed!
1952
- return;
1953
- }
1954
-
1955
- $menu_item_type = get_post_meta( $post_id, '_menu_item_type', true );
1956
- switch ( $menu_item_type ) {
1957
- case 'taxonomy':
1958
- if ( isset( $this->mapping['term_id'][ $menu_object_id ] ) ) {
1959
- $menu_object = $this->mapping['term_id'][ $menu_object_id ];
1960
- }
1961
- break;
1962
-
1963
- case 'post_type':
1964
- if ( isset( $this->mapping['post'][ $menu_object_id ] ) ) {
1965
- $menu_object = $this->mapping['post'][ $menu_object_id ];
1966
- }
1967
- break;
1968
-
1969
- default:
1970
- // Cannot handle this.
1971
- return;
1972
- }
1973
-
1974
- if ( ! empty( $menu_object ) ) {
1975
- update_post_meta( $post_id, '_menu_item_object_id', wp_slash( $menu_object ) );
1976
- } else {
1977
- $this->logger->warning( sprintf(
1978
- __( 'Could not find the menu object for "%1$s" (post #%2$d)', 'wordpress-importer' ),
1979
- get_the_title( $post_id ),
1980
- $post_id
1981
- ) );
1982
- $this->logger->debug( sprintf(
1983
- __( 'Post %1$d was imported with object "%2$d" of type "%3$s", but could not be found', 'wordpress-importer' ),
1984
- $post_id,
1985
- $menu_object_id,
1986
- $menu_item_type
1987
- ) );
1988
- }
1989
-
1990
- delete_post_meta( $post_id, '_wxr_import_menu_item' );
1991
- }
1992
-
1993
-
1994
- protected function post_process_comments( $todo ) {
1995
- foreach ( $todo as $comment_id => $_ ) {
1996
- $data = array();
1997
-
1998
- $parent_id = get_comment_meta( $comment_id, '_wxr_import_parent', true );
1999
- if ( ! empty( $parent_id ) ) {
2000
- // Have we imported the parent now?
2001
- if ( isset( $this->mapping['comment'][ $parent_id ] ) ) {
2002
- $data['comment_parent'] = $this->mapping['comment'][ $parent_id ];
2003
- } else {
2004
- $this->logger->warning( sprintf(
2005
- __( 'Could not find the comment parent for comment #%d', 'wordpress-importer' ),
2006
- $comment_id
2007
- ) );
2008
- $this->logger->debug( sprintf(
2009
- __( 'Comment %1$d was imported with parent %2$d, but could not be found', 'wordpress-importer' ),
2010
- $comment_id,
2011
- $parent_id
2012
- ) );
2013
- }
2014
- }
2015
-
2016
- $author_id = get_comment_meta( $comment_id, '_wxr_import_user', true );
2017
- if ( ! empty( $author_id ) ) {
2018
- // Have we imported the user now?
2019
- if ( isset( $this->mapping['user'][ $author_id ] ) ) {
2020
- $data['user_id'] = $this->mapping['user'][ $author_id ];
2021
- } else {
2022
- $this->logger->warning( sprintf(
2023
- __( 'Could not find the author for comment #%d', 'wordpress-importer' ),
2024
- $comment_id
2025
- ) );
2026
- $this->logger->debug( sprintf(
2027
- __( 'Comment %1$d was imported with author %2$d, but could not be found', 'wordpress-importer' ),
2028
- $comment_id,
2029
- $author_id
2030
- ) );
2031
- }
2032
- }
2033
-
2034
- // Do we have updates to make?
2035
- if ( empty( $data ) ) {
2036
- continue;
2037
- }
2038
-
2039
- // Run the update
2040
- $data['comment_ID'] = $comment_ID;
2041
- $result = wp_update_comment( wp_slash( $data ) );
2042
- if ( empty( $result ) ) {
2043
- $this->logger->warning( sprintf(
2044
- __( 'Could not update comment #%d with mapped data', 'wordpress-importer' ),
2045
- $comment_id
2046
- ) );
2047
- continue;
2048
- }
2049
-
2050
- // Clear out our temporary meta keys
2051
- delete_comment_meta( $comment_id, '_wxr_import_parent' );
2052
- delete_comment_meta( $comment_id, '_wxr_import_user' );
2053
- }// End foreach().
2054
- }
2055
-
2056
- /**
2057
- * Use stored mapping information to update old attachment URLs
2058
- */
2059
- protected function replace_attachment_urls_in_content() {
2060
- global $wpdb;
2061
- // make sure we do the longest urls first, in case one is a substring of another
2062
- uksort( $this->url_remap, array( $this, 'cmpr_strlen' ) );
2063
-
2064
- foreach ( $this->url_remap as $from_url => $to_url ) {
2065
- // remap urls in post_content
2066
- $query = $wpdb->prepare( "UPDATE {$wpdb->posts} SET post_content = REPLACE(post_content, %s, %s)", $from_url, $to_url );
2067
- $wpdb->query( $query );
2068
-
2069
- // remap enclosure urls
2070
- $query = $wpdb->prepare( "UPDATE {$wpdb->postmeta} SET meta_value = REPLACE(meta_value, %s, %s) WHERE meta_key='enclosure'", $from_url, $to_url );
2071
- $result = $wpdb->query( $query );
2072
- }
2073
- }
2074
-
2075
- /**
2076
- * Update _thumbnail_id meta to new, imported attachment IDs
2077
- */
2078
- function remap_featured_images() {
2079
- // cycle through posts that have a featured image
2080
- foreach ( $this->featured_images as $post_id => $value ) {
2081
- if ( isset( $this->processed_posts[ $value ] ) ) {
2082
- $new_id = $this->processed_posts[ $value ];
2083
-
2084
- // only update if there's a difference
2085
- if ( $new_id !== $value ) {
2086
- update_post_meta( $post_id, '_thumbnail_id', $new_id );
2087
- }
2088
- }
2089
- }
2090
- }
2091
-
2092
- /**
2093
- * Decide if the given meta key maps to information we will want to import
2094
- *
2095
- * @param string $key The meta key to check
2096
- * @return string|bool The key if we do want to import, false if not
2097
- */
2098
- public function is_valid_meta_key( $key ) {
2099
- // skip attachment metadata since we'll regenerate it from scratch
2100
- // skip _edit_lock as not relevant for import
2101
- if ( in_array( $key, array( '_wp_attached_file', '_wp_attachment_metadata', '_edit_lock' ) ) ) {
2102
- return false;
2103
- }
2104
-
2105
- return $key;
2106
- }
2107
-
2108
- /**
2109
- * Decide what the maximum file size for downloaded attachments is.
2110
- * Default is 0 (unlimited), can be filtered via import_attachment_size_limit
2111
- *
2112
- * @return int Maximum attachment file size to import
2113
- */
2114
- protected function max_attachment_size() {
2115
- return apply_filters( 'import_attachment_size_limit', 0 );
2116
- }
2117
-
2118
- /**
2119
- * Added to http_request_timeout filter to force timeout at 60 seconds during import
2120
- *
2121
- * @access protected
2122
- * @return int 60
2123
- */
2124
- function bump_request_timeout( $val ) {
2125
- return 60;
2126
- }
2127
-
2128
- // return the difference in length between two strings
2129
- function cmpr_strlen( $a, $b ) {
2130
- return strlen( $b ) - strlen( $a );
2131
- }
2132
-
2133
- /**
2134
- * Prefill existing post data.
2135
- *
2136
- * This preloads all GUIDs into memory, allowing us to avoid hitting the
2137
- * database when we need to check for existence. With larger imports, this
2138
- * becomes prohibitively slow to perform SELECT queries on each.
2139
- *
2140
- * By preloading all this data into memory, it's a constant-time lookup in
2141
- * PHP instead. However, this does use a lot more memory, so for sites doing
2142
- * small imports onto a large site, it may be a better tradeoff to use
2143
- * on-the-fly checking instead.
2144
- */
2145
- protected function prefill_existing_posts() {
2146
- global $wpdb;
2147
- $posts = $wpdb->get_results( "SELECT ID, guid FROM {$wpdb->posts}" );
2148
-
2149
- foreach ( $posts as $item ) {
2150
- $this->exists['post'][ $item->guid ] = $item->ID;
2151
- }
2152
- }
2153
-
2154
- /**
2155
- * Does the post exist?
2156
- *
2157
- * @param array $data Post data to check against.
2158
- * @return int|bool Existing post ID if it exists, false otherwise.
2159
- */
2160
- protected function post_exists( $data ) {
2161
- // Constant-time lookup if we prefilled
2162
- $exists_key = $data['guid'];
2163
-
2164
- if ( $this->options['prefill_existing_posts'] ) {
2165
- return isset( $this->exists['post'][ $exists_key ] ) ? $this->exists['post'][ $exists_key ] : false;
2166
- }
2167
-
2168
- // No prefilling, but might have already handled it
2169
- if ( isset( $this->exists['post'][ $exists_key ] ) ) {
2170
- return $this->exists['post'][ $exists_key ];
2171
- }
2172
-
2173
- // Still nothing, try post_exists, and cache it
2174
- $exists = post_exists( $data['post_title'], $data['post_content'], $data['post_date'] );
2175
- $this->exists['post'][ $exists_key ] = $exists;
2176
-
2177
- return $exists;
2178
- }
2179
-
2180
- /**
2181
- * Mark the post as existing.
2182
- *
2183
- * @param array $data Post data to mark as existing.
2184
- * @param int $post_id Post ID.
2185
- */
2186
- protected function mark_post_exists( $data, $post_id ) {
2187
- $exists_key = $data['guid'];
2188
- $this->exists['post'][ $exists_key ] = $post_id;
2189
- }
2190
-
2191
- /**
2192
- * Prefill existing comment data.
2193
- *
2194
- * @see self::prefill_existing_posts() for justification of why this exists.
2195
- */
2196
- protected function prefill_existing_comments() {
2197
- global $wpdb;
2198
- $posts = $wpdb->get_results( "SELECT comment_ID, comment_author, comment_date FROM {$wpdb->comments}" );
2199
-
2200
- foreach ( $posts as $item ) {
2201
- $exists_key = sha1( $item->comment_author . ':' . $item->comment_date );
2202
- $this->exists['comment'][ $exists_key ] = $item->comment_ID;
2203
- }
2204
- }
2205
-
2206
- /**
2207
- * Does the comment exist?
2208
- *
2209
- * @param array $data Comment data to check against.
2210
- * @return int|bool Existing comment ID if it exists, false otherwise.
2211
- */
2212
- protected function comment_exists( $data ) {
2213
- $exists_key = sha1( $data['comment_author'] . ':' . $data['comment_date'] );
2214
-
2215
- // Constant-time lookup if we prefilled
2216
- if ( $this->options['prefill_existing_comments'] ) {
2217
- return isset( $this->exists['comment'][ $exists_key ] ) ? $this->exists['comment'][ $exists_key ] : false;
2218
- }
2219
-
2220
- // No prefilling, but might have already handled it
2221
- if ( isset( $this->exists['comment'][ $exists_key ] ) ) {
2222
- return $this->exists['comment'][ $exists_key ];
2223
- }
2224
-
2225
- // Still nothing, try comment_exists, and cache it
2226
- $exists = comment_exists( $data['comment_author'], $data['comment_date'] );
2227
- $this->exists['comment'][ $exists_key ] = $exists;
2228
-
2229
- return $exists;
2230
- }
2231
-
2232
- /**
2233
- * Mark the comment as existing.
2234
- *
2235
- * @param array $data Comment data to mark as existing.
2236
- * @param int $comment_id Comment ID.
2237
- */
2238
- protected function mark_comment_exists( $data, $comment_id ) {
2239
- $exists_key = sha1( $data['comment_author'] . ':' . $data['comment_date'] );
2240
- $this->exists['comment'][ $exists_key ] = $comment_id;
2241
- }
2242
-
2243
- /**
2244
- * Prefill existing term data.
2245
- *
2246
- * @see self::prefill_existing_posts() for justification of why this exists.
2247
- */
2248
- protected function prefill_existing_terms() {
2249
- global $wpdb;
2250
- $query = "SELECT t.term_id, tt.taxonomy, t.slug FROM {$wpdb->terms} AS t";
2251
- $query .= " JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id";
2252
- $terms = $wpdb->get_results( $query );
2253
-
2254
- foreach ( $terms as $item ) {
2255
- $exists_key = sha1( $item->taxonomy . ':' . $item->slug );
2256
- $this->exists['term'][ $exists_key ] = $item->term_id;
2257
- }
2258
- }
2259
-
2260
- /**
2261
- * Does the term exist?
2262
- *
2263
- * @param array $data Term data to check against.
2264
- * @return int|bool Existing term ID if it exists, false otherwise.
2265
- */
2266
- protected function term_exists( $data ) {
2267
- $exists_key = sha1( $data['taxonomy'] . ':' . $data['slug'] );
2268
-
2269
- // Constant-time lookup if we prefilled
2270
- if ( $this->options['prefill_existing_terms'] ) {
2271
- return isset( $this->exists['term'][ $exists_key ] ) ? $this->exists['term'][ $exists_key ] : false;
2272
- }
2273
-
2274
- // No prefilling, but might have already handled it
2275
- if ( isset( $this->exists['term'][ $exists_key ] ) ) {
2276
- return $this->exists['term'][ $exists_key ];
2277
- }
2278
-
2279
- // Still nothing, try comment_exists, and cache it
2280
- $exists = term_exists( $data['slug'], $data['taxonomy'] );
2281
- if ( is_array( $exists ) ) {
2282
- $exists = $exists['term_id'];
2283
- }
2284
-
2285
- $this->exists['term'][ $exists_key ] = $exists;
2286
-
2287
- return $exists;
2288
- }
2289
-
2290
- /**
2291
- * Mark the term as existing.
2292
- *
2293
- * @param array $data Term data to mark as existing.
2294
- * @param int $term_id Term ID.
2295
- */
2296
- protected function mark_term_exists( $data, $term_id ) {
2297
- $exists_key = sha1( $data['taxonomy'] . ':' . $data['slug'] );
2298
- $this->exists['term'][ $exists_key ] = $term_id;
2299
- }
2300
- }
2301
  endif;
1
+ <?php
2
+
3
+ if( ! class_exists( 'WXR_Importer' ) && class_exists( 'WP_Importer' ) ) :
4
+ class WXR_Importer extends WP_Importer {
5
+ /**
6
+ * Maximum supported WXR version
7
+ */
8
+ const MAX_WXR_VERSION = 1.2;
9
+
10
+ /**
11
+ * Regular expression for checking if a post references an attachment
12
+ *
13
+ * Note: This is a quick, weak check just to exclude text-only posts. More
14
+ * vigorous checking is done later to verify.
15
+ */
16
+ const REGEX_HAS_ATTACHMENT_REFS = '!
17
+ (
18
+ # Match anything with an image or attachment class
19
+ class=[\'"].*?\b(wp-image-\d+|attachment-[\w\-]+)\b
20
+ |
21
+ # Match anything that looks like an upload URL
22
+ src=[\'"][^\'"]*(
23
+ [0-9]{4}/[0-9]{2}/[^\'"]+\.(jpg|jpeg|png|gif)
24
+ |
25
+ content/uploads[^\'"]+
26
+ )[\'"]
27
+ )!ix';
28
+
29
+ /**
30
+ * Version of WXR we're importing.
31
+ *
32
+ * Defaults to 1.0 for compatibility. Typically overridden by a
33
+ * `<wp:wxr_version>` tag at the start of the file.
34
+ *
35
+ * @var string
36
+ */
37
+ protected $version = '1.0';
38
+
39
+ // information to import from WXR file
40
+ protected $categories = array();
41
+ protected $tags = array();
42
+ protected $base_url = '';
43
+
44
+ // TODO: REMOVE THESE
45
+ protected $processed_terms = array();
46
+ protected $processed_posts = array();
47
+ protected $processed_menu_items = array();
48
+ protected $menu_item_orphans = array();
49
+ protected $missing_menu_items = array();
50
+
51
+ // NEW STYLE
52
+ protected $mapping = array();
53
+ protected $requires_remapping = array();
54
+ protected $exists = array();
55
+ protected $user_slug_override = array();
56
+
57
+ protected $url_remap = array();
58
+ protected $featured_images = array();
59
+
60
+ /**
61
+ * Logger instance.
62
+ *
63
+ * @var WP_Importer_Logger
64
+ */
65
+ protected $logger;
66
+
67
+ /**
68
+ * Constructor
69
+ *
70
+ * @param array $options {
71
+ * @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.)
72
+ * @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.)
73
+ * @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.)
74
+ * @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.)
75
+ * @var bool $fetch_attachments Fetch attachments from the remote server. (True fetches and creates attachment posts, false skips attachments. Default is false.)
76
+ * @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.)
77
+ * @var int $default_author User ID to use if author is missing or invalid. (Default is null, which leaves posts unassigned.)
78
+ * }
79
+ */
80
+ public function __construct( $options = array() ) {
81
+ // Initialize some important variables
82
+ $empty_types = array(
83
+ 'post' => array(),
84
+ 'comment' => array(),
85
+ 'term' => array(),
86
+ 'user' => array(),
87
+ );
88
+
89
+ $this->mapping = $empty_types;
90
+ $this->mapping['user_slug'] = array();
91
+ $this->mapping['term_id'] = array();
92
+ $this->requires_remapping = $empty_types;
93
+ $this->exists = $empty_types;
94
+
95
+ $this->options = wp_parse_args( $options, array(
96
+ 'prefill_existing_posts' => true,
97
+ 'prefill_existing_comments' => true,
98
+ 'prefill_existing_terms' => true,
99
+ 'update_attachment_guids' => false,
100
+ 'fetch_attachments' => false,
101
+ 'aggressive_url_search' => false,
102
+ 'default_author' => null,
103
+ ) );
104
+ }
105
+
106
+ public function set_logger( $logger ) {
107
+ $this->logger = $logger;
108
+ }
109
+
110
+ /**
111
+ * Get a stream reader for the file.
112
+ *
113
+ * @param string $file Path to the XML file.
114
+ * @return XMLReader|WP_Error Reader instance on success, error otherwise.
115
+ */
116
+ protected function get_reader( $file ) {
117
+ // Avoid loading external entities for security
118
+ $old_value = null;
119
+ if ( function_exists( 'libxml_disable_entity_loader' ) ) {
120
+ // $old_value = libxml_disable_entity_loader( true );
121
+ }
122
+
123
+ $reader = new XMLReader();
124
+ $status = $reader->open( $file );
125
+
126
+ if ( ! is_null( $old_value ) ) {
127
+ // libxml_disable_entity_loader( $old_value );
128
+ }
129
+
130
+ if ( ! $status ) {
131
+ return new WP_Error( 'wxr_importer.cannot_parse', __( 'Could not open the file for parsing', 'wordpress-importer' ) );
132
+ }
133
+
134
+ return $reader;
135
+ }
136
+
137
+ /**
138
+ * The main controller for the actual import stage.
139
+ *
140
+ * @param string $file Path to the WXR file for importing
141
+ */
142
+ public function get_preliminary_information( $file ) {
143
+ // Let's run the actual importer now, woot
144
+ $reader = $this->get_reader( $file );
145
+ if ( is_wp_error( $reader ) ) {
146
+ return $reader;
147
+ }
148
+
149
+ // Set the version to compatibility mode first
150
+ $this->version = '1.0';
151
+
152
+ // Start parsing!
153
+ $data = new WXR_Import_Info();
154
+ while ( $reader->read() ) {
155
+ // Only deal with element opens
156
+ if ( $reader->nodeType !== XMLReader::ELEMENT ) {
157
+ continue;
158
+ }
159
+
160
+ switch ( $reader->name ) {
161
+ case 'wp:wxr_version':
162
+ // Upgrade to the correct version
163
+ $this->version = $reader->readString();
164
+
165
+ if ( version_compare( $this->version, self::MAX_WXR_VERSION, '>' ) ) {
166
+ $this->logger->warning( sprintf(
167
+ __( 'This WXR file (version %1$s) is newer than the importer (version %2$s) and may not be supported. Please consider updating.', 'wordpress-importer' ),
168
+ $this->version,
169
+ self::MAX_WXR_VERSION
170
+ ) );
171
+ }
172
+
173
+ // Handled everything in this node, move on to the next
174
+ $reader->next();
175
+ break;
176
+
177
+ case 'generator':
178
+ $data->generator = $reader->readString();
179
+ $reader->next();
180
+ break;
181
+
182
+ case 'title':
183
+ $data->title = $reader->readString();
184
+ $reader->next();
185
+ break;
186
+
187
+ case 'wp:base_site_url':
188
+ $data->siteurl = $reader->readString();
189
+ $reader->next();
190
+ break;
191
+
192
+ case 'wp:base_blog_url':
193
+ $data->home = $reader->readString();
194
+ $reader->next();
195
+ break;
196
+
197
+ case 'wp:author':
198
+ $node = $reader->expand();
199
+
200
+ $parsed = $this->parse_author_node( $node );
201
+ if ( is_wp_error( $parsed ) ) {
202
+ $this->log_error( $parsed );
203
+
204
+ // Skip the rest of this post
205
+ $reader->next();
206
+ break;
207
+ }
208
+
209
+ $data->users[] = $parsed;
210
+
211
+ // Handled everything in this node, move on to the next
212
+ $reader->next();
213
+ break;
214
+
215
+ case 'item':
216
+ $node = $reader->expand();
217
+ $parsed = $this->parse_post_node( $node );
218
+ if ( is_wp_error( $parsed ) ) {
219
+ $this->log_error( $parsed );
220
+
221
+ // Skip the rest of this post
222
+ $reader->next();
223
+ break;
224
+ }
225
+
226
+ if ( $parsed['data']['post_type'] === 'attachment' ) {
227
+ $data->media_count++;
228
+ } else {
229
+ $data->post_count++;
230
+ }
231
+ $data->comment_count += count( $parsed['comments'] );
232
+
233
+ // Handled everything in this node, move on to the next
234
+ $reader->next();
235
+ break;
236
+
237
+ case 'wp:category':
238
+ case 'wp:tag':
239
+ case 'wp:term':
240
+ $data->term_count++;
241
+
242
+ // Handled everything in this node, move on to the next
243
+ $reader->next();
244
+ break;
245
+ }// End switch().
246
+ }// End while().
247
+
248
+ $data->version = $this->version;
249
+
250
+ return $data;
251
+ }
252
+
253
+ /**
254
+ * The main controller for the actual import stage.
255
+ *
256
+ * @param string $file Path to the WXR file for importing
257
+ */
258
+ public function parse_authors( $file ) {
259
+ // Let's run the actual importer now, woot
260
+ $reader = $this->get_reader( $file );
261
+ if ( is_wp_error( $reader ) ) {
262
+ return $reader;
263
+ }
264
+
265
+ // Set the version to compatibility mode first
266
+ $this->version = '1.0';
267
+
268
+ // Start parsing!
269
+ $authors = array();
270
+ while ( $reader->read() ) {
271
+ // Only deal with element opens
272
+ if ( $reader->nodeType !== XMLReader::ELEMENT ) {
273
+ continue;
274
+ }
275
+
276
+ switch ( $reader->name ) {
277
+ case 'wp:wxr_version':
278
+ // Upgrade to the correct version
279
+ $this->version = $reader->readString();
280
+
281
+ if ( version_compare( $this->version, self::MAX_WXR_VERSION, '>' ) ) {
282
+ $this->logger->warning( sprintf(
283
+ __( 'This WXR file (version %1$s) is newer than the importer (version %2$s) and may not be supported. Please consider updating.', 'wordpress-importer' ),
284
+ $this->version,
285
+ self::MAX_WXR_VERSION
286
+ ) );
287
+ }
288
+
289
+ // Handled everything in this node, move on to the next
290
+ $reader->next();
291
+ break;
292
+
293
+ case 'wp:author':
294
+ $node = $reader->expand();
295
+
296
+ $parsed = $this->parse_author_node( $node );
297
+ if ( is_wp_error( $parsed ) ) {
298
+ $this->log_error( $parsed );
299
+
300
+ // Skip the rest of this post
301
+ $reader->next();
302
+ break;
303
+ }
304
+
305
+ $authors[] = $parsed;
306
+
307
+ // Handled everything in this node, move on to the next
308
+ $reader->next();
309
+ break;
310
+ }
311
+ }// End while().
312
+
313
+ return $authors;
314
+ }
315
+
316
+ /**
317
+ * The main controller for the actual import stage.
318
+ *
319
+ * @param string $file Path to the WXR file for importing
320
+ */
321
+ public function import( $file ) {
322
+ add_filter( 'import_post_meta_key', array( $this, 'is_valid_meta_key' ) );
323
+ add_filter( 'http_request_timeout', array( &$this, 'bump_request_timeout' ) );
324
+
325
+ $result = $this->import_start( $file );
326
+ if ( is_wp_error( $result ) ) {
327
+ return $result;
328
+ }
329
+
330
+ // Let's run the actual importer now, woot
331
+ $reader = $this->get_reader( $file );
332
+ if ( is_wp_error( $reader ) ) {
333
+ return $reader;
334
+ }
335
+
336
+ // Set the version to compatibility mode first
337
+ $this->version = '1.0';
338
+
339
+ // Reset other variables
340
+ $this->base_url = '';
341
+
342
+ // Start parsing!
343
+ while ( $reader->read() ) {
344
+ // Only deal with element opens
345
+ if ( $reader->nodeType !== XMLReader::ELEMENT ) {
346
+ continue;
347
+ }
348
+
349
+ switch ( $reader->name ) {
350
+ case 'wp:wxr_version':
351
+ // Upgrade to the correct version
352
+ $this->version = $reader->readString();
353
+
354
+ if ( version_compare( $this->version, self::MAX_WXR_VERSION, '>' ) ) {
355
+ $this->logger->warning( sprintf(
356
+ __( 'This WXR file (version %1$s) is newer than the importer (version %2$s) and may not be supported. Please consider updating.', 'wordpress-importer' ),
357
+ $this->version,
358
+ self::MAX_WXR_VERSION
359
+ ) );
360
+ }
361
+
362
+ // Handled everything in this node, move on to the next
363
+ $reader->next();
364
+ break;
365
+
366
+ case 'wp:base_site_url':
367
+ $this->base_url = $reader->readString();
368
+
369
+ // Handled everything in this node, move on to the next
370
+ $reader->next();
371
+ break;
372
+
373
+ case 'item':
374
+ $node = $reader->expand();
375
+ $parsed = $this->parse_post_node( $node );
376
+ if ( is_wp_error( $parsed ) ) {
377
+ $this->log_error( $parsed );
378
+
379
+ // Skip the rest of this post
380
+ $reader->next();
381
+ break;
382
+ }
383
+
384
+ $this->process_post( $parsed['data'], $parsed['meta'], $parsed['comments'], $parsed['terms'] );
385
+
386
+ // Handled everything in this node, move on to the next
387
+ $reader->next();
388
+ break;
389
+
390
+ case 'wp:author':
391
+ $node = $reader->expand();
392
+
393
+ $parsed = $this->parse_author_node( $node );
394
+ if ( is_wp_error( $parsed ) ) {
395
+ $this->log_error( $parsed );
396
+
397
+ // Skip the rest of this post
398
+ $reader->next();
399
+ break;
400
+ }
401
+
402
+ $status = $this->process_author( $parsed['data'], $parsed['meta'] );
403
+ if ( is_wp_error( $status ) ) {
404
+ $this->log_error( $status );
405
+ }
406
+
407
+ // Handled everything in this node, move on to the next
408
+ $reader->next();
409
+ break;
410
+
411
+ case 'wp:category':
412
+ $node = $reader->expand();
413
+
414
+ $parsed = $this->parse_term_node( $node, 'category' );
415
+ if ( is_wp_error( $parsed ) ) {
416
+ $this->log_error( $parsed );
417
+
418
+ // Skip the rest of this post
419
+ $reader->next();
420
+ break;
421
+ }
422
+
423
+ $status = $this->process_term( $parsed['data'], $parsed['meta'] );
424
+
425
+ // Handled everything in this node, move on to the next
426
+ $reader->next();
427
+ break;
428
+
429
+ case 'wp:tag':
430
+ $node = $reader->expand();
431
+
432
+ $parsed = $this->parse_term_node( $node, 'tag' );
433
+ if ( is_wp_error( $parsed ) ) {
434
+ $this->log_error( $parsed );
435
+
436
+ // Skip the rest of this post
437
+ $reader->next();
438
+ break;
439
+ }
440
+
441
+ $status = $this->process_term( $parsed['data'], $parsed['meta'] );
442
+
443
+ // Handled everything in this node, move on to the next
444
+ $reader->next();
445
+ break;
446
+
447
+ case 'wp:term':
448
+ $node = $reader->expand();
449
+
450
+ $parsed = $this->parse_term_node( $node );
451
+ if ( is_wp_error( $parsed ) ) {
452
+ $this->log_error( $parsed );
453
+
454
+ // Skip the rest of this post
455
+ $reader->next();
456
+ break;
457
+ }
458
+
459
+ $status = $this->process_term( $parsed['data'], $parsed['meta'] );
460
+
461
+ // Handled everything in this node, move on to the next
462
+ $reader->next();
463
+ break;
464
+
465
+ default:
466
+ // Skip this node, probably handled by something already
467
+ break;
468
+ }// End switch().
469
+ }// End while().
470
+
471
+ // Now that we've done the main processing, do any required
472
+ // post-processing and remapping.
473
+ $this->post_process();
474
+
475
+ if ( $this->options['aggressive_url_search'] ) {
476
+ $this->replace_attachment_urls_in_content();
477
+ }
478
+ // $this->remap_featured_images();
479
+ $this->import_end();
480
+ }
481
+
482
+ /**
483
+ * Log an error instance to the logger.
484
+ *
485
+ * @param WP_Error $error Error instance to log.
486
+ */
487
+ protected function log_error( WP_Error $error ) {
488
+ $this->logger->warning( $error->get_error_message() );
489
+
490
+ // Log the data as debug info too
491
+ $data = $error->get_error_data();
492
+ if ( ! empty( $data ) ) {
493
+ $this->logger->debug( var_export( $data, true ) );
494
+ }
495
+ }
496
+
497
+ /**
498
+ * Parses the WXR file and prepares us for the task of processing parsed data
499
+ *
500
+ * @param string $file Path to the WXR file for importing
501
+ */
502
+ protected function import_start( $file ) {
503
+ if ( ! is_file( $file ) ) {
504
+ return new WP_Error( 'wxr_importer.file_missing', __( 'The file does not exist, please try again.', 'wordpress-importer' ) );
505
+ }
506
+
507
+ // Suspend bunches of stuff in WP core
508
+ wp_defer_term_counting( true );
509
+ wp_defer_comment_counting( true );
510
+ wp_suspend_cache_invalidation( true );
511
+
512
+ // Prefill exists calls if told to
513
+ if ( $this->options['prefill_existing_posts'] ) {
514
+ $this->prefill_existing_posts();
515
+ }
516
+ if ( $this->options['prefill_existing_comments'] ) {
517
+ $this->prefill_existing_comments();
518
+ }
519
+ if ( $this->options['prefill_existing_terms'] ) {
520
+ $this->prefill_existing_terms();
521
+ }
522
+
523
+ /**
524
+ * Begin the import.
525
+ *
526
+ * Fires before the import process has begun. If you need to suspend
527
+ * caching or heavy processing on hooks, do so here.
528
+ */
529
+ do_action( 'import_start' );
530
+ }
531
+
532
+ /**
533
+ * Performs post-import cleanup of files and the cache
534
+ */
535
+ protected function import_end() {
536
+ // Re-enable stuff in core
537
+ wp_suspend_cache_invalidation( false );
538
+ wp_cache_flush();
539
+ foreach ( get_taxonomies() as $tax ) {
540
+ delete_option( "{$tax}_children" );
541
+ _get_term_hierarchy( $tax );
542
+ }
543
+
544
+ wp_defer_term_counting( false );
545
+ wp_defer_comment_counting( false );
546
+
547
+ /**
548
+ * Complete the import.
549
+ *
550
+ * Fires after the import process has finished. If you need to update
551
+ * your cache or re-enable processing, do so here.
552
+ */
553
+ do_action( 'import_end' );
554
+ }
555
+
556
+ /**
557
+ * Set the user mapping.
558
+ *
559
+ * @param array $mapping List of map arrays (containing `old_slug`, `old_id`, `new_id`)
560
+ */
561
+ public function set_user_mapping( $mapping ) {
562
+ foreach ( $mapping as $map ) {
563
+ if ( empty( $map['old_slug'] ) || empty( $map['old_id'] ) || empty( $map['new_id'] ) ) {
564
+ $this->logger->warning( __( 'Invalid author mapping', 'wordpress-importer' ) );
565
+ $this->logger->debug( var_export( $map, true ) );
566
+ continue;
567
+ }
568
+
569
+ $old_slug = $map['old_slug'];
570
+ $old_id = $map['old_id'];
571
+ $new_id = $map['new_id'];
572
+
573
+ $this->mapping['user'][ $old_id ] = $new_id;
574
+ $this->mapping['user_slug'][ $old_slug ] = $new_id;
575
+ }
576
+ }
577
+
578
+ /**
579
+ * Set the user slug overrides.
580
+ *
581
+ * Allows overriding the slug in the import with a custom/renamed version.
582
+ *
583
+ * @param string[] $overrides Map of old slug to new slug.
584
+ */
585
+ public function set_user_slug_overrides( $overrides ) {
586
+ foreach ( $overrides as $original => $renamed ) {
587
+ $this->user_slug_override[ $original ] = $renamed;
588
+ }
589
+ }
590
+
591
+ /**
592
+ * Parse a post node into post data.
593
+ *
594
+ * @param DOMElement $node Parent node of post data (typically `item`).
595
+ * @return array|WP_Error Post data array on success, error otherwise.
596
+ */
597
+ protected function parse_post_node( $node ) {
598
+ $data = array();
599
+ $meta = array();
600
+ $comments = array();
601
+ $terms = array();
602
+
603
+ foreach ( $node->childNodes as $child ) {
604
+ // We only care about child elements
605
+ if ( $child->nodeType !== XML_ELEMENT_NODE ) {
606
+ continue;
607
+ }
608
+
609
+ switch ( $child->tagName ) {
610
+ case 'wp:post_type':
611
+ $data['post_type'] = $child->textContent;
612
+ break;
613
+
614
+ case 'title':
615
+ $data['post_title'] = $child->textContent;
616
+ break;
617
+
618
+ case 'guid':
619
+ $data['guid'] = $child->textContent;
620
+ break;
621
+
622
+ case 'dc:creator':
623
+ $data['post_author'] = $child->textContent;
624
+ break;
625
+
626
+ case 'content:encoded':
627
+ $data['post_content'] = $child->textContent;
628
+ break;
629
+
630
+ case 'excerpt:encoded':
631
+ $data['post_excerpt'] = $child->textContent;
632
+ break;
633
+
634
+ case 'wp:post_id':
635
+ $data['post_id'] = $child->textContent;
636
+ break;
637
+
638
+ case 'wp:post_date':
639
+ $data['post_date'] = $child->textContent;
640
+ break;
641
+
642
+ case 'wp:post_date_gmt':
643
+ $data['post_date_gmt'] = $child->textContent;
644
+ break;
645
+
646
+ case 'wp:comment_status':
647
+ $data['comment_status'] = $child->textContent;
648
+ break;
649
+
650
+ case 'wp:ping_status':
651
+ $data['ping_status'] = $child->textContent;
652
+ break;
653
+
654
+ case 'wp:post_name':
655
+ $data['post_name'] = $child->textContent;
656
+ break;
657
+
658
+ case 'wp:status':
659
+ $data['post_status'] = $child->textContent;
660
+
661
+ if ( $data['post_status'] === 'auto-draft' ) {
662
+ // Bail now
663
+ return new WP_Error(
664
+ 'wxr_importer.post.cannot_import_draft',
665
+ __( 'Cannot import auto-draft posts' ),
666
+ $data
667
+ );
668
+ }
669
+ break;
670
+
671
+ case 'wp:post_parent':
672
+ $data['post_parent'] = $child->textContent;
673
+ break;
674
+
675
+ case 'wp:menu_order':
676
+ $data['menu_order'] = $child->textContent;
677
+ break;
678
+
679
+ case 'wp:post_password':
680
+ $data['post_password'] = $child->textContent;
681
+ break;
682
+
683
+ case 'wp:is_sticky':
684
+ $data['is_sticky'] = $child->textContent;
685
+ break;
686
+
687
+ case 'wp:attachment_url':
688
+ $data['attachment_url'] = $child->textContent;
689
+ break;
690
+
691
+ case 'wp:postmeta':
692
+ $meta_item = $this->parse_meta_node( $child );
693
+ if ( ! empty( $meta_item ) ) {
694
+ $meta[] = $meta_item;
695
+ }
696
+ break;
697
+
698
+ case 'wp:comment':
699
+ $comment_item = $this->parse_comment_node( $child );
700
+ if ( ! empty( $comment_item ) ) {
701
+ $comments[] = $comment_item;
702
+ }
703
+ break;
704
+
705
+ case 'category':
706
+ $term_item = $this->parse_category_node( $child );
707
+ if ( ! empty( $term_item ) ) {
708
+ $terms[] = $term_item;
709
+ }
710
+ break;
711
+ }// End switch().
712
+ }// End foreach().
713
+
714
+ return compact( 'data', 'meta', 'comments', 'terms' );
715
+ }
716
+
717
+ /**
718
+ * Create new posts based on import information
719
+ *
720
+ * Posts marked as having a parent which doesn't exist will become top level items.
721
+ * Doesn't create a new post if: the post type doesn't exist, the given post ID
722
+ * is already noted as imported or a post with the same title and date already exists.
723
+ * Note that new/updated terms, comments and meta are imported for the last of the above.
724
+ */
725
+ protected function process_post( $data, $meta, $comments, $terms ) {
726
+ /**
727
+ * Pre-process post data.
728
+ *
729
+ * @param array $data Post data. (Return empty to skip.)
730
+ * @param array $meta Meta data.
731
+ * @param array $comments Comments on the post.
732
+ * @param array $terms Terms on the post.
733
+ */
734
+ $data = apply_filters( 'wxr_importer.pre_process.post', $data, $meta, $comments, $terms );
735
+ if ( empty( $data ) ) {
736
+ return false;
737
+ }
738
+
739
+ $original_id = isset( $data['post_id'] ) ? (int) $data['post_id'] : 0;
740
+ $parent_id = isset( $data['post_parent'] ) ? (int) $data['post_parent'] : 0;
741
+ $author_id = isset( $data['post_author'] ) ? (int) $data['post_author'] : 0;
742
+
743
+ // Have we already processed this?
744
+ if ( isset( $this->mapping['post'][ $original_id ] ) ) {
745
+ return;
746
+ }
747
+
748
+ $post_type_object = get_post_type_object( $data['post_type'] );
749
+
750
+ // Is this type even valid?
751
+ if ( ! $post_type_object ) {
752
+ $this->logger->warning( sprintf(
753
+ __( 'Failed to import "%1$s": Invalid post type %2$s', 'wordpress-importer' ),
754
+ $data['post_title'],
755
+ $data['post_type']
756
+ ) );
757
+ return false;
758
+ }
759
+
760
+ $post_exists = $this->post_exists( $data );
761
+ if ( $post_exists ) {
762
+ $this->logger->info( sprintf(
763
+ __( '%1$s "%2$s" already exists.', 'wordpress-importer' ),
764
+ $post_type_object->labels->singular_name,
765
+ $data['post_title']
766
+ ) );
767
+
768
+ /**
769
+ * Post processing already imported.
770
+ *
771
+ * @param array $data Raw data imported for the post.
772
+ */
773
+ do_action( 'wxr_importer.process_already_imported.post', $data );
774
+
775
+ // Even though this post already exists, new comments might need importing
776
+ $this->process_comments( $comments, $original_id, $data, $post_exists );
777
+
778
+ return false;
779
+ }
780
+
781
+ // Map the parent post, or mark it as one we need to fix
782
+ $requires_remapping = false;
783
+ if ( $parent_id ) {
784
+ if ( isset( $this->mapping['post'][ $parent_id ] ) ) {
785
+ $data['post_parent'] = $this->mapping['post'][ $parent_id ];
786
+ } else {
787
+ $meta[] = array(
788
+ 'key' => '_wxr_import_parent',
789
+ 'value' => $parent_id,
790
+ );
791
+ $requires_remapping = true;
792
+
793
+ $data['post_parent'] = 0;
794
+ }
795
+ }
796
+
797
+ // Map the author, or mark it as one we need to fix
798
+ $author = sanitize_user( $data['post_author'], true );
799
+ if ( empty( $author ) ) {
800
+ // Missing or invalid author, use default if available.
801
+ $data['post_author'] = $this->options['default_author'];
802
+ } elseif ( isset( $this->mapping['user_slug'][ $author ] ) ) {
803
+ $data['post_author'] = $this->mapping['user_slug'][ $author ];
804
+ } else {
805
+ $meta[] = array(
806
+ 'key' => '_wxr_import_user_slug',
807
+ 'value' => $author,
808
+ );
809
+ $requires_remapping = true;
810
+
811
+ $data['post_author'] = (int) get_current_user_id();
812
+ }
813
+
814
+ // Does the post look like it contains attachment images?
815
+ if ( preg_match( self::REGEX_HAS_ATTACHMENT_REFS, $data['post_content'] ) ) {
816
+ $meta[] = array(
817
+ 'key' => '_wxr_import_has_attachment_refs',
818
+ 'value' => true,
819
+ );
820
+ $requires_remapping = true;
821
+ }
822
+
823
+ // Whitelist to just the keys we allow
824
+ $postdata = array(
825
+ 'import_id' => $data['post_id'],
826
+ );
827
+ $allowed = array(
828
+ 'post_author' => true,
829
+ 'post_date' => true,
830
+ 'post_date_gmt' => true,
831
+ 'post_content' => true,
832
+ 'post_excerpt' => true,
833
+ 'post_title' => true,
834
+ 'post_status' => true,
835
+ 'post_name' => true,
836
+ 'comment_status' => true,
837
+ 'ping_status' => true,
838
+ 'guid' => true,
839
+ 'post_parent' => true,
840
+ 'menu_order' => true,
841
+ 'post_type' => true,
842
+ 'post_password' => true,
843
+ );
844
+ foreach ( $data as $key => $value ) {
845
+ if ( ! isset( $allowed[ $key ] ) ) {
846
+ continue;
847
+ }
848
+
849
+ $postdata[ $key ] = $data[ $key ];
850
+ }
851
+
852
+ $postdata = apply_filters( 'wp_import_post_data_processed', $postdata, $data );
853
+
854
+ if ( 'attachment' === $postdata['post_type'] ) {
855
+ if ( ! $this->options['fetch_attachments'] ) {
856
+ $this->logger->notice( sprintf(
857
+ __( 'Skipping attachment "%s", fetching attachments disabled' ),
858
+ $data['post_title']
859
+ ) );
860
+ /**
861
+ * Post processing skipped.
862
+ *
863
+ * @param array $data Raw data imported for the post.
864
+ * @param array $meta Raw meta data, already processed by {@see process_post_meta}.
865
+ */
866
+ do_action( 'wxr_importer.process_skipped.post', $data, $meta );
867
+ return false;
868
+ }
869
+ $remote_url = ! empty( $data['attachment_url'] ) ? $data['attachment_url'] : $data['guid'];
870
+ $post_id = $this->process_attachment( $postdata, $meta, $remote_url );
871
+ } else {
872
+ $post_id = wp_insert_post( $postdata, true );
873
+ do_action( 'wp_import_insert_post', $post_id, $original_id, $postdata, $data );
874
+ }
875
+
876
+ if ( is_wp_error( $post_id ) ) {
877
+ $this->logger->error( sprintf(
878
+ __( 'Failed to import "%1$s" (%2$s)', 'wordpress-importer' ),
879
+ $data['post_title'],
880
+ $post_type_object->labels->singular_name
881
+ ) );
882
+ $this->logger->debug( $post_id->get_error_message() );
883
+
884
+ /**
885
+ * Post processing failed.
886
+ *
887
+ * @param WP_Error $post_id Error object.
888
+ * @param array $data Raw data imported for the post.
889
+ * @param array $meta Raw meta data, already processed by {@see process_post_meta}.
890
+ * @param array $comments Raw comment data, already processed by {@see process_comments}.
891
+ * @param array $terms Raw term data, already processed.
892
+ */
893
+ do_action( 'wxr_importer.process_failed.post', $post_id, $data, $meta, $comments, $terms );
894
+ return false;
895
+ }
896
+
897
+ // Ensure stickiness is handled correctly too
898
+ if ( $data['is_sticky'] === '1' ) {
899
+ stick_post( $post_id );
900
+ }
901
+
902
+ // map pre-import ID to local ID
903
+ $this->mapping['post'][ $original_id ] = (int) $post_id;
904
+ if ( $requires_remapping ) {
905
+ $this->requires_remapping['post'][ $post_id ] = true;
906
+ }
907
+ $this->mark_post_exists( $data, $post_id );
908
+
909
+ $this->logger->info( sprintf(
910
+ __( 'Imported "%1$s" (%2$s)', 'wordpress-importer' ),
911
+ $data['post_title'],
912
+ $post_type_object->labels->singular_name
913
+ ) );
914
+ $this->logger->debug( sprintf(
915
+ __( 'Post %1$d remapped to %2$d', 'wordpress-importer' ),
916
+ $original_id,
917
+ $post_id
918
+ ) );
919
+
920
+ // Handle the terms too
921
+ $terms = apply_filters( 'wp_import_post_terms', $terms, $post_id, $data );
922
+
923
+ if ( ! empty( $terms ) ) {
924
+ $term_ids = array();
925
+ foreach ( $terms as $term ) {
926
+ $taxonomy = $term['taxonomy'];
927
+ $key = sha1( $taxonomy . ':' . $term['slug'] );
928
+
929
+ if ( isset( $this->mapping['term'][ $key ] ) ) {
930
+ $term_ids[ $taxonomy ][] = (int) $this->mapping['term'][ $key ];
931
+ } else {
932
+ $meta[] = array(
933
+ 'key' => '_wxr_import_term',
934
+ 'value' => $term,
935
+ );
936
+ $requires_remapping = true;
937
+ }
938
+ }
939
+
940
+ foreach ( $term_ids as $tax => $ids ) {
941
+ $tt_ids = wp_set_post_terms( $post_id, $ids, $tax );
942
+ do_action( 'wp_import_set_post_terms', $tt_ids, $ids, $tax, $post_id, $data );
943
+ }
944
+ }
945
+
946
+ $this->process_comments( $comments, $post_id, $data );
947
+ $this->process_post_meta( $meta, $post_id, $data );
948
+
949
+ if ( 'nav_menu_item' === $data['post_type'] ) {
950
+ $this->process_menu_item_meta( $post_id, $data, $meta );
951
+ }
952
+
953
+ /**
954
+ * Post processing completed.
955
+ *
956
+ * @param int $post_id New post ID.
957
+ * @param array $data Raw data imported for the post.
958
+ * @param array $meta Raw meta data, already processed by {@see process_post_meta}.
959
+ * @param array $comments Raw comment data, already processed by {@see process_comments}.
960
+ * @param array $terms Raw term data, already processed.
961
+ */
962
+ do_action( 'wxr_importer.processed.post', $post_id, $data, $meta, $comments, $terms );
963
+ }
964
+
965
+ /**
966
+ * Attempt to create a new menu item from import data
967
+ *
968
+ * Fails for draft, orphaned menu items and those without an associated nav_menu
969
+ * or an invalid nav_menu term. If the post type or term object which the menu item
970
+ * represents doesn't exist then the menu item will not be imported (waits until the
971
+ * end of the import to retry again before discarding).
972
+ *
973
+ * @param array $item Menu item details from WXR file
974
+ */
975
+ protected function process_menu_item_meta( $post_id, $data, $meta ) {
976
+
977
+ $item_type = get_post_meta( $post_id, '_menu_item_type', true );
978
+ $original_object_id = get_post_meta( $post_id, '_menu_item_object_id', true );
979
+ $object_id = null;
980
+
981
+ $this->logger->debug( sprintf( 'Processing menu item %s', $item_type ) );
982
+
983
+ $requires_remapping = false;
984
+ switch ( $item_type ) {
985
+ case 'taxonomy':
986
+ if ( isset( $this->mapping['term_id'][ $original_object_id ] ) ) {
987
+ $object_id = $this->mapping['term_id'][ $original_object_id ];
988
+ } else {
989
+ add_post_meta( $post_id, '_wxr_import_menu_item', wp_slash( $original_object_id ) );
990
+ $requires_remapping = true;
991
+ }
992
+ break;
993
+
994
+ case 'post_type':
995
+ if ( isset( $this->mapping['post'][ $original_object_id ] ) ) {
996
+ $object_id = $this->mapping['post'][ $original_object_id ];
997
+ } else {
998
+ add_post_meta( $post_id, '_wxr_import_menu_item', wp_slash( $original_object_id ) );
999
+ $requires_remapping = true;
1000
+ }
1001
+ break;
1002
+
1003
+ case 'custom':
1004
+ // Custom refers to itself, wonderfully easy.
1005
+ $object_id = $post_id;
1006
+ break;
1007
+
1008
+ default:
1009
+ // associated object is missing or not imported yet, we'll retry later
1010
+ $this->missing_menu_items[] = $item;
1011
+ $this->logger->debug( 'Unknown menu item type' );
1012
+ break;
1013
+ }
1014
+
1015
+ if ( $requires_remapping ) {
1016
+ $this->requires_remapping['post'][ $post_id ] = true;
1017
+ }
1018
+
1019
+ if ( empty( $object_id ) ) {
1020
+ // Nothing needed here.
1021
+ return;
1022
+ }
1023
+
1024
+ $this->logger->debug( sprintf( 'Menu item %d mapped to %d', $original_object_id, $object_id ) );
1025
+ update_post_meta( $post_id, '_menu_item_object_id', wp_slash( $object_id ) );
1026
+ }
1027
+
1028
+ /**
1029
+ * If fetching attachments is enabled then attempt to create a new attachment
1030
+ *
1031
+ * @param array $post Attachment post details from WXR
1032
+ * @param string $url URL to fetch attachment from
1033
+ * @return int|WP_Error Post ID on success, WP_Error otherwise
1034
+ */
1035
+ protected function process_attachment( $post, $meta, $remote_url ) {
1036
+ // try to use _wp_attached file for upload folder placement to ensure the same location as the export site
1037
+ // e.g. location is 2003/05/image.jpg but the attachment post_date is 2010/09, see media_handle_upload()
1038
+ $post['upload_date'] = $post['post_date'];
1039
+ foreach ( $meta as $meta_item ) {
1040
+ if ( $meta_item['key'] !== '_wp_attached_file' ) {
1041
+ continue;
1042
+ }
1043
+
1044
+ if ( preg_match( '%^[0-9]{4}/[0-9]{2}%', $meta_item['value'], $matches ) ) {
1045
+ $post['upload_date'] = $matches[0];
1046
+ }
1047
+ break;
1048
+ }
1049
+
1050
+ // if the URL is absolute, but does not contain address, then upload it assuming base_site_url
1051
+ if ( preg_match( '|^/[\w\W]+$|', $remote_url ) ) {
1052
+ $remote_url = rtrim( $this->base_url, '/' ) . $remote_url;
1053
+ }
1054
+
1055
+ $upload = $this->fetch_remote_file( $remote_url, $post );
1056
+ if ( is_wp_error( $upload ) ) {
1057
+ return $upload;
1058
+ }
1059
+
1060
+ $info = wp_check_filetype( $upload['file'] );
1061
+ if ( ! $info ) {
1062
+ return new WP_Error( 'attachment_processing_error', __( 'Invalid file type', 'wordpress-importer' ) );
1063
+ }
1064
+
1065
+ $post['post_mime_type'] = $info['type'];
1066
+
1067
+ // WP really likes using the GUID for display. Allow updating it.
1068
+ // See https://core.trac.wordpress.org/ticket/33386
1069
+ if ( $this->options['update_attachment_guids'] ) {
1070
+ $post['guid'] = $upload['url'];
1071
+ }
1072
+
1073
+ // as per wp-admin/includes/upload.php
1074
+ $post_id = wp_insert_attachment( $post, $upload['file'] );
1075
+ if ( is_wp_error( $post_id ) ) {
1076
+ return $post_id;
1077
+ }
1078
+
1079
+ $attachment_metadata = wp_generate_attachment_metadata( $post_id, $upload['file'] );
1080
+ wp_update_attachment_metadata( $post_id, $attachment_metadata );
1081
+
1082
+ // Map this image URL later if we need to
1083
+ $this->url_remap[ $remote_url ] = $upload['url'];
1084
+
1085
+ // If we have a HTTPS URL, ensure the HTTP URL gets replaced too
1086
+ if ( substr( $remote_url, 0, 8 ) === 'https://' ) {
1087
+ $insecure_url = 'http' . substr( $remote_url, 5 );
1088
+ $this->url_remap[ $insecure_url ] = $upload['url'];
1089
+ }
1090
+
1091
+ if ( $this->options['aggressive_url_search'] ) {
1092
+ // remap resized image URLs, works by stripping the extension and remapping the URL stub.
1093
+ /*
1094
+ if ( preg_match( '!^image/!', $info['type'] ) ) {
1095
+ $parts = pathinfo( $remote_url );
1096
+ $name = basename( $parts['basename'], ".{$parts['extension']}" ); // PATHINFO_FILENAME in PHP 5.2
1097
+
1098
+ $parts_new = pathinfo( $upload['url'] );
1099
+ $name_new = basename( $parts_new['basename'], ".{$parts_new['extension']}" );
1100
+
1101
+ $this->url_remap[$parts['dirname'] . '/' . $name] = $parts_new['dirname'] . '/' . $name_new;
1102
+ }*/
1103
+ }
1104
+
1105
+ return $post_id;
1106
+ }
1107
+
1108
+ /**
1109
+ * Parse a meta node into meta data.
1110
+ *
1111
+ * @param DOMElement $node Parent node of meta data (typically `wp:postmeta` or `wp:commentmeta`).
1112
+ * @return array|null Meta data array on success, or null on error.
1113
+ */
1114
+ protected function parse_meta_node( $node ) {
1115
+ foreach ( $node->childNodes as $child ) {
1116
+ // We only care about child elements
1117
+ if ( $child->nodeType !== XML_ELEMENT_NODE ) {
1118
+ continue;
1119
+ }
1120
+
1121
+ switch ( $child->tagName ) {
1122
+ case 'wp:meta_key':
1123
+ $key = $child->textContent;
1124
+ break;
1125
+
1126
+ case 'wp:meta_value':
1127
+ $value = $child->textContent;
1128
+ break;
1129
+ }
1130
+ }
1131
+
1132
+ if ( empty( $key ) || empty( $value ) ) {
1133
+ return null;
1134
+ }
1135
+
1136
+ return compact( 'key', 'value' );
1137
+ }
1138
+
1139
+ /**
1140
+ * Process and import post meta items.
1141
+ *
1142
+ * @param array $meta List of meta data arrays
1143
+ * @param int $post_id Post to associate with
1144
+ * @param array $post Post data
1145
+ * @return int|WP_Error Number of meta items imported on success, error otherwise.
1146
+ */
1147
+ protected function process_post_meta( $meta, $post_id, $post ) {
1148
+ if ( empty( $meta ) ) {
1149
+ return true;
1150
+ }
1151
+
1152
+ foreach ( $meta as $meta_item ) {
1153
+ /**
1154
+ * Pre-process post meta data.
1155
+ *
1156
+ * @param array $meta_item Meta data. (Return empty to skip.)
1157
+ * @param int $post_id Post the meta is attached to.
1158
+ */
1159
+ $meta_item = apply_filters( 'wxr_importer.pre_process.post_meta', $meta_item, $post_id );
1160
+ if ( empty( $meta_item ) ) {
1161
+ return false;
1162
+ }
1163
+
1164
+ $key = apply_filters( 'import_post_meta_key', $meta_item['key'], $post_id, $post );
1165
+ $value = false;
1166
+
1167
+ if ( '_edit_last' === $key ) {
1168
+ $value = intval( $meta_item['value'] );
1169
+ if ( ! isset( $this->mapping['user'][ $value ] ) ) {
1170
+ // Skip!
1171
+ continue;
1172
+ }
1173
+
1174
+ $value = $this->mapping['user'][ $value ];
1175
+ }
1176
+
1177
+ if ( $key ) {
1178
+ // export gets meta straight from the DB so could have a serialized string
1179
+ if ( ! $value ) {
1180
+ $value = maybe_unserialize( $meta_item['value'] );
1181
+ }
1182
+
1183
+ add_post_meta( $post_id, $key, $value );
1184
+ do_action( 'import_post_meta', $post_id, $key, $value );
1185
+
1186
+ // if the post has a featured image, take note of this in case of remap
1187
+ if ( '_thumbnail_id' === $key ) {
1188
+ $this->featured_images[ $post_id ] = (int) $value;
1189
+ }
1190
+ }
1191
+ }// End foreach().
1192
+
1193
+ return true;
1194
+ }
1195
+
1196
+ /**
1197
+ * Parse a comment node into comment data.
1198
+ *
1199
+ * @param DOMElement $node Parent node of comment data (typically `wp:comment`).
1200
+ * @return array Comment data array.
1201
+ */
1202
+ protected function parse_comment_node( $node ) {
1203
+ $data = array(
1204
+ 'commentmeta' => array(),
1205
+ );
1206
+
1207
+ foreach ( $node->childNodes as $child ) {
1208
+ // We only care about child elements
1209
+ if ( $child->nodeType !== XML_ELEMENT_NODE ) {
1210
+ continue;
1211
+ }
1212
+
1213
+ switch ( $child->tagName ) {
1214
+ case 'wp:comment_id':
1215
+ $data['comment_id'] = $child->textContent;
1216
+ break;
1217
+ case 'wp:comment_author':
1218
+ $data['comment_author'] = $child->textContent;
1219
+ break;
1220
+
1221
+ case 'wp:comment_author_email':
1222
+ $data['comment_author_email'] = $child->textContent;
1223
+ break;
1224
+
1225
+ case 'wp:comment_author_IP':
1226
+ $data['comment_author_IP'] = $child->textContent;
1227
+ break;
1228
+
1229
+ case 'wp:comment_author_url':
1230
+ $data['comment_author_url'] = $child->textContent;
1231
+ break;
1232
+
1233
+ case 'wp:comment_user_id':
1234
+ $data['comment_user_id'] = $child->textContent;
1235
+ break;
1236
+
1237
+ case 'wp:comment_date':
1238
+ $data['comment_date'] = $child->textContent;
1239
+ break;
1240
+
1241
+ case 'wp:comment_date_gmt':
1242
+ $data['comment_date_gmt'] = $child->textContent;
1243
+ break;
1244
+
1245
+ case 'wp:comment_content':
1246
+ $data['comment_content'] = $child->textContent;
1247
+ break;
1248
+
1249
+ case 'wp:comment_approved':
1250
+ $data['comment_approved'] = $child->textContent;
1251
+ break;
1252
+
1253
+ case 'wp:comment_type':
1254
+ $data['comment_type'] = $child->textContent;
1255
+ break;
1256
+
1257
+ case 'wp:comment_parent':
1258
+ $data['comment_parent'] = $child->textContent;
1259
+ break;
1260
+
1261
+ case 'wp:commentmeta':
1262
+ $meta_item = $this->parse_meta_node( $child );
1263
+ if ( ! empty( $meta_item ) ) {
1264
+ $data['commentmeta'][] = $meta_item;
1265
+ }
1266
+ break;
1267
+ }// End switch().
1268
+ }// End foreach().
1269
+
1270
+ return $data;
1271
+ }
1272
+
1273
+ /**
1274
+ * Process and import comment data.
1275
+ *
1276
+ * @param array $comments List of comment data arrays.
1277
+ * @param int $post_id Post to associate with.
1278
+ * @param array $post Post data.
1279
+ * @return int|WP_Error Number of comments imported on success, error otherwise.
1280
+ */
1281
+ protected function process_comments( $comments, $post_id, $post, $post_exists = false ) {
1282
+
1283
+ $comments = apply_filters( 'wp_import_post_comments', $comments, $post_id, $post );
1284
+ if ( empty( $comments ) ) {
1285
+ return 0;
1286
+ }
1287
+
1288
+ $num_comments = 0;
1289
+
1290
+ // Sort by ID to avoid excessive remapping later
1291
+ usort( $comments, array( $this, 'sort_comments_by_id' ) );
1292
+
1293
+ foreach ( $comments as $key => $comment ) {
1294
+ /**
1295
+ * Pre-process comment data
1296
+ *
1297
+ * @param array $comment Comment data. (Return empty to skip.)
1298
+ * @param int $post_id Post the comment is attached to.
1299
+ */
1300
+ $comment = apply_filters( 'wxr_importer.pre_process.comment', $comment, $post_id );
1301
+ if ( empty( $comment ) ) {
1302
+ return false;
1303
+ }
1304
+
1305
+ $original_id = isset( $comment['comment_id'] ) ? (int) $comment['comment_id'] : 0;
1306
+ $parent_id = isset( $comment['comment_parent'] ) ? (int) $comment['comment_parent'] : 0;
1307
+ $author_id = isset( $comment['comment_user_id'] ) ? (int) $comment['comment_user_id'] : 0;
1308
+
1309
+ // if this is a new post we can skip the comment_exists() check
1310
+ // TODO: Check comment_exists for performance
1311
+ if ( $post_exists ) {
1312
+ $existing = $this->comment_exists( $comment );
1313
+ if ( $existing ) {
1314
+
1315
+ /**
1316
+ * Comment processing already imported.
1317
+ *
1318
+ * @param array $comment Raw data imported for the comment.
1319
+ */
1320
+ do_action( 'wxr_importer.process_already_imported.comment', $comment );
1321
+
1322
+ $this->mapping['comment'][ $original_id ] = $existing;
1323
+ continue;
1324
+ }
1325
+ }
1326
+
1327
+ // Remove meta from the main array
1328
+ $meta = isset( $comment['commentmeta'] ) ? $comment['commentmeta'] : array();
1329
+ unset( $comment['commentmeta'] );
1330
+
1331
+ // Map the parent comment, or mark it as one we need to fix
1332
+ $requires_remapping = false;
1333
+ if ( $parent_id ) {
1334
+ if ( isset( $this->mapping['comment'][ $parent_id ] ) ) {
1335
+ $comment['comment_parent'] = $this->mapping['comment'][ $parent_id ];
1336
+ } else {
1337
+ // Prepare for remapping later
1338
+ $meta[] = array(
1339
+ 'key' => '_wxr_import_parent',
1340
+ 'value' => $parent_id,
1341
+ );
1342
+ $requires_remapping = true;
1343
+
1344
+ // Wipe the parent for now
1345
+ $comment['comment_parent'] = 0;
1346
+ }
1347
+ }
1348
+
1349
+ // Map the author, or mark it as one we need to fix
1350
+ if ( $author_id ) {
1351
+ if ( isset( $this->mapping['user'][ $author_id ] ) ) {
1352
+ $comment['user_id'] = $this->mapping['user'][ $author_id ];
1353
+ } else {
1354
+ // Prepare for remapping later
1355
+ $meta[] = array(
1356
+ 'key' => '_wxr_import_user',
1357
+ 'value' => $author_id,
1358
+ );
1359
+ $requires_remapping = true;
1360
+
1361
+ // Wipe the user for now
1362
+ $comment['user_id'] = 0;
1363
+ }
1364
+ }
1365
+
1366
+ // Run standard core filters
1367
+ $comment['comment_post_ID'] = $post_id;
1368
+ $comment = wp_filter_comment( $comment );
1369
+
1370
+ // wp_insert_comment expects slashed data
1371
+ $comment_id = wp_insert_comment( wp_slash( $comment ) );
1372
+ $this->mapping['comment'][ $original_id ] = $comment_id;
1373
+ if ( $requires_remapping ) {
1374
+ $this->requires_remapping['comment'][ $comment_id ] = true;
1375
+ }
1376
+ $this->mark_comment_exists( $comment, $comment_id );
1377
+
1378
+ /**
1379
+ * Comment has been imported.
1380
+ *
1381
+ * @param int $comment_id New comment ID
1382
+ * @param array $comment Comment inserted (`comment_id` item refers to the original ID)
1383
+ * @param int $post_id Post parent of the comment
1384
+ * @param array $post Post data
1385
+ */
1386
+ do_action( 'wp_import_insert_comment', $comment_id, $comment, $post_id, $post );
1387
+
1388
+ // Process the meta items
1389
+ foreach ( $meta as $meta_item ) {
1390
+ $value = maybe_unserialize( $meta_item['value'] );
1391
+ add_comment_meta( $comment_id, wp_slash( $meta_item['key'] ), wp_slash( $value ) );
1392
+ }
1393
+
1394
+ /**
1395
+ * Post processing completed.
1396
+ *
1397
+ * @param int $post_id New post ID.
1398
+ * @param array $comment Raw data imported for the comment.
1399
+ * @param array $meta Raw meta data, already processed by {@see process_post_meta}.
1400
+ * @param array $post_id Parent post ID.
1401
+ */
1402
+ do_action( 'wxr_importer.processed.comment', $comment_id, $comment, $meta, $post_id );
1403
+
1404
+ $num_comments++;
1405
+ }// End foreach().
1406
+
1407
+ return $num_comments;
1408
+ }
1409
+
1410
+ protected function parse_category_node( $node ) {
1411
+ $data = array(
1412
+ // Default taxonomy to "category", since this is a `<category>` tag
1413
+ 'taxonomy' => 'category',
1414
+ );
1415
+ $meta = array();
1416
+
1417
+ if ( $node->hasAttribute( 'domain' ) ) {
1418
+ $data['taxonomy'] = $node->getAttribute( 'domain' );
1419
+ }
1420
+ if ( $node->hasAttribute( 'nicename' ) ) {
1421
+ $data['slug'] = $node->getAttribute( 'nicename' );
1422
+ }
1423
+
1424
+ $data['name'] = $node->textContent;
1425
+
1426
+ if ( empty( $data['slug'] ) ) {
1427
+ return null;
1428
+ }
1429
+
1430
+ // Just for extra compatibility
1431
+ if ( $data['taxonomy'] === 'tag' ) {
1432
+ $data['taxonomy'] = 'post_tag';
1433
+ }
1434
+
1435
+ return $data;
1436
+ }
1437
+
1438
+ /**
1439
+ * Callback for `usort` to sort comments by ID
1440
+ *
1441
+ * @param array $a Comment data for the first comment
1442
+ * @param array $b Comment data for the second comment
1443
+ * @return int
1444
+ */
1445
+ public static function sort_comments_by_id( $a, $b ) {
1446
+ if ( empty( $a['comment_id'] ) ) {
1447
+ return 1;
1448
+ }
1449
+
1450
+ if ( empty( $b['comment_id'] ) ) {
1451
+ return -1;
1452
+ }
1453
+
1454
+ return $a['comment_id'] - $b['comment_id'];
1455
+ }
1456
+
1457
+ protected function parse_author_node( $node ) {
1458
+ $data = array();
1459
+ $meta = array();
1460
+ foreach ( $node->childNodes as $child ) {
1461
+ // We only care about child elements
1462
+ if ( $child->nodeType !== XML_ELEMENT_NODE ) {
1463
+ continue;
1464
+ }
1465
+
1466
+ switch ( $child->tagName ) {
1467
+ case 'wp:author_login':
1468
+ $data['user_login'] = $child->textContent;
1469
+ break;
1470
+
1471
+ case 'wp:author_id':
1472
+ $data['ID'] = $child->textContent;
1473
+ break;
1474
+
1475
+ case 'wp:author_email':
1476
+ $data['user_email'] = $child->textContent;
1477
+ break;
1478
+
1479
+ case 'wp:author_display_name':
1480
+ $data['display_name'] = $child->textContent;
1481
+ break;
1482
+
1483
+ case 'wp:author_first_name':
1484
+ $data['first_name'] = $child->textContent;
1485
+ break;
1486
+
1487
+ case 'wp:author_last_name':
1488
+ $data['last_name'] = $child->textContent;
1489
+ break;
1490
+ }
1491
+ }
1492
+
1493
+ return compact( 'data', 'meta' );
1494
+ }
1495
+
1496
+ protected function process_author( $data, $meta ) {
1497
+ /**
1498
+ * Pre-process user data.
1499
+ *
1500
+ * @param array $data User data. (Return empty to skip.)
1501
+ * @param array $meta Meta data.
1502
+ */
1503
+ $data = apply_filters( 'wxr_importer.pre_process.user', $data, $meta );
1504
+ if ( empty( $data ) ) {
1505
+ return false;
1506
+ }
1507
+
1508
+ // Have we already handled this user?
1509
+ $original_id = isset( $data['ID'] ) ? $data['ID'] : 0;
1510
+ $original_slug = $data['user_login'];
1511
+
1512
+ if ( isset( $this->mapping['user'][ $original_id ] ) ) {
1513
+ $existing = $this->mapping['user'][ $original_id ];
1514
+
1515
+ // Note the slug mapping if we need to too
1516
+ if ( ! isset( $this->mapping['user_slug'][ $original_slug ] ) ) {
1517
+ $this->mapping['user_slug'][ $original_slug ] = $existing;
1518
+ }
1519
+
1520
+ return false;
1521
+ }
1522
+
1523
+ if ( isset( $this->mapping['user_slug'][ $original_slug ] ) ) {
1524
+ $existing = $this->mapping['user_slug'][ $original_slug ];
1525
+
1526
+ // Ensure we note the mapping too
1527
+ $this->mapping['user'][ $original_id ] = $existing;
1528
+
1529
+ return false;
1530
+ }
1531
+
1532
+ // Allow overriding the user's slug
1533
+ $login = $original_slug;
1534
+ if ( isset( $this->user_slug_override[ $login ] ) ) {
1535
+ $login = $this->user_slug_override[ $login ];
1536
+ }
1537
+
1538
+ $userdata = array(
1539
+ 'user_login' => sanitize_user( $login, true ),
1540
+ 'user_pass' => wp_generate_password(),
1541
+ );
1542
+
1543
+ $allowed = array(
1544
+ 'user_email' => true,
1545
+ 'display_name' => true,
1546
+ 'first_name' => true,
1547
+ 'last_name' => true,
1548
+ );
1549
+ foreach ( $data as $key => $value ) {
1550
+ if ( ! isset( $allowed[ $key ] ) ) {
1551
+ continue;
1552
+ }
1553
+
1554
+ $userdata[ $key ] = $data[ $key ];
1555
+ }
1556
+
1557
+ $user_id = wp_insert_user( wp_slash( $userdata ) );
1558
+ if ( is_wp_error( $user_id ) ) {
1559
+ $this->logger->error( sprintf(
1560
+ __( 'Failed to import user "%s"', 'wordpress-importer' ),
1561
+ $userdata['user_login']
1562
+ ) );
1563
+ $this->logger->debug( $user_id->get_error_message() );
1564
+
1565
+ /**
1566
+ * User processing failed.
1567
+ *
1568
+ * @param WP_Error $user_id Error object.
1569
+ * @param array $userdata Raw data imported for the user.
1570
+ */
1571
+ do_action( 'wxr_importer.process_failed.user', $user_id, $userdata );
1572
+ return false;
1573
+ }
1574
+
1575
+ if ( $original_id ) {
1576
+ $this->mapping['user'][ $original_id ] = $user_id;
1577
+ }
1578
+ $this->mapping['user_slug'][ $original_slug ] = $user_id;
1579
+
1580
+ $this->logger->info( sprintf(
1581
+ __( 'Imported user "%s"', 'wordpress-importer' ),
1582
+ $userdata['user_login']
1583
+ ) );
1584
+ $this->logger->debug( sprintf(
1585
+ __( 'User %1$d remapped to %2$d', 'wordpress-importer' ),
1586
+ $original_id,
1587
+ $user_id
1588
+ ) );
1589
+
1590
+ // TODO: Implement meta handling once WXR includes it
1591
+ /**
1592
+ * User processing completed.
1593
+ *
1594
+ * @param int $user_id New user ID.
1595
+ * @param array $userdata Raw data imported for the user.
1596
+ */
1597
+ do_action( 'wxr_importer.processed.user', $user_id, $userdata );
1598
+ }
1599
+
1600
+ protected function parse_term_node( $node, $type = 'term' ) {
1601
+ $data = array();
1602
+ $meta = array();
1603
+
1604
+ $tag_name = array(
1605
+ 'id' => 'wp:term_id',
1606
+ 'taxonomy' => 'wp:term_taxonomy',
1607
+ 'slug' => 'wp:term_slug',
1608
+ 'parent' => 'wp:term_parent',
1609
+ 'name' => 'wp:term_name',
1610
+ 'description' => 'wp:term_description',
1611
+ );
1612
+ $taxonomy = null;
1613
+
1614
+ // Special casing!
1615
+ switch ( $type ) {
1616
+ case 'category':
1617
+ $tag_name['slug'] = 'wp:category_nicename';
1618
+ $tag_name['parent'] = 'wp:category_parent';
1619
+ $tag_name['name'] = 'wp:cat_name';
1620
+ $tag_name['description'] = 'wp:category_description';
1621
+ $tag_name['taxonomy'] = null;
1622
+
1623
+ $data['taxonomy'] = 'category';
1624
+ break;
1625
+
1626
+ case 'tag':
1627
+ $tag_name['slug'] = 'wp:tag_slug';
1628
+ $tag_name['parent'] = null;
1629
+ $tag_name['name'] = 'wp:tag_name';
1630
+ $tag_name['description'] = 'wp:tag_description';
1631
+ $tag_name['taxonomy'] = null;
1632
+
1633
+ $data['taxonomy'] = 'post_tag';
1634
+ break;
1635
+ }
1636
+
1637
+ foreach ( $node->childNodes as $child ) {
1638
+ // We only care about child elements
1639
+ if ( $child->nodeType !== XML_ELEMENT_NODE ) {
1640
+ continue;
1641
+ }
1642
+
1643
+ $key = array_search( $child->tagName, $tag_name );
1644
+ if ( $key ) {
1645
+ $data[ $key ] = $child->textContent;
1646
+ }
1647
+ }
1648
+
1649
+ if ( empty( $data['taxonomy'] ) ) {
1650
+ return null;
1651
+ }
1652
+
1653
+ // Compatibility with WXR 1.0
1654
+ if ( $data['taxonomy'] === 'tag' ) {
1655
+ $data['taxonomy'] = 'post_tag';
1656
+ }
1657
+
1658
+ return compact( 'data', 'meta' );
1659
+ }
1660
+
1661
+ protected function process_term( $data, $meta ) {
1662
+ /**
1663
+ * Pre-process term data.
1664
+ *
1665
+ * @param array $data Term data. (Return empty to skip.)
1666
+ * @param array $meta Meta data.
1667
+ */
1668
+ $data = apply_filters( 'wxr_importer.pre_process.term', $data, $meta );
1669
+ if ( empty( $data ) ) {
1670
+ return false;
1671
+ }
1672
+
1673
+ $original_id = isset( $data['id'] ) ? (int) $data['id'] : 0;
1674
+ $parent_id = isset( $data['parent'] ) ? (int) $data['parent'] : 0;
1675
+
1676
+ $mapping_key = sha1( $data['taxonomy'] . ':' . $data['slug'] );
1677
+ $existing = $this->term_exists( $data );
1678
+ if ( $existing ) {
1679
+
1680
+ /**
1681
+ * Term processing already imported.
1682
+ *
1683
+ * @param array $data Raw data imported for the term.
1684
+ */
1685
+ do_action( 'wxr_importer.process_already_imported.term', $data );
1686
+
1687
+ $this->mapping['term'][ $mapping_key ] = $existing;
1688
+ $this->mapping['term_id'][ $original_id ] = $existing;
1689
+ return false;
1690
+ }
1691
+
1692
+ // WP really likes to repeat itself in export files
1693
+ if ( isset( $this->mapping['term'][ $mapping_key ] ) ) {
1694
+ return false;
1695
+ }
1696
+
1697
+ $termdata = array();
1698
+ $allowed = array(
1699
+ 'slug' => true,
1700
+ 'description' => true,
1701
+ );
1702
+
1703
+ // Map the parent comment, or mark it as one we need to fix
1704
+ // TODO: add parent mapping and remapping
1705
+ /*
1706
+ $requires_remapping = false;
1707
+ if ( $parent_id ) {
1708
+ if ( isset( $this->mapping['term'][ $parent_id ] ) ) {
1709
+ $data['parent'] = $this->mapping['term'][ $parent_id ];
1710
+ } else {
1711
+ // Prepare for remapping later
1712
+ $meta[] = array( 'key' => '_wxr_import_parent', 'value' => $parent_id );
1713
+ $requires_remapping = true;
1714
+
1715
+ // Wipe the parent for now
1716
+ $data['parent'] = 0;
1717
+ }
1718
+ }*/
1719
+
1720
+ foreach ( $data as $key => $value ) {
1721
+ if ( ! isset( $allowed[ $key ] ) ) {
1722
+ continue;
1723
+ }
1724
+
1725
+ $termdata[ $key ] = $data[ $key ];
1726
+ }
1727
+
1728
+ $result = wp_insert_term( $data['name'], $data['taxonomy'], $termdata );
1729
+ if ( is_wp_error( $result ) ) {
1730
+ $this->logger->warning( sprintf(
1731
+ __( 'Failed to import %1$s %2$s', 'wordpress-importer' ),
1732
+ $data['taxonomy'],
1733
+ $data['name']
1734
+ ) );
1735
+ $this->logger->debug( $result->get_error_message() );
1736
+ do_action( 'wp_import_insert_term_failed', $result, $data );
1737
+
1738
+ /**
1739
+ * Term processing failed.
1740
+ *
1741
+ * @param WP_Error $result Error object.
1742
+ * @param array $data Raw data imported for the term.
1743
+ * @param array $meta Meta data supplied for the term.
1744
+ */
1745
+ do_action( 'wxr_importer.process_failed.term', $result, $data, $meta );
1746
+ return false;
1747
+ }
1748
+
1749
+ $term_id = $result['term_id'];
1750
+
1751
+ $this->mapping['term'][ $mapping_key ] = $term_id;
1752
+ $this->mapping['term_id'][ $original_id ] = $term_id;
1753
+
1754
+ $this->logger->info( sprintf(
1755
+ __( 'Imported "%1$s" (%2$s)', 'wordpress-importer' ),
1756
+ $data['name'],
1757
+ $data['taxonomy']
1758
+ ) );
1759
+ $this->logger->debug( sprintf(
1760
+ __( 'Term %1$d remapped to %2$d', 'wordpress-importer' ),
1761
+ $original_id,
1762
+ $term_id
1763
+ ) );
1764
+
1765
+ do_action( 'wp_import_insert_term', $term_id, $data );
1766
+
1767
+ /**
1768
+ * Term processing completed.
1769
+ *
1770
+ * @param int $term_id New term ID.
1771
+ * @param array $data Raw data imported for the term.
1772
+ */
1773
+ do_action( 'wxr_importer.processed.term', $term_id, $data );
1774
+ }
1775
+
1776
+ /**
1777
+ * Attempt to download a remote file attachment
1778
+ *
1779
+ * @param string $url URL of item to fetch
1780
+ * @param array $post Attachment details
1781
+ * @return array|WP_Error Local file location details on success, WP_Error otherwise
1782
+ */
1783
+ protected function fetch_remote_file( $url, $post ) {
1784
+ // extract the file name and extension from the url
1785
+ $file_name = basename( $url );
1786
+
1787
+ // get placeholder file in the upload dir with a unique, sanitized filename
1788
+ $upload = wp_upload_bits( $file_name, 0, '', $post['upload_date'] );
1789
+ if ( $upload['error'] ) {
1790
+ return new WP_Error( 'upload_dir_error', $upload['error'] );
1791
+ }
1792
+
1793
+ // fetch the remote url and write it to the placeholder file
1794
+ $response = wp_remote_get( $url, array(
1795
+ 'stream' => true,
1796
+ 'filename' => $upload['file'],
1797
+ ) );
1798
+
1799
+ // request failed
1800
+ if ( is_wp_error( $response ) ) {
1801
+ unlink( $upload['file'] );
1802
+ return $response;
1803
+ }
1804
+
1805
+ $code = (int) wp_remote_retrieve_response_code( $response );
1806
+
1807
+ // make sure the fetch was successful
1808
+ if ( $code !== 200 ) {
1809
+ unlink( $upload['file'] );
1810
+ return new WP_Error(
1811
+ 'import_file_error',
1812
+ sprintf(
1813
+ __( 'Remote server returned %1$d %2$s for %3$s', 'wordpress-importer' ),
1814
+ $code,
1815
+ get_status_header_desc( $code ),
1816
+ $url
1817
+ )
1818
+ );
1819
+ }
1820
+
1821
+ $filesize = filesize( $upload['file'] );
1822
+ $headers = wp_remote_retrieve_headers( $response );
1823
+
1824
+ if ( isset( $headers['content-length'] ) && $filesize !== (int) $headers['content-length'] ) {
1825
+ unlink( $upload['file'] );
1826
+ return new WP_Error( 'import_file_error', __( 'Remote file is incorrect size', 'wordpress-importer' ) );
1827
+ }
1828
+
1829
+ if ( 0 === $filesize ) {
1830
+ unlink( $upload['file'] );
1831
+ return new WP_Error( 'import_file_error', __( 'Zero size file downloaded', 'wordpress-importer' ) );
1832
+ }
1833
+
1834
+ $max_size = (int) $this->max_attachment_size();
1835
+ if ( ! empty( $max_size ) && $filesize > $max_size ) {
1836
+ unlink( $upload['file'] );
1837
+ $message = sprintf( __( 'Remote file is too large, limit is %s', 'wordpress-importer' ), size_format( $max_size ) );
1838
+ return new WP_Error( 'import_file_error', $message );
1839
+ }
1840
+
1841
+ return $upload;
1842
+ }
1843
+
1844
+ protected function post_process() {
1845
+ // Time to tackle any left-over bits
1846
+ if ( ! empty( $this->requires_remapping['post'] ) ) {
1847
+ $this->post_process_posts( $this->requires_remapping['post'] );
1848
+ }
1849
+ if ( ! empty( $this->requires_remapping['comment'] ) ) {
1850
+ $this->post_process_comments( $this->requires_remapping['comment'] );
1851
+ }
1852
+ }
1853
+
1854
+ protected function post_process_posts( $todo ) {
1855
+ foreach ( $todo as $post_id => $_ ) {
1856
+ $this->logger->debug( sprintf(
1857
+ // Note: title intentionally not used to skip extra processing
1858
+ // for when debug logging is off
1859
+ __( 'Running post-processing for post %d', 'wordpress-importer' ),
1860
+ $post_id
1861
+ ) );
1862
+
1863
+ $data = array();
1864
+
1865
+ $parent_id = get_post_meta( $post_id, '_wxr_import_parent', true );
1866
+ if ( ! empty( $parent_id ) ) {
1867
+ // Have we imported the parent now?
1868
+ if ( isset( $this->mapping['post'][ $parent_id ] ) ) {
1869
+ $data['post_parent'] = $this->mapping['post'][ $parent_id ];
1870
+ } else {
1871
+ $this->logger->warning( sprintf(
1872
+ __( 'Could not find the post parent for "%1$s" (post #%2$d)', 'wordpress-importer' ),
1873
+ get_the_title( $post_id ),
1874
+ $post_id
1875
+ ) );
1876
+ $this->logger->debug( sprintf(
1877
+ __( 'Post %1$d was imported with parent %2$d, but could not be found', 'wordpress-importer' ),
1878
+ $post_id,
1879
+ $parent_id
1880
+ ) );
1881
+ }
1882
+ }
1883
+
1884
+ $author_slug = get_post_meta( $post_id, '_wxr_import_user_slug', true );
1885
+ if ( ! empty( $author_slug ) ) {
1886
+ // Have we imported the user now?
1887
+ if ( isset( $this->mapping['user_slug'][ $author_slug ] ) ) {
1888
+ $data['post_author'] = $this->mapping['user_slug'][ $author_slug ];
1889
+ } else {
1890
+ $this->logger->warning( sprintf(
1891
+ __( 'Could not find the author for "%1$s" (post #%2$d)', 'wordpress-importer' ),
1892
+ get_the_title( $post_id ),
1893
+ $post_id
1894
+ ) );
1895
+ $this->logger->debug( sprintf(
1896
+ __( 'Post %1$d was imported with author "%2$s", but could not be found', 'wordpress-importer' ),
1897
+ $post_id,
1898
+ $author_slug
1899
+ ) );
1900
+ }
1901
+ }
1902
+
1903
+ $has_attachments = get_post_meta( $post_id, '_wxr_import_has_attachment_refs', true );
1904
+ if ( ! empty( $has_attachments ) ) {
1905
+ $post = get_post( $post_id );
1906
+ $content = $post->post_content;
1907
+
1908
+ // Replace all the URLs we've got
1909
+ $new_content = str_replace( array_keys( $this->url_remap ), $this->url_remap, $content );
1910
+ if ( $new_content !== $content ) {
1911
+ $data['post_content'] = $new_content;
1912
+ }
1913
+ }
1914
+
1915
+ if ( get_post_type( $post_id ) === 'nav_menu_item' ) {
1916
+ $this->post_process_menu_item( $post_id );
1917
+ }
1918
+
1919
+ // Do we have updates to make?
1920
+ if ( empty( $data ) ) {
1921
+ $this->logger->debug( sprintf(
1922
+ __( 'Post %d was marked for post-processing, but none was required.', 'wordpress-importer' ),
1923
+ $post_id
1924
+ ) );
1925
+ continue;
1926
+ }
1927
+
1928
+ // Run the update
1929
+ $data['ID'] = $post_id;
1930
+ $result = wp_update_post( $data, true );
1931
+ if ( is_wp_error( $result ) ) {
1932
+ $this->logger->warning( sprintf(
1933
+ __( 'Could not update "%1$s" (post #%2$d) with mapped data', 'wordpress-importer' ),
1934
+ get_the_title( $post_id ),
1935
+ $post_id
1936
+ ) );
1937
+ $this->logger->debug( $result->get_error_message() );
1938
+ continue;
1939
+ }
1940
+
1941
+ // Clear out our temporary meta keys
1942
+ delete_post_meta( $post_id, '_wxr_import_parent' );
1943
+ delete_post_meta( $post_id, '_wxr_import_user_slug' );
1944
+ delete_post_meta( $post_id, '_wxr_import_has_attachment_refs' );
1945
+ }// End foreach().
1946
+ }
1947
+
1948
+ protected function post_process_menu_item( $post_id ) {
1949
+ $menu_object_id = get_post_meta( $post_id, '_wxr_import_menu_item', true );
1950
+ if ( empty( $menu_object_id ) ) {
1951
+ // No processing needed!
1952
+ return;
1953
+ }
1954
+
1955
+ $menu_item_type = get_post_meta( $post_id, '_menu_item_type', true );
1956
+ switch ( $menu_item_type ) {
1957
+ case 'taxonomy':
1958
+ if ( isset( $this->mapping['term_id'][ $menu_object_id ] ) ) {
1959
+ $menu_object = $this->mapping['term_id'][ $menu_object_id ];
1960
+ }
1961
+ break;
1962
+
1963
+ case 'post_type':
1964
+ if ( isset( $this->mapping['post'][ $menu_object_id ] ) ) {
1965
+ $menu_object = $this->mapping['post'][ $menu_object_id ];
1966
+ }
1967
+ break;
1968
+
1969
+ default:
1970
+ // Cannot handle this.
1971
+ return;
1972
+ }
1973
+
1974
+ if ( ! empty( $menu_object ) ) {
1975
+ update_post_meta( $post_id, '_menu_item_object_id', wp_slash( $menu_object ) );
1976
+ } else {
1977
+ $this->logger->warning( sprintf(
1978
+ __( 'Could not find the menu object for "%1$s" (post #%2$d)', 'wordpress-importer' ),
1979
+ get_the_title( $post_id ),
1980
+ $post_id
1981
+ ) );
1982
+ $this->logger->debug( sprintf(
1983
+ __( 'Post %1$d was imported with object "%2$d" of type "%3$s", but could not be found', 'wordpress-importer' ),
1984
+ $post_id,
1985
+ $menu_object_id,
1986
+ $menu_item_type
1987
+ ) );
1988
+ }
1989
+
1990
+ delete_post_meta( $post_id, '_wxr_import_menu_item' );
1991
+ }
1992
+
1993
+
1994
+ protected function post_process_comments( $todo ) {
1995
+ foreach ( $todo as $comment_id => $_ ) {
1996
+ $data = array();
1997
+
1998
+ $parent_id = get_comment_meta( $comment_id, '_wxr_import_parent', true );
1999
+ if ( ! empty( $parent_id ) ) {
2000
+ // Have we imported the parent now?
2001
+ if ( isset( $this->mapping['comment'][ $parent_id ] ) ) {
2002
+ $data['comment_parent'] = $this->mapping['comment'][ $parent_id ];
2003
+ } else {
2004
+ $this->logger->warning( sprintf(
2005
+ __( 'Could not find the comment parent for comment #%d', 'wordpress-importer' ),
2006
+ $comment_id
2007
+ ) );
2008
+ $this->logger->debug( sprintf(
2009
+ __( 'Comment %1$d was imported with parent %2$d, but could not be found', 'wordpress-importer' ),
2010
+ $comment_id,
2011
+ $parent_id
2012
+ ) );
2013
+ }
2014
+ }
2015
+
2016
+ $author_id = get_comment_meta( $comment_id, '_wxr_import_user', true );
2017
+ if ( ! empty( $author_id ) ) {
2018
+ // Have we imported the user now?
2019
+ if ( isset( $this->mapping['user'][ $author_id ] ) ) {
2020
+ $data['user_id'] = $this->mapping['user'][ $author_id ];
2021
+ } else {
2022
+ $this->logger->warning( sprintf(
2023
+ __( 'Could not find the author for comment #%d', 'wordpress-importer' ),
2024
+ $comment_id
2025
+ ) );
2026
+ $this->logger->debug( sprintf(
2027
+ __( 'Comment %1$d was imported with author %2$d, but could not be found', 'wordpress-importer' ),
2028
+ $comment_id,
2029
+ $author_id
2030
+ ) );
2031
+ }
2032
+ }
2033
+
2034
+ // Do we have updates to make?
2035
+ if ( empty( $data ) ) {
2036
+ continue;
2037
+ }
2038
+
2039
+ // Run the update
2040
+ $data['comment_ID'] = $comment_ID;
2041
+ $result = wp_update_comment( wp_slash( $data ) );
2042
+ if ( empty( $result ) ) {
2043
+ $this->logger->warning( sprintf(
2044
+ __( 'Could not update comment #%d with mapped data', 'wordpress-importer' ),
2045
+ $comment_id
2046
+ ) );
2047
+ continue;
2048
+ }
2049
+
2050
+ // Clear out our temporary meta keys
2051
+ delete_comment_meta( $comment_id, '_wxr_import_parent' );
2052
+ delete_comment_meta( $comment_id, '_wxr_import_user' );
2053
+ }// End foreach().
2054
+ }
2055
+
2056
+ /**
2057
+ * Use stored mapping information to update old attachment URLs
2058
+ */
2059
+ protected function replace_attachment_urls_in_content() {
2060
+ global $wpdb;
2061
+ // make sure we do the longest urls first, in case one is a substring of another
2062
+ uksort( $this->url_remap, array( $this, 'cmpr_strlen' ) );
2063
+
2064
+ foreach ( $this->url_remap as $from_url => $to_url ) {
2065
+ // remap urls in post_content
2066
+ $query = $wpdb->prepare( "UPDATE {$wpdb->posts} SET post_content = REPLACE(post_content, %s, %s)", $from_url, $to_url );
2067
+ $wpdb->query( $query );
2068
+
2069
+ // remap enclosure urls
2070
+ $query = $wpdb->prepare( "UPDATE {$wpdb->postmeta} SET meta_value = REPLACE(meta_value, %s, %s) WHERE meta_key='enclosure'", $from_url, $to_url );
2071
+ $result = $wpdb->query( $query );
2072
+ }
2073
+ }
2074
+
2075
+ /**
2076
+ * Update _thumbnail_id meta to new, imported attachment IDs
2077
+ */
2078
+ function remap_featured_images() {
2079
+ // cycle through posts that have a featured image
2080
+ foreach ( $this->featured_images as $post_id => $value ) {
2081
+ if ( isset( $this->processed_posts[ $value ] ) ) {
2082
+ $new_id = $this->processed_posts[ $value ];
2083
+
2084
+ // only update if there's a difference
2085
+ if ( $new_id !== $value ) {
2086
+ update_post_meta( $post_id, '_thumbnail_id', $new_id );
2087
+ }
2088
+ }
2089
+ }
2090
+ }
2091
+
2092
+ /**
2093
+ * Decide if the given meta key maps to information we will want to import
2094
+ *
2095
+ * @param string $key The meta key to check
2096
+ * @return string|bool The key if we do want to import, false if not
2097
+ */
2098
+ public function is_valid_meta_key( $key ) {
2099
+ // skip attachment metadata since we'll regenerate it from scratch
2100
+ // skip _edit_lock as not relevant for import
2101
+ if ( in_array( $key, array( '_wp_attached_file', '_wp_attachment_metadata', '_edit_lock' ) ) ) {
2102
+ return false;
2103
+ }
2104
+
2105
+ return $key;
2106
+ }
2107
+
2108
+ /**
2109
+ * Decide what the maximum file size for downloaded attachments is.
2110
+ * Default is 0 (unlimited), can be filtered via import_attachment_size_limit
2111
+ *
2112
+ * @return int Maximum attachment file size to import
2113
+ */
2114
+ protected function max_attachment_size() {
2115
+ return apply_filters( 'import_attachment_size_limit', 0 );
2116
+ }
2117
+
2118
+ /**
2119
+ * Added to http_request_timeout filter to force timeout at 60 seconds during import
2120
+ *
2121
+ * @access protected
2122
+ * @return int 60
2123
+ */
2124
+ function bump_request_timeout( $val ) {
2125
+ return 60;
2126
+ }
2127
+
2128
+ // return the difference in length between two strings
2129
+ function cmpr_strlen( $a, $b ) {
2130
+ return strlen( $b ) - strlen( $a );
2131
+ }
2132
+
2133
+ /**
2134
+ * Prefill existing post data.
2135
+ *
2136
+ * This preloads all GUIDs into memory, allowing us to avoid hitting the
2137
+ * database when we need to check for existence. With larger imports, this
2138
+ * becomes prohibitively slow to perform SELECT queries on each.
2139
+ *
2140
+ * By preloading all this data into memory, it's a constant-time lookup in
2141
+ * PHP instead. However, this does use a lot more memory, so for sites doing
2142
+ * small imports onto a large site, it may be a better tradeoff to use
2143
+ * on-the-fly checking instead.
2144
+ */
2145
+ protected function prefill_existing_posts() {
2146
+ global $wpdb;
2147
+ $posts = $wpdb->get_results( "SELECT ID, guid FROM {$wpdb->posts}" );
2148
+
2149
+ foreach ( $posts as $item ) {
2150
+ $this->exists['post'][ $item->guid ] = $item->ID;
2151
+ }
2152
+ }
2153
+
2154
+ /**
2155
+ * Does the post exist?
2156
+ *
2157
+ * @param array $data Post data to check against.
2158
+ * @return int|bool Existing post ID if it exists, false otherwise.
2159
+ */
2160
+ protected function post_exists( $data ) {
2161
+ // Constant-time lookup if we prefilled
2162
+ $exists_key = $data['guid'];
2163
+
2164
+ if ( $this->options['prefill_existing_posts'] ) {
2165
+ return isset( $this->exists['post'][ $exists_key ] ) ? $this->exists['post'][ $exists_key ] : false;
2166
+ }
2167
+
2168
+ // No prefilling, but might have already handled it
2169
+ if ( isset( $this->exists['post'][ $exists_key ] ) ) {
2170
+ return $this->exists['post'][ $exists_key ];
2171
+ }
2172
+
2173
+ // Still nothing, try post_exists, and cache it
2174
+ $exists = post_exists( $data['post_title'], $data['post_content'], $data['post_date'] );
2175
+ $this->exists['post'][ $exists_key ] = $exists;
2176
+
2177
+ return $exists;
2178
+ }
2179
+
2180
+ /**
2181
+ * Mark the post as existing.
2182
+ *
2183
+ * @param array $data Post data to mark as existing.
2184
+ * @param int $post_id Post ID.
2185
+ */
2186
+ protected function mark_post_exists( $data, $post_id ) {
2187
+ $exists_key = $data['guid'];
2188
+ $this->exists['post'][ $exists_key ] = $post_id;
2189
+ }
2190
+
2191
+ /**
2192
+ * Prefill existing comment data.
2193
+ *
2194
+ * @see self::prefill_existing_posts() for justification of why this exists.
2195
+ */
2196
+ protected function prefill_existing_comments() {
2197
+ global $wpdb;
2198
+ $posts = $wpdb->get_results( "SELECT comment_ID, comment_author, comment_date FROM {$wpdb->comments}" );
2199
+
2200
+ foreach ( $posts as $item ) {
2201
+ $exists_key = sha1( $item->comment_author . ':' . $item->comment_date );
2202
+ $this->exists['comment'][ $exists_key ] = $item->comment_ID;
2203
+ }
2204
+ }
2205
+
2206
+ /**
2207
+ * Does the comment exist?
2208
+ *
2209
+ * @param array $data Comment data to check against.
2210
+ * @return int|bool Existing comment ID if it exists, false otherwise.
2211
+ */
2212
+ protected function comment_exists( $data ) {
2213
+ $exists_key = sha1( $data['comment_author'] . ':' . $data['comment_date'] );
2214
+
2215
+ // Constant-time lookup if we prefilled
2216
+ if ( $this->options['prefill_existing_comments'] ) {
2217
+ return isset( $this->exists['comment'][ $exists_key ] ) ? $this->exists['comment'][ $exists_key ] : false;
2218
+ }
2219
+
2220
+ // No prefilling, but might have already handled it
2221
+ if ( isset( $this->exists['comment'][ $exists_key ] ) ) {
2222
+ return $this->exists['comment'][ $exists_key ];
2223
+ }
2224
+
2225
+ // Still nothing, try comment_exists, and cache it
2226
+ $exists = comment_exists( $data['comment_author'], $data['comment_date'] );
2227
+ $this->exists['comment'][ $exists_key ] = $exists;
2228
+
2229
+ return $exists;
2230
+ }
2231
+
2232
+ /**
2233
+ * Mark the comment as existing.
2234
+ *
2235
+ * @param array $data Comment data to mark as existing.
2236
+ * @param int $comment_id Comment ID.
2237
+ */
2238
+ protected function mark_comment_exists( $data, $comment_id ) {
2239
+ $exists_key = sha1( $data['comment_author'] . ':' . $data['comment_date'] );
2240
+ $this->exists['comment'][ $exists_key ] = $comment_id;
2241
+ }
2242
+
2243
+ /**
2244
+ * Prefill existing term data.
2245
+ *
2246
+ * @see self::prefill_existing_posts() for justification of why this exists.
2247
+ */
2248
+ protected function prefill_existing_terms() {
2249
+ global $wpdb;
2250
+ $query = "SELECT t.term_id, tt.taxonomy, t.slug FROM {$wpdb->terms} AS t";
2251
+ $query .= " JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id";
2252
+ $terms = $wpdb->get_results( $query );
2253
+
2254
+ foreach ( $terms as $item ) {
2255
+ $exists_key = sha1( $item->taxonomy . ':' . $item->slug );
2256
+ $this->exists['term'][ $exists_key ] = $item->term_id;
2257
+ }
2258
+ }
2259
+
2260
+ /**
2261
+ * Does the term exist?
2262
+ *
2263
+ * @param array $data Term data to check against.
2264
+ * @return int|bool Existing term ID if it exists, false otherwise.
2265
+ */
2266
+ protected function term_exists( $data ) {
2267
+ $exists_key = sha1( $data['taxonomy'] . ':' . $data['slug'] );
2268
+
2269
+ // Constant-time lookup if we prefilled
2270
+ if ( $this->options['prefill_existing_terms'] ) {
2271
+ return isset( $this->exists['term'][ $exists_key ] ) ? $this->exists['term'][ $exists_key ] : false;
2272
+ }
2273
+
2274
+ // No prefilling, but might have already handled it
2275
+ if ( isset( $this->exists['term'][ $exists_key ] ) ) {
2276
+ return $this->exists['term'][ $exists_key ];
2277
+ }
2278
+
2279
+ // Still nothing, try comment_exists, and cache it
2280
+ $exists = term_exists( $data['slug'], $data['taxonomy'] );
2281
+ if ( is_array( $exists ) ) {
2282
+ $exists = $exists['term_id'];
2283
+ }
2284
+
2285
+ $this->exists['term'][ $exists_key ] = $exists;
2286
+
2287
+ return $exists;
2288
+ }
2289
+
2290
+ /**
2291
+ * Mark the term as existing.
2292
+ *
2293
+ * @param array $data Term data to mark as existing.
2294
+ * @param int $term_id Term ID.
2295
+ */
2296
+ protected function mark_term_exists( $data, $term_id ) {
2297
+ $exists_key = sha1( $data['taxonomy'] . ':' . $data['slug'] );
2298
+ $this->exists['term'][ $exists_key ] = $term_id;
2299
+ }
2300
+ }
2301
  endif;
languages/astra-sites.pot CHANGED
@@ -1,709 +1,721 @@
1
- # Copyright (C) 2019 Brainstorm Force
2
- # This file is distributed under the same license as the Astra Starter Sites – Elementor, Beaver Builder & Gutenberg Templates package.
3
- msgid ""
4
- msgstr ""
5
- "Project-Id-Version: Astra Starter Sites – Elementor, Beaver Builder & "
6
- "Gutenberg Templates 1.2.13\n"
7
- "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/astra-sites\n"
8
- "POT-Creation-Date: 2019-03-12 10:21:32+00:00\n"
9
- "MIME-Version: 1.0\n"
10
- "Content-Type: text/plain; charset=utf-8\n"
11
- "Content-Transfer-Encoding: 8bit\n"
12
- "PO-Revision-Date: 2019-MO-DA HO:MI+ZONE\n"
13
- "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
- "Language-Team: LANGUAGE <LL@li.org>\n"
15
- "Language: en\n"
16
- "Plural-Forms: nplurals=2; plural=(n != 1);\n"
17
- "X-Poedit-Country: United States\n"
18
- "X-Poedit-SourceCharset: UTF-8\n"
19
- "X-Poedit-KeywordsList: "
20
- "__;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;_nx_noop:1,2,3c;esc_"
21
- "attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;esc_html_x:1,2c;\n"
22
- "X-Poedit-Basepath: ../\n"
23
- "X-Poedit-SearchPath-0: .\n"
24
- "X-Poedit-Bookmarks: \n"
25
- "X-Textdomain-Support: yes\n"
26
- "X-Generator: grunt-wp-i18n1.0.0\n"
27
-
28
- #: astra-sites.php:18 inc/classes/class-astra-sites-page.php:85
29
- msgid "Astra Sites"
30
- msgstr ""
31
-
32
- #: inc/classes/class-astra-sites-importer-log.php:352
33
- msgid "Enabled"
34
- msgstr ""
35
-
36
- #: inc/classes/class-astra-sites-importer-log.php:355
37
- msgid "Disabled"
38
- msgstr ""
39
-
40
- #: inc/classes/class-astra-sites-importer-log.php:440
41
- #: inc/classes/class-astra-sites-importer-log.php:497
42
- msgid "Yes"
43
- msgstr ""
44
-
45
- #: inc/classes/class-astra-sites-importer-log.php:443
46
- #: inc/classes/class-astra-sites-importer-log.php:500
47
- msgid "No"
48
- msgstr ""
49
-
50
- #: inc/classes/class-astra-sites-importer.php:87
51
- msgid "You have not \"customize\" access to import the Astra site."
52
- msgstr ""
53
-
54
- #: inc/classes/class-astra-sites-importer.php:111
55
- msgid "Request site API URL is empty. Try again!"
56
- msgstr ""
57
-
58
- #: inc/classes/class-astra-sites-importer.php:134
59
- msgid "Customizer data is empty!"
60
- msgstr ""
61
-
62
- #: inc/classes/class-astra-sites-importer.php:150
63
- msgid ""
64
- "If XMLReader is not available, it imports all other settings and only skips "
65
- "XML import. This creates an incomplete website. We should bail early and "
66
- "not import anything if this is not present."
67
- msgstr ""
68
-
69
- #: inc/classes/class-astra-sites-importer.php:166
70
- msgid "There was an error downloading the XML file."
71
- msgstr ""
72
-
73
- #: inc/classes/class-astra-sites-importer.php:172
74
- msgid "Invalid site XML file!"
75
- msgstr ""
76
-
77
- #: inc/classes/class-astra-sites-importer.php:194
78
- msgid "Site options are empty!"
79
- msgstr ""
80
-
81
- #: inc/classes/class-astra-sites-importer.php:216
82
- msgid "Widget data is empty!"
83
- msgstr ""
84
-
85
- #: inc/classes/class-astra-sites-page.php:113
86
- msgid "Required XMLReader PHP extension is missing on your server!"
87
- msgstr ""
88
-
89
- #: inc/classes/class-astra-sites-page.php:115
90
- #. translators: %s is the white label name.
91
- msgid ""
92
- "%s import requires XMLReader extension to be installed. Please contact your "
93
- "web hosting provider and ask them to install and activate the XMLReader PHP "
94
- "extension."
95
- msgstr ""
96
-
97
- #: inc/classes/class-astra-sites-page.php:216
98
- msgid "Settings saved successfully."
99
- msgstr ""
100
-
101
- #: inc/classes/class-astra-sites-white-label.php:186
102
- #. translators: %1$s product name
103
- msgid "%1$s Branding"
104
- msgstr ""
105
-
106
- #: inc/classes/class-astra-sites.php:81
107
- #. translators: 1: theme.php file
108
- msgid ""
109
- "Astra Theme needs to be active for you to use currently installed \"%1$s\" "
110
- "plugin. <a href=\"%2$s\">Install & Activate Now</a>"
111
- msgstr ""
112
-
113
- #: inc/classes/class-astra-sites.php:121
114
- msgid "See Library"
115
- msgstr ""
116
-
117
- #: inc/classes/class-astra-sites.php:174
118
- msgid "Page Builder"
119
- msgstr ""
120
-
121
- #: inc/classes/class-astra-sites.php:179
122
- msgid "Categories"
123
- msgstr ""
124
-
125
- #: inc/classes/class-astra-sites.php:218
126
- msgid "Get Agency Bundle"
127
- msgstr ""
128
-
129
- #: inc/classes/class-astra-sites.php:220
130
- msgid "Upgrade"
131
- msgstr ""
132
-
133
- #: inc/classes/class-astra-sites.php:227
134
- #. translators: %s are HTML tags.
135
- msgid ""
136
- "%1$sRequired XMLReader PHP extension is missing on your server!%2$sAstra "
137
- "Sites import requires XMLReader extension to be installed. Please contact "
138
- "your web hosting provider and ask them to install and activate the "
139
- "XMLReader PHP extension."
140
- msgstr ""
141
-
142
- #: inc/classes/class-astra-sites.php:228
143
- msgid ""
144
- "Warning! Astra Site Import process is not complete. Don't close the window "
145
- "until import process complete. Do you still want to leave the window?"
146
- msgstr ""
147
-
148
- #: inc/classes/class-astra-sites.php:229
149
- msgid "Error!"
150
- msgstr ""
151
-
152
- #: inc/classes/class-astra-sites.php:230
153
- msgid "Error! Read Possibilities."
154
- msgstr ""
155
-
156
- #: inc/classes/class-astra-sites.php:232
157
- msgid "Done! View Site"
158
- msgstr ""
159
-
160
- #: inc/classes/class-astra-sites.php:233
161
- msgid "Activating"
162
- msgstr ""
163
-
164
- #: inc/classes/class-astra-sites.php:234
165
- msgid "Active"
166
- msgstr ""
167
-
168
- #: inc/classes/class-astra-sites.php:235
169
- msgid "Import failed."
170
- msgstr ""
171
-
172
- #: inc/classes/class-astra-sites.php:236
173
- msgid "Import failed. See error log."
174
- msgstr ""
175
-
176
- #: inc/classes/class-astra-sites.php:237
177
- msgid "Import This Site"
178
- msgstr ""
179
-
180
- #: inc/classes/class-astra-sites.php:238 inc/classes/class-astra-sites.php:255
181
- msgid "Importing.."
182
- msgstr ""
183
-
184
- #: inc/classes/class-astra-sites.php:239 inc/includes/admin-page.php:159
185
- msgid "Read more"
186
- msgstr ""
187
-
188
- #: inc/classes/class-astra-sites.php:240
189
- msgid "Hide"
190
- msgstr ""
191
-
192
- #: inc/classes/class-astra-sites.php:241
193
- msgid "There was a problem receiving a response from server."
194
- msgstr ""
195
-
196
- #: inc/classes/class-astra-sites.php:242 inc/includes/admin-page.php:319
197
- msgid "No Demos found, Try a different search."
198
- msgstr ""
199
-
200
- #: inc/classes/class-astra-sites.php:243
201
- msgid ""
202
- "Executing Demo Import will make your site similar as ours. Please bear in "
203
- "mind -\n"
204
- "\n"
205
- "1. It is recommended to run import on a fresh WordPress installation.\n"
206
- "\n"
207
- "2. Importing site does not delete any pages or posts. However, it can "
208
- "overwrite your existing content.\n"
209
- "\n"
210
- "3. Copyrighted media will not be imported. Instead it will be replaced with "
211
- "placeholders."
212
- msgstr ""
213
-
214
- #: inc/classes/class-astra-sites.php:246
215
- msgid "Installing plugin "
216
- msgstr ""
217
-
218
- #: inc/classes/class-astra-sites.php:247
219
- msgid "Successfully plugin installed!"
220
- msgstr ""
221
-
222
- #: inc/classes/class-astra-sites.php:248
223
- msgid "Activating plugin "
224
- msgstr ""
225
-
226
- #: inc/classes/class-astra-sites.php:249
227
- msgid "Successfully plugin activated "
228
- msgstr ""
229
-
230
- #: inc/classes/class-astra-sites.php:250
231
- msgid "Bulk plugin activation..."
232
- msgstr ""
233
-
234
- #: inc/classes/class-astra-sites.php:251
235
- msgid "Successfully plugin activate - "
236
- msgstr ""
237
-
238
- #: inc/classes/class-astra-sites.php:252
239
- msgid "Error! While activating plugin - "
240
- msgstr ""
241
-
242
- #: inc/classes/class-astra-sites.php:253
243
- msgid "Bulk plugin installation..."
244
- msgstr ""
245
-
246
- #: inc/classes/class-astra-sites.php:254
247
- msgid "Site API "
248
- msgstr ""
249
-
250
- #: inc/classes/class-astra-sites.php:256
251
- msgid "Processing requests..."
252
- msgstr ""
253
-
254
- #: inc/classes/class-astra-sites.php:257
255
- msgid "1) Importing \"Customizer Settings\"..."
256
- msgstr ""
257
-
258
- #: inc/classes/class-astra-sites.php:258
259
- msgid "Successfully imported customizer settings!"
260
- msgstr ""
261
-
262
- #: inc/classes/class-astra-sites.php:259
263
- msgid "2) Preparing \"XML\" Data..."
264
- msgstr ""
265
-
266
- #: inc/classes/class-astra-sites.php:260
267
- msgid "Successfully set XML data!"
268
- msgstr ""
269
-
270
- #: inc/classes/class-astra-sites.php:261
271
- msgid "3) Importing \"XML\"..."
272
- msgstr ""
273
-
274
- #: inc/classes/class-astra-sites.php:262
275
- msgid "Successfully imported XML!"
276
- msgstr ""
277
-
278
- #: inc/classes/class-astra-sites.php:263
279
- msgid "4) Importing \"Options\"..."
280
- msgstr ""
281
-
282
- #: inc/classes/class-astra-sites.php:264
283
- msgid "Successfully imported Options!"
284
- msgstr ""
285
-
286
- #: inc/classes/class-astra-sites.php:265
287
- msgid "5) Importing \"Widgets\"..."
288
- msgstr ""
289
-
290
- #: inc/classes/class-astra-sites.php:266
291
- msgid "Successfully imported Widgets!"
292
- msgstr ""
293
-
294
- #: inc/classes/class-astra-sites.php:268
295
- msgid "Site imported successfully! visit : "
296
- msgstr ""
297
-
298
- #: inc/classes/class-astra-sites.php:269
299
- msgid "Getting Site Information.."
300
- msgstr ""
301
-
302
- #: inc/classes/class-astra-sites.php:270
303
- msgid "Importing Customizer Settings.."
304
- msgstr ""
305
-
306
- #: inc/classes/class-astra-sites.php:271
307
- msgid "Setting up import data.."
308
- msgstr ""
309
-
310
- #: inc/classes/class-astra-sites.php:272
311
- msgid "Importing Pages, Posts & Media.."
312
- msgstr ""
313
-
314
- #: inc/classes/class-astra-sites.php:273
315
- msgid "Importing Site Options.."
316
- msgstr ""
317
-
318
- #: inc/classes/class-astra-sites.php:274
319
- msgid "Importing Widgets.."
320
- msgstr ""
321
-
322
- #: inc/classes/class-astra-sites.php:275
323
- msgid "Import Complete.."
324
- msgstr ""
325
-
326
- #: inc/classes/class-astra-sites.php:276
327
- msgid "Previewing "
328
- msgstr ""
329
-
330
- #: inc/classes/class-astra-sites.php:277
331
- msgid "See Error Log &rarr;"
332
- msgstr ""
333
-
334
- #: inc/classes/class-astra-sites.php:312
335
- msgid "No plugin specified"
336
- msgstr ""
337
-
338
- #: inc/classes/class-astra-sites.php:341
339
- msgid "Plugin Successfully Activated"
340
- msgstr ""
341
-
342
- #: inc/importers/batch-processing/helpers/class-wp-background-process.php:433
343
- msgid "Every %d Minutes"
344
- msgstr ""
345
-
346
- #: inc/importers/class-widgets-importer.php:83
347
- msgid "Import data could not be read. Please try a different file."
348
- msgstr ""
349
-
350
- #: inc/importers/class-widgets-importer.php:127
351
- msgid "Widget area does not exist in theme (using Inactive)"
352
- msgstr ""
353
-
354
- #: inc/importers/class-widgets-importer.php:149
355
- msgid "Site does not support widget"
356
- msgstr ""
357
-
358
- #: inc/importers/class-widgets-importer.php:185
359
- msgid "Widget already exists"
360
- msgstr ""
361
-
362
- #: inc/importers/class-widgets-importer.php:254
363
- msgid "Imported"
364
- msgstr ""
365
-
366
- #: inc/importers/class-widgets-importer.php:257
367
- msgid "Imported to Inactive"
368
- msgstr ""
369
-
370
- #: inc/importers/class-widgets-importer.php:263
371
- msgid "No Title"
372
- msgstr ""
373
-
374
- #: inc/importers/wxr-importer/class-astra-wxr-importer.php:229
375
- msgid "Import complete!"
376
- msgstr ""
377
-
378
- #: inc/importers/wxr-importer/class-wxr-importer.php:131
379
- msgid "Could not open the file for parsing"
380
- msgstr ""
381
-
382
- #: inc/importers/wxr-importer/class-wxr-importer.php:167
383
- #: inc/importers/wxr-importer/class-wxr-importer.php:283
384
- #: inc/importers/wxr-importer/class-wxr-importer.php:356
385
- msgid ""
386
- "This WXR file (version %1$s) is newer than the importer (version %2$s) and "
387
- "may not be supported. Please consider updating."
388
- msgstr ""
389
-
390
- #: inc/importers/wxr-importer/class-wxr-importer.php:504
391
- msgid "The file does not exist, please try again."
392
- msgstr ""
393
-
394
- #: inc/importers/wxr-importer/class-wxr-importer.php:564
395
- msgid "Invalid author mapping"
396
- msgstr ""
397
-
398
- #: inc/importers/wxr-importer/class-wxr-importer.php:665
399
- msgid "Cannot import auto-draft posts"
400
- msgstr ""
401
-
402
- #: inc/importers/wxr-importer/class-wxr-importer.php:753
403
- msgid "Failed to import \"%1$s\": Invalid post type %2$s"
404
- msgstr ""
405
-
406
- #: inc/importers/wxr-importer/class-wxr-importer.php:763
407
- msgid "%1$s \"%2$s\" already exists."
408
- msgstr ""
409
-
410
- #: inc/importers/wxr-importer/class-wxr-importer.php:857
411
- msgid "Skipping attachment \"%s\", fetching attachments disabled"
412
- msgstr ""
413
-
414
- #: inc/importers/wxr-importer/class-wxr-importer.php:878
415
- msgid "Failed to import \"%1$s\" (%2$s)"
416
- msgstr ""
417
-
418
- #: inc/importers/wxr-importer/class-wxr-importer.php:910
419
- #: inc/importers/wxr-importer/class-wxr-importer.php:1755
420
- msgid "Imported \"%1$s\" (%2$s)"
421
- msgstr ""
422
-
423
- #: inc/importers/wxr-importer/class-wxr-importer.php:915
424
- msgid "Post %1$d remapped to %2$d"
425
- msgstr ""
426
-
427
- #: inc/importers/wxr-importer/class-wxr-importer.php:1062
428
- msgid "Invalid file type"
429
- msgstr ""
430
-
431
- #: inc/importers/wxr-importer/class-wxr-importer.php:1560
432
- msgid "Failed to import user \"%s\""
433
- msgstr ""
434
-
435
- #: inc/importers/wxr-importer/class-wxr-importer.php:1581
436
- msgid "Imported user \"%s\""
437
- msgstr ""
438
-
439
- #: inc/importers/wxr-importer/class-wxr-importer.php:1585
440
- msgid "User %1$d remapped to %2$d"
441
- msgstr ""
442
-
443
- #: inc/importers/wxr-importer/class-wxr-importer.php:1731
444
- msgid "Failed to import %1$s %2$s"
445
- msgstr ""
446
-
447
- #: inc/importers/wxr-importer/class-wxr-importer.php:1760
448
- msgid "Term %1$d remapped to %2$d"
449
- msgstr ""
450
-
451
- #: inc/importers/wxr-importer/class-wxr-importer.php:1813
452
- msgid "Remote server returned %1$d %2$s for %3$s"
453
- msgstr ""
454
-
455
- #: inc/importers/wxr-importer/class-wxr-importer.php:1826
456
- msgid "Remote file is incorrect size"
457
- msgstr ""
458
-
459
- #: inc/importers/wxr-importer/class-wxr-importer.php:1831
460
- msgid "Zero size file downloaded"
461
- msgstr ""
462
-
463
- #: inc/importers/wxr-importer/class-wxr-importer.php:1837
464
- msgid "Remote file is too large, limit is %s"
465
- msgstr ""
466
-
467
- #: inc/importers/wxr-importer/class-wxr-importer.php:1859
468
- msgid "Running post-processing for post %d"
469
- msgstr ""
470
-
471
- #: inc/importers/wxr-importer/class-wxr-importer.php:1872
472
- msgid "Could not find the post parent for \"%1$s\" (post #%2$d)"
473
- msgstr ""
474
-
475
- #: inc/importers/wxr-importer/class-wxr-importer.php:1877
476
- msgid "Post %1$d was imported with parent %2$d, but could not be found"
477
- msgstr ""
478
-
479
- #: inc/importers/wxr-importer/class-wxr-importer.php:1891
480
- msgid "Could not find the author for \"%1$s\" (post #%2$d)"
481
- msgstr ""
482
-
483
- #: inc/importers/wxr-importer/class-wxr-importer.php:1896
484
- msgid "Post %1$d was imported with author \"%2$s\", but could not be found"
485
- msgstr ""
486
-
487
- #: inc/importers/wxr-importer/class-wxr-importer.php:1922
488
- msgid "Post %d was marked for post-processing, but none was required."
489
- msgstr ""
490
-
491
- #: inc/importers/wxr-importer/class-wxr-importer.php:1933
492
- msgid "Could not update \"%1$s\" (post #%2$d) with mapped data"
493
- msgstr ""
494
-
495
- #: inc/importers/wxr-importer/class-wxr-importer.php:1978
496
- msgid "Could not find the menu object for \"%1$s\" (post #%2$d)"
497
- msgstr ""
498
-
499
- #: inc/importers/wxr-importer/class-wxr-importer.php:1983
500
- msgid ""
501
- "Post %1$d was imported with object \"%2$d\" of type \"%3$s\", but could not "
502
- "be found"
503
- msgstr ""
504
-
505
- #: inc/importers/wxr-importer/class-wxr-importer.php:2005
506
- msgid "Could not find the comment parent for comment #%d"
507
- msgstr ""
508
-
509
- #: inc/importers/wxr-importer/class-wxr-importer.php:2009
510
- msgid "Comment %1$d was imported with parent %2$d, but could not be found"
511
- msgstr ""
512
-
513
- #: inc/importers/wxr-importer/class-wxr-importer.php:2023
514
- msgid "Could not find the author for comment #%d"
515
- msgstr ""
516
-
517
- #: inc/importers/wxr-importer/class-wxr-importer.php:2027
518
- msgid "Comment %1$d was imported with author %2$d, but could not be found"
519
- msgstr ""
520
-
521
- #: inc/importers/wxr-importer/class-wxr-importer.php:2044
522
- msgid "Could not update comment #%d with mapped data"
523
- msgstr ""
524
-
525
- #: inc/includes/admin-page.php:42
526
- msgid "Search Sites"
527
- msgstr ""
528
-
529
- #: inc/includes/admin-page.php:43
530
- msgid "Search Sites..."
531
- msgstr ""
532
-
533
- #: inc/includes/admin-page.php:72
534
- msgid "Liked this demo?"
535
- msgstr ""
536
-
537
- #: inc/includes/admin-page.php:76
538
- #. translators: %s is pricing page link
539
- msgid ""
540
- "It is a premium website demo which is available only with the Agency "
541
- "Bundles <a href=\"%s\" target=\"_blank\">Buy Now!</a>"
542
- msgstr ""
543
-
544
- #: inc/includes/admin-page.php:82
545
- #. translators: %s is article link
546
- msgid ""
547
- "Already own an Agency Bundle? Read an article to know how you can <a "
548
- "href=\"%s\" target=\"_blank\">import a premium website demo</a>."
549
- msgstr ""
550
-
551
- #: inc/includes/admin-page.php:93
552
- msgid "You are just 2 minutes away from importing this demo!"
553
- msgstr ""
554
-
555
- #: inc/includes/admin-page.php:94
556
- msgid ""
557
- "It is a premium website demo and you need to activate the license to access "
558
- "it."
559
- msgstr ""
560
-
561
- #: inc/includes/admin-page.php:98
562
- #. translators: %s is article link
563
- msgid ""
564
- "Learn how you can <a href=\"%s\" target=\"_blank\">activate the license</a> "
565
- "of the Astra Premium Sites plugin."
566
- msgstr ""
567
-
568
- #: inc/includes/admin-page.php:113
569
- msgid "Select Your Favorite Page Builder"
570
- msgstr ""
571
-
572
- #: inc/includes/admin-page.php:116
573
- msgid "Sites List.."
574
- msgstr ""
575
-
576
- #: inc/includes/admin-page.php:140
577
- msgid "Close"
578
- msgstr ""
579
-
580
- #: inc/includes/admin-page.php:141
581
- msgid "Previous"
582
- msgstr ""
583
-
584
- #: inc/includes/admin-page.php:142
585
- msgid "Next"
586
- msgstr ""
587
-
588
- #: inc/includes/admin-page.php:143 inc/includes/admin-page.php:171
589
- msgid "Install Plugins"
590
- msgstr ""
591
-
592
- #: inc/includes/admin-page.php:162
593
- msgid "Required Plugins"
594
- msgstr ""
595
-
596
- #: inc/includes/admin-page.php:177
597
- msgid "Collapse"
598
- msgstr ""
599
-
600
- #: inc/includes/admin-page.php:183
601
- msgid "Enter desktop preview mode"
602
- msgstr ""
603
-
604
- #: inc/includes/admin-page.php:186
605
- msgid "Enter tablet preview mode"
606
- msgstr ""
607
-
608
- #: inc/includes/admin-page.php:189
609
- msgid "Enter mobile preview mode"
610
- msgstr ""
611
-
612
- #: inc/includes/admin-page.php:197 inc/includes/admin-page.php:311
613
- msgid "Preview"
614
- msgstr ""
615
-
616
- #: inc/includes/admin-page.php:212
617
- #. translators: %1$s & %2$s are a Demo API URL
618
- msgid ""
619
- "<p> It seems the demo data server, <i><a href=\"%1$s\">%2$s</a></i> is "
620
- "unreachable from your site.</p>"
621
- msgstr ""
622
-
623
- #: inc/includes/admin-page.php:214
624
- msgid ""
625
- "<p class=\"left-margin\"> 1. Sometimes, simple page reload fixes any "
626
- "temporary issues. No kidding!</p>"
627
- msgstr ""
628
-
629
- #: inc/includes/admin-page.php:216
630
- msgid ""
631
- "<p class=\"left-margin\"> 2. If that does not work, you will need to talk "
632
- "to your server administrator and check if demo server is being blocked by "
633
- "the firewall!</p>"
634
- msgstr ""
635
-
636
- #: inc/includes/admin-page.php:219
637
- #. translators: %1$s is a support link
638
- msgid ""
639
- "<p>If that does not help, please open up a <a href=\"%1$s\" "
640
- "target=\"_blank\">Support Ticket</a> and we will be glad take a closer look "
641
- "for you.</p>"
642
- msgstr ""
643
-
644
- #: inc/includes/admin-page.php:231
645
- msgid "Under Maintenance.."
646
- msgstr ""
647
-
648
- #: inc/includes/admin-page.php:232
649
- msgid ""
650
- "If you are seeing this message, most likely our servers are under routine "
651
- "maintenance and we will be back shortly. "
652
- msgstr ""
653
-
654
- #: inc/includes/admin-page.php:233
655
- msgid ""
656
- "In rare case, it is possible your website is having trouble connecting with "
657
- "ours. If you need help, please feel free to get in touch with us from our "
658
- "website."
659
- msgstr ""
660
-
661
- #: inc/includes/admin-page.php:300
662
- msgid "Details &amp; Preview"
663
- msgstr ""
664
-
665
- #: inc/includes/admin-page.php:323 inc/includes/admin-page.php:341
666
- #. translators: %1$s External Link
667
- msgid ""
668
- "Don't see a site that you would like to import?<br><a target=\"_blank\" "
669
- "href=\"%1$s\">Please suggest us!</a>"
670
- msgstr ""
671
-
672
- #: inc/includes/white-label.php:29
673
- msgid "Plugin Name:"
674
- msgstr ""
675
-
676
- #: inc/includes/white-label.php:34
677
- msgid "Plugin Description:"
678
- msgstr ""
679
-
680
- #. Plugin Name of the plugin/theme
681
- msgid "Astra Starter Sites – Elementor, Beaver Builder & Gutenberg Templates"
682
- msgstr ""
683
-
684
- #. Plugin URI of the plugin/theme
685
- msgid "http://www.wpastra.com/pro/"
686
- msgstr ""
687
-
688
- #. Description of the plugin/theme
689
- msgid "Import free sites build with Astra theme."
690
- msgstr ""
691
-
692
- #. Author of the plugin/theme
693
- msgid "Brainstorm Force"
694
- msgstr ""
695
-
696
- #. Author URI of the plugin/theme
697
- msgid "http://www.brainstormforce.com"
698
- msgstr ""
699
-
700
- #: inc/classes/class-astra-sites-importer-log.php:373
701
- #. translators: %1$s Memory Limit, %2$s Recommended memory limit.
702
- msgctxt "Recommended Memory Limit"
703
- msgid "Current memory limit %1$s. We recommend setting memory to at least %2$s."
704
- msgstr ""
705
-
706
- #: inc/classes/class-astra-sites-importer-log.php:454
707
- msgctxt "PHP Version"
708
- msgid "We recommend to use php 5.4 or higher"
 
 
 
 
 
 
 
 
 
 
 
 
709
  msgstr ""
1
+ # Copyright (C) 2019 Brainstorm Force
2
+ # This file is distributed under the same license as the Astra Starter Sites – Elementor, Beaver Builder & Gutenberg Templates package.
3
+ msgid ""
4
+ msgstr ""
5
+ "Project-Id-Version: Astra Starter Sites – Elementor, Beaver Builder & "
6
+ "Gutenberg Templates 1.2.14\n"
7
+ "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/astra-sites\n"
8
+ "POT-Creation-Date: 2019-03-13 08:33:42+00:00\n"
9
+ "MIME-Version: 1.0\n"
10
+ "Content-Type: text/plain; charset=utf-8\n"
11
+ "Content-Transfer-Encoding: 8bit\n"
12
+ "PO-Revision-Date: 2019-MO-DA HO:MI+ZONE\n"
13
+ "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
+ "Language-Team: LANGUAGE <LL@li.org>\n"
15
+ "Language: en\n"
16
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
17
+ "X-Poedit-Country: United States\n"
18
+ "X-Poedit-SourceCharset: UTF-8\n"
19
+ "X-Poedit-KeywordsList: "
20
+ "__;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;_nx_noop:1,2,3c;esc_"
21
+ "attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;esc_html_x:1,2c;\n"
22
+ "X-Poedit-Basepath: ../\n"
23
+ "X-Poedit-SearchPath-0: .\n"
24
+ "X-Poedit-Bookmarks: \n"
25
+ "X-Textdomain-Support: yes\n"
26
+ "X-Generator: grunt-wp-i18n1.0.0\n"
27
+
28
+ #: astra-sites.php:18 inc/classes/class-astra-sites-page.php:85
29
+ msgid "Astra Sites"
30
+ msgstr ""
31
+
32
+ #: inc/classes/class-astra-sites-importer-log.php:352
33
+ msgid "Enabled"
34
+ msgstr ""
35
+
36
+ #: inc/classes/class-astra-sites-importer-log.php:355
37
+ msgid "Disabled"
38
+ msgstr ""
39
+
40
+ #: inc/classes/class-astra-sites-importer-log.php:440
41
+ #: inc/classes/class-astra-sites-importer-log.php:497
42
+ msgid "Yes"
43
+ msgstr ""
44
+
45
+ #: inc/classes/class-astra-sites-importer-log.php:443
46
+ #: inc/classes/class-astra-sites-importer-log.php:500
47
+ msgid "No"
48
+ msgstr ""
49
+
50
+ #: inc/classes/class-astra-sites-importer.php:88
51
+ msgid "You have not \"customize\" access to import the Astra site."
52
+ msgstr ""
53
+
54
+ #: inc/classes/class-astra-sites-importer.php:112
55
+ msgid "Request site API URL is empty. Try again!"
56
+ msgstr ""
57
+
58
+ #: inc/classes/class-astra-sites-importer.php:204
59
+ msgid "Customizer data is empty!"
60
+ msgstr ""
61
+
62
+ #: inc/classes/class-astra-sites-importer.php:220
63
+ msgid ""
64
+ "If XMLReader is not available, it imports all other settings and only skips "
65
+ "XML import. This creates an incomplete website. We should bail early and "
66
+ "not import anything if this is not present."
67
+ msgstr ""
68
+
69
+ #: inc/classes/class-astra-sites-importer.php:236
70
+ msgid "There was an error downloading the XML file."
71
+ msgstr ""
72
+
73
+ #: inc/classes/class-astra-sites-importer.php:242
74
+ msgid "Invalid site XML file!"
75
+ msgstr ""
76
+
77
+ #: inc/classes/class-astra-sites-importer.php:264
78
+ msgid "Site options are empty!"
79
+ msgstr ""
80
+
81
+ #: inc/classes/class-astra-sites-importer.php:286
82
+ msgid "Widget data is empty!"
83
+ msgstr ""
84
+
85
+ #: inc/classes/class-astra-sites-page.php:113
86
+ msgid "Required XMLReader PHP extension is missing on your server!"
87
+ msgstr ""
88
+
89
+ #: inc/classes/class-astra-sites-page.php:115
90
+ #. translators: %s is the white label name.
91
+ msgid ""
92
+ "%s import requires XMLReader extension to be installed. Please contact your "
93
+ "web hosting provider and ask them to install and activate the XMLReader PHP "
94
+ "extension."
95
+ msgstr ""
96
+
97
+ #: inc/classes/class-astra-sites-page.php:216
98
+ msgid "Settings saved successfully."
99
+ msgstr ""
100
+
101
+ #: inc/classes/class-astra-sites-white-label.php:186
102
+ #. translators: %1$s product name
103
+ msgid "%1$s Branding"
104
+ msgstr ""
105
+
106
+ #: inc/classes/class-astra-sites.php:81
107
+ #. translators: 1: theme.php file
108
+ msgid ""
109
+ "Astra Theme needs to be active for you to use currently installed \"%1$s\" "
110
+ "plugin. <a href=\"%2$s\">Install & Activate Now</a>"
111
+ msgstr ""
112
+
113
+ #: inc/classes/class-astra-sites.php:121
114
+ msgid "See Library"
115
+ msgstr ""
116
+
117
+ #: inc/classes/class-astra-sites.php:174
118
+ msgid "Page Builder"
119
+ msgstr ""
120
+
121
+ #: inc/classes/class-astra-sites.php:179
122
+ msgid "Categories"
123
+ msgstr ""
124
+
125
+ #: inc/classes/class-astra-sites.php:218
126
+ msgid "Get Agency Bundle"
127
+ msgstr ""
128
+
129
+ #: inc/classes/class-astra-sites.php:220
130
+ msgid "Upgrade"
131
+ msgstr ""
132
+
133
+ #: inc/classes/class-astra-sites.php:227
134
+ #. translators: %s are HTML tags.
135
+ msgid ""
136
+ "%1$sRequired XMLReader PHP extension is missing on your server!%2$sAstra "
137
+ "Sites import requires XMLReader extension to be installed. Please contact "
138
+ "your web hosting provider and ask them to install and activate the "
139
+ "XMLReader PHP extension."
140
+ msgstr ""
141
+
142
+ #: inc/classes/class-astra-sites.php:228
143
+ msgid ""
144
+ "Warning! Astra Site Import process is not complete. Don't close the window "
145
+ "until import process complete. Do you still want to leave the window?"
146
+ msgstr ""
147
+
148
+ #: inc/classes/class-astra-sites.php:229
149
+ msgid "Error!"
150
+ msgstr ""
151
+
152
+ #: inc/classes/class-astra-sites.php:230
153
+ msgid "Error! Read Possibilities."
154
+ msgstr ""
155
+
156
+ #: inc/classes/class-astra-sites.php:232
157
+ msgid "Done! View Site"
158
+ msgstr ""
159
+
160
+ #: inc/classes/class-astra-sites.php:233
161
+ msgid "Activating"
162
+ msgstr ""
163
+
164
+ #: inc/classes/class-astra-sites.php:234
165
+ msgid "Active"
166
+ msgstr ""
167
+
168
+ #: inc/classes/class-astra-sites.php:235
169
+ msgid "Import failed."
170
+ msgstr ""
171
+
172
+ #: inc/classes/class-astra-sites.php:236
173
+ msgid "Import failed. See error log."
174
+ msgstr ""
175
+
176
+ #: inc/classes/class-astra-sites.php:237
177
+ msgid "Import This Site"
178
+ msgstr ""
179
+
180
+ #: inc/classes/class-astra-sites.php:238 inc/classes/class-astra-sites.php:255
181
+ msgid "Importing.."
182
+ msgstr ""
183
+
184
+ #: inc/classes/class-astra-sites.php:239 inc/includes/admin-page.php:159
185
+ msgid "Read more"
186
+ msgstr ""
187
+
188
+ #: inc/classes/class-astra-sites.php:240
189
+ msgid "Hide"
190
+ msgstr ""
191
+
192
+ #: inc/classes/class-astra-sites.php:241
193
+ msgid "There was a problem receiving a response from server."
194
+ msgstr ""
195
+
196
+ #: inc/classes/class-astra-sites.php:242 inc/includes/admin-page.php:319
197
+ msgid "No Demos found, Try a different search."
198
+ msgstr ""
199
+
200
+ #: inc/classes/class-astra-sites.php:243
201
+ msgid ""
202
+ "Executing Demo Import will make your site similar as ours. Please bear in "
203
+ "mind -\n"
204
+ "\n"
205
+ "1. It is recommended to run import on a fresh WordPress installation.\n"
206
+ "\n"
207
+ "2. Importing site does not delete any pages or posts. However, it can "
208
+ "overwrite your existing content.\n"
209
+ "\n"
210
+ "3. Copyrighted media will not be imported. Instead it will be replaced with "
211
+ "placeholders."
212
+ msgstr ""
213
+
214
+ #: inc/classes/class-astra-sites.php:246
215
+ msgid "Installing plugin "
216
+ msgstr ""
217
+
218
+ #: inc/classes/class-astra-sites.php:247
219
+ msgid "Successfully plugin installed!"
220
+ msgstr ""
221
+
222
+ #: inc/classes/class-astra-sites.php:248
223
+ msgid "Activating plugin "
224
+ msgstr ""
225
+
226
+ #: inc/classes/class-astra-sites.php:249
227
+ msgid "Successfully plugin activated "
228
+ msgstr ""
229
+
230
+ #: inc/classes/class-astra-sites.php:250
231
+ msgid "Bulk plugin activation..."
232
+ msgstr ""
233
+
234
+ #: inc/classes/class-astra-sites.php:251
235
+ msgid "Successfully plugin activate - "
236
+ msgstr ""
237
+
238
+ #: inc/classes/class-astra-sites.php:252
239
+ msgid "Error! While activating plugin - "
240
+ msgstr ""
241
+
242
+ #: inc/classes/class-astra-sites.php:253
243
+ msgid "Bulk plugin installation..."
244
+ msgstr ""
245
+
246
+ #: inc/classes/class-astra-sites.php:254
247
+ msgid "Site API "
248
+ msgstr ""
249
+
250
+ #: inc/classes/class-astra-sites.php:256
251
+ msgid "Processing requests..."
252
+ msgstr ""
253
+
254
+ #: inc/classes/class-astra-sites.php:257
255
+ msgid "1) Importing \"Customizer Settings\"..."
256
+ msgstr ""
257
+
258
+ #: inc/classes/class-astra-sites.php:258
259
+ msgid "Successfully imported customizer settings!"
260
+ msgstr ""
261
+
262
+ #: inc/classes/class-astra-sites.php:259
263
+ msgid "2) Importing \"WPForms\"..."
264
+ msgstr ""
265
+
266
+ #: inc/classes/class-astra-sites.php:260
267
+ msgid "Successfully imported WPForms!"
268
+ msgstr ""
269
+
270
+ #: inc/classes/class-astra-sites.php:261
271
+ msgid "3) Preparing \"XML\" Data..."
272
+ msgstr ""
273
+
274
+ #: inc/classes/class-astra-sites.php:262
275
+ msgid "Successfully set XML data!"
276
+ msgstr ""
277
+
278
+ #: inc/classes/class-astra-sites.php:263
279
+ msgid "4) Importing \"XML\"..."
280
+ msgstr ""
281
+
282
+ #: inc/classes/class-astra-sites.php:264
283
+ msgid "Successfully imported XML!"
284
+ msgstr ""
285
+
286
+ #: inc/classes/class-astra-sites.php:265
287
+ msgid "5) Importing \"Options\"..."
288
+ msgstr ""
289
+
290
+ #: inc/classes/class-astra-sites.php:266
291
+ msgid "Successfully imported Options!"
292
+ msgstr ""
293
+
294
+ #: inc/classes/class-astra-sites.php:267
295
+ msgid "6) Importing \"Widgets\"..."
296
+ msgstr ""
297
+
298
+ #: inc/classes/class-astra-sites.php:268
299
+ msgid "Successfully imported Widgets!"
300
+ msgstr ""
301
+
302
+ #: inc/classes/class-astra-sites.php:270
303
+ msgid "Site imported successfully! visit : "
304
+ msgstr ""
305
+
306
+ #: inc/classes/class-astra-sites.php:271
307
+ msgid "Getting Site Information.."
308
+ msgstr ""
309
+
310
+ #: inc/classes/class-astra-sites.php:272
311
+ msgid "Importing Customizer Settings.."
312
+ msgstr ""
313
+
314
+ #: inc/classes/class-astra-sites.php:273
315
+ msgid "Importing WP Forms.."
316
+ msgstr ""
317
+
318
+ #: inc/classes/class-astra-sites.php:274
319
+ msgid "Setting up import data.."
320
+ msgstr ""
321
+
322
+ #: inc/classes/class-astra-sites.php:275
323
+ msgid "Importing Pages, Posts & Media.."
324
+ msgstr ""
325
+
326
+ #: inc/classes/class-astra-sites.php:276
327
+ msgid "Importing Site Options.."
328
+ msgstr ""
329
+
330
+ #: inc/classes/class-astra-sites.php:277
331
+ msgid "Importing Widgets.."
332
+ msgstr ""
333
+
334
+ #: inc/classes/class-astra-sites.php:278
335
+ msgid "Import Complete.."
336
+ msgstr ""
337
+
338
+ #: inc/classes/class-astra-sites.php:279
339
+ msgid "Previewing "
340
+ msgstr ""
341
+
342
+ #: inc/classes/class-astra-sites.php:280
343
+ msgid "See Error Log &rarr;"
344
+ msgstr ""
345
+
346
+ #: inc/classes/class-astra-sites.php:315
347
+ msgid "No plugin specified"
348
+ msgstr ""
349
+
350
+ #: inc/classes/class-astra-sites.php:344
351
+ msgid "Plugin Successfully Activated"
352
+ msgstr ""
353
+
354
+ #: inc/importers/batch-processing/helpers/class-wp-background-process.php:433
355
+ msgid "Every %d Minutes"
356
+ msgstr ""
357
+
358
+ #: inc/importers/class-widgets-importer.php:83
359
+ msgid "Import data could not be read. Please try a different file."
360
+ msgstr ""
361
+
362
+ #: inc/importers/class-widgets-importer.php:127
363
+ msgid "Widget area does not exist in theme (using Inactive)"
364
+ msgstr ""
365
+
366
+ #: inc/importers/class-widgets-importer.php:149
367
+ msgid "Site does not support widget"
368
+ msgstr ""
369
+
370
+ #: inc/importers/class-widgets-importer.php:185
371
+ msgid "Widget already exists"
372
+ msgstr ""
373
+
374
+ #: inc/importers/class-widgets-importer.php:254
375
+ msgid "Imported"
376
+ msgstr ""
377
+
378
+ #: inc/importers/class-widgets-importer.php:257
379
+ msgid "Imported to Inactive"
380
+ msgstr ""
381
+
382
+ #: inc/importers/class-widgets-importer.php:263
383
+ msgid "No Title"
384
+ msgstr ""
385
+
386
+ #: inc/importers/wxr-importer/class-astra-wxr-importer.php:239
387
+ msgid "Import complete!"
388
+ msgstr ""
389
+
390
+ #: inc/importers/wxr-importer/class-wxr-importer.php:131
391
+ msgid "Could not open the file for parsing"
392
+ msgstr ""
393
+
394
+ #: inc/importers/wxr-importer/class-wxr-importer.php:167
395
+ #: inc/importers/wxr-importer/class-wxr-importer.php:283
396
+ #: inc/importers/wxr-importer/class-wxr-importer.php:356
397
+ msgid ""
398
+ "This WXR file (version %1$s) is newer than the importer (version %2$s) and "
399
+ "may not be supported. Please consider updating."
400
+ msgstr ""
401
+
402
+ #: inc/importers/wxr-importer/class-wxr-importer.php:504
403
+ msgid "The file does not exist, please try again."
404
+ msgstr ""
405
+
406
+ #: inc/importers/wxr-importer/class-wxr-importer.php:564
407
+ msgid "Invalid author mapping"
408
+ msgstr ""
409
+
410
+ #: inc/importers/wxr-importer/class-wxr-importer.php:665
411
+ msgid "Cannot import auto-draft posts"
412
+ msgstr ""
413
+
414
+ #: inc/importers/wxr-importer/class-wxr-importer.php:753
415
+ msgid "Failed to import \"%1$s\": Invalid post type %2$s"
416
+ msgstr ""
417
+
418
+ #: inc/importers/wxr-importer/class-wxr-importer.php:763
419
+ msgid "%1$s \"%2$s\" already exists."
420
+ msgstr ""
421
+
422
+ #: inc/importers/wxr-importer/class-wxr-importer.php:857
423
+ msgid "Skipping attachment \"%s\", fetching attachments disabled"
424
+ msgstr ""
425
+
426
+ #: inc/importers/wxr-importer/class-wxr-importer.php:878
427
+ msgid "Failed to import \"%1$s\" (%2$s)"
428
+ msgstr ""
429
+
430
+ #: inc/importers/wxr-importer/class-wxr-importer.php:910
431
+ #: inc/importers/wxr-importer/class-wxr-importer.php:1755
432
+ msgid "Imported \"%1$s\" (%2$s)"
433
+ msgstr ""
434
+
435
+ #: inc/importers/wxr-importer/class-wxr-importer.php:915
436
+ msgid "Post %1$d remapped to %2$d"
437
+ msgstr ""
438
+
439
+ #: inc/importers/wxr-importer/class-wxr-importer.php:1062
440
+ msgid "Invalid file type"
441
+ msgstr ""
442
+
443
+ #: inc/importers/wxr-importer/class-wxr-importer.php:1560
444
+ msgid "Failed to import user \"%s\""
445
+ msgstr ""
446
+
447
+ #: inc/importers/wxr-importer/class-wxr-importer.php:1581
448
+ msgid "Imported user \"%s\""
449
+ msgstr ""
450
+
451
+ #: inc/importers/wxr-importer/class-wxr-importer.php:1585
452
+ msgid "User %1$d remapped to %2$d"
453
+ msgstr ""
454
+
455
+ #: inc/importers/wxr-importer/class-wxr-importer.php:1731
456
+ msgid "Failed to import %1$s %2$s"
457
+ msgstr ""
458
+
459
+ #: inc/importers/wxr-importer/class-wxr-importer.php:1760
460
+ msgid "Term %1$d remapped to %2$d"
461
+ msgstr ""
462
+
463
+ #: inc/importers/wxr-importer/class-wxr-importer.php:1813
464
+ msgid "Remote server returned %1$d %2$s for %3$s"
465
+ msgstr ""
466
+
467
+ #: inc/importers/wxr-importer/class-wxr-importer.php:1826
468
+ msgid "Remote file is incorrect size"
469
+ msgstr ""
470
+
471
+ #: inc/importers/wxr-importer/class-wxr-importer.php:1831
472
+ msgid "Zero size file downloaded"
473
+ msgstr ""
474
+
475
+ #: inc/importers/wxr-importer/class-wxr-importer.php:1837
476
+ msgid "Remote file is too large, limit is %s"
477
+ msgstr ""
478
+
479
+ #: inc/importers/wxr-importer/class-wxr-importer.php:1859
480
+ msgid "Running post-processing for post %d"
481
+ msgstr ""
482
+
483
+ #: inc/importers/wxr-importer/class-wxr-importer.php:1872
484
+ msgid "Could not find the post parent for \"%1$s\" (post #%2$d)"
485
+ msgstr ""
486
+
487
+ #: inc/importers/wxr-importer/class-wxr-importer.php:1877
488
+ msgid "Post %1$d was imported with parent %2$d, but could not be found"
489
+ msgstr ""
490
+
491
+ #: inc/importers/wxr-importer/class-wxr-importer.php:1891
492
+ msgid "Could not find the author for \"%1$s\" (post #%2$d)"
493
+ msgstr ""
494
+
495
+ #: inc/importers/wxr-importer/class-wxr-importer.php:1896
496
+ msgid "Post %1$d was imported with author \"%2$s\", but could not be found"
497
+ msgstr ""
498
+
499
+ #: inc/importers/wxr-importer/class-wxr-importer.php:1922
500
+ msgid "Post %d was marked for post-processing, but none was required."
501
+ msgstr ""
502
+
503
+ #: inc/importers/wxr-importer/class-wxr-importer.php:1933
504
+ msgid "Could not update \"%1$s\" (post #%2$d) with mapped data"
505
+ msgstr ""
506
+
507
+ #: inc/importers/wxr-importer/class-wxr-importer.php:1978
508
+ msgid "Could not find the menu object for \"%1$s\" (post #%2$d)"
509
+ msgstr ""
510
+
511
+ #: inc/importers/wxr-importer/class-wxr-importer.php:1983
512
+ msgid ""
513
+ "Post %1$d was imported with object \"%2$d\" of type \"%3$s\", but could not "
514
+ "be found"
515
+ msgstr ""
516
+
517
+ #: inc/importers/wxr-importer/class-wxr-importer.php:2005
518
+ msgid "Could not find the comment parent for comment #%d"
519
+ msgstr ""
520
+
521
+ #: inc/importers/wxr-importer/class-wxr-importer.php:2009
522
+ msgid "Comment %1$d was imported with parent %2$d, but could not be found"
523
+ msgstr ""
524
+
525
+ #: inc/importers/wxr-importer/class-wxr-importer.php:2023
526
+ msgid "Could not find the author for comment #%d"
527
+ msgstr ""
528
+
529
+ #: inc/importers/wxr-importer/class-wxr-importer.php:2027
530
+ msgid "Comment %1$d was imported with author %2$d, but could not be found"
531
+ msgstr ""
532
+
533
+ #: inc/importers/wxr-importer/class-wxr-importer.php:2044
534
+ msgid "Could not update comment #%d with mapped data"
535
+ msgstr ""
536
+
537
+ #: inc/includes/admin-page.php:42
538
+ msgid "Search Sites"
539
+ msgstr ""
540
+
541
+ #: inc/includes/admin-page.php:43
542
+ msgid "Search Sites..."
543
+ msgstr ""
544
+
545
+ #: inc/includes/admin-page.php:72
546
+ msgid "Liked this demo?"
547
+ msgstr ""
548
+
549
+ #: inc/includes/admin-page.php:76
550
+ #. translators: %s is pricing page link
551
+ msgid ""
552
+ "It is a premium website demo which is available only with the Agency "
553
+ "Bundles <a href=\"%s\" target=\"_blank\">Buy Now!</a>"
554
+ msgstr ""
555
+
556
+ #: inc/includes/admin-page.php:82
557
+ #. translators: %s is article link
558
+ msgid ""
559
+ "Already own an Agency Bundle? Read an article to know how you can <a "
560
+ "href=\"%s\" target=\"_blank\">import a premium website demo</a>."
561
+ msgstr ""
562
+
563
+ #: inc/includes/admin-page.php:93
564
+ msgid "You are just 2 minutes away from importing this demo!"
565
+ msgstr ""
566
+
567
+ #: inc/includes/admin-page.php:94
568
+ msgid ""
569
+ "It is a premium website demo and you need to activate the license to access "
570
+ "it."
571
+ msgstr ""
572
+
573
+ #: inc/includes/admin-page.php:98
574
+ #. translators: %s is article link
575
+ msgid ""
576
+ "Learn how you can <a href=\"%s\" target=\"_blank\">activate the license</a> "
577
+ "of the Astra Premium Sites plugin."
578
+ msgstr ""
579
+
580
+ #: inc/includes/admin-page.php:113
581
+ msgid "Select Your Favorite Page Builder"
582
+ msgstr ""
583
+
584
+ #: inc/includes/admin-page.php:116
585
+ msgid "Sites List.."
586
+ msgstr ""
587
+
588
+ #: inc/includes/admin-page.php:140
589
+ msgid "Close"
590
+ msgstr ""
591
+
592
+ #: inc/includes/admin-page.php:141
593
+ msgid "Previous"
594
+ msgstr ""
595
+
596
+ #: inc/includes/admin-page.php:142
597
+ msgid "Next"
598
+ msgstr ""
599
+
600
+ #: inc/includes/admin-page.php:143 inc/includes/admin-page.php:171
601
+ msgid "Install Plugins"
602
+ msgstr ""
603
+
604
+ #: inc/includes/admin-page.php:162
605
+ msgid "Required Plugins"
606
+ msgstr ""
607
+
608
+ #: inc/includes/admin-page.php:177
609
+ msgid "Collapse"
610
+ msgstr ""
611
+
612
+ #: inc/includes/admin-page.php:183
613
+ msgid "Enter desktop preview mode"
614
+ msgstr ""
615
+
616
+ #: inc/includes/admin-page.php:186
617
+ msgid "Enter tablet preview mode"
618
+ msgstr ""
619
+
620
+ #: inc/includes/admin-page.php:189
621
+ msgid "Enter mobile preview mode"
622
+ msgstr ""
623
+
624
+ #: inc/includes/admin-page.php:197 inc/includes/admin-page.php:311
625
+ msgid "Preview"
626
+ msgstr ""
627
+
628
+ #: inc/includes/admin-page.php:212
629
+ #. translators: %1$s & %2$s are a Demo API URL
630
+ msgid ""
631
+ "<p> It seems the demo data server, <i><a href=\"%1$s\">%2$s</a></i> is "
632
+ "unreachable from your site.</p>"
633
+ msgstr ""
634
+
635
+ #: inc/includes/admin-page.php:214
636
+ msgid ""
637
+ "<p class=\"left-margin\"> 1. Sometimes, simple page reload fixes any "
638
+ "temporary issues. No kidding!</p>"
639
+ msgstr ""
640
+
641
+ #: inc/includes/admin-page.php:216
642
+ msgid ""
643
+ "<p class=\"left-margin\"> 2. If that does not work, you will need to talk "
644
+ "to your server administrator and check if demo server is being blocked by "
645
+ "the firewall!</p>"
646
+ msgstr ""
647
+
648
+ #: inc/includes/admin-page.php:219
649
+ #. translators: %1$s is a support link
650
+ msgid ""
651
+ "<p>If that does not help, please open up a <a href=\"%1$s\" "
652
+ "target=\"_blank\">Support Ticket</a> and we will be glad take a closer look "
653
+ "for you.</p>"
654
+ msgstr ""
655
+
656
+ #: inc/includes/admin-page.php:231
657
+ msgid "Under Maintenance.."
658
+ msgstr ""
659
+
660
+ #: inc/includes/admin-page.php:232
661
+ msgid ""
662
+ "If you are seeing this message, most likely our servers are under routine "
663
+ "maintenance and we will be back shortly. "
664
+ msgstr ""
665
+
666
+ #: inc/includes/admin-page.php:233
667
+ msgid ""
668
+ "In rare case, it is possible your website is having trouble connecting with "
669
+ "ours. If you need help, please feel free to get in touch with us from our "
670
+ "website."
671
+ msgstr ""
672
+
673
+ #: inc/includes/admin-page.php:300
674
+ msgid "Details &amp; Preview"
675
+ msgstr ""
676
+
677
+ #: inc/includes/admin-page.php:323 inc/includes/admin-page.php:341
678
+ #. translators: %1$s External Link
679
+ msgid ""
680
+ "Don't see a site that you would like to import?<br><a target=\"_blank\" "
681
+ "href=\"%1$s\">Please suggest us!</a>"
682
+ msgstr ""
683
+
684
+ #: inc/includes/white-label.php:29
685
+ msgid "Plugin Name:"
686
+ msgstr ""
687
+
688
+ #: inc/includes/white-label.php:34
689
+ msgid "Plugin Description:"
690
+ msgstr ""
691
+
692
+ #. Plugin Name of the plugin/theme
693
+ msgid "Astra Starter Sites – Elementor, Beaver Builder & Gutenberg Templates"
694
+ msgstr ""
695
+
696
+ #. Plugin URI of the plugin/theme
697
+ msgid "http://www.wpastra.com/pro/"
698
+ msgstr ""
699
+
700
+ #. Description of the plugin/theme
701
+ msgid "Import free sites build with Astra theme."
702
+ msgstr ""
703
+
704
+ #. Author of the plugin/theme
705
+ msgid "Brainstorm Force"
706
+ msgstr ""
707
+
708
+ #. Author URI of the plugin/theme
709
+ msgid "http://www.brainstormforce.com"
710
+ msgstr ""
711
+
712
+ #: inc/classes/class-astra-sites-importer-log.php:373
713
+ #. translators: %1$s Memory Limit, %2$s Recommended memory limit.
714
+ msgctxt "Recommended Memory Limit"
715
+ msgid "Current memory limit %1$s. We recommend setting memory to at least %2$s."
716
+ msgstr ""
717
+
718
+ #: inc/classes/class-astra-sites-importer-log.php:454
719
+ msgctxt "PHP Version"
720
+ msgid "We recommend to use php 5.4 or higher"
721
  msgstr ""
readme.txt CHANGED
@@ -1,282 +1,285 @@
1
- === Astra Starter Sites – Elementor, Beaver Builder & Gutenberg Templates ===
2
- Contributors: brainstormforce
3
- Donate link: https://wpastra.com/pro/
4
- Tags: Elementor,Beaver Builder,Templates,Gutenberg,Astra Starter Sites
5
- Requires at least: 4.4
6
- Requires PHP: 5.3
7
- Tested up to: 5.1
8
- Stable tag: 1.2.13
9
- License: GPLv2 or later
10
- License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
-
12
- The growing library of 90+ ready-to-use free website templates built for Elementor, Beaver Builder page builder and the default WordPress editor Gutenberg.
13
-
14
- == Description ==
15
-
16
- = FREE TEMPLATES FOR ELEMENTOR, BEAVER BUILDER AND GUTENBERG =
17
-
18
- Create professional designed pixel perfect websites in minutes with the Astra Starter Sites plugin.
19
-
20
- This plugin gives you access to 90+ pre-made full website demos for your favorite page builder such as Elementor, Beaver Builder, Brizy and the WordPress default editor Gutenberg.
21
-
22
- All you need to do is select the demo that suits your needs, import, tweak and go live!
23
-
24
- > I love the fact that the Astra Starter Sites plugin comes with dozens of pre-built sites that were built using Elementor and that can be used to create a full website with one click. - Ben Pines, CMO at Elementor
25
-
26
- > Astra Sites allows anyone to have a beautiful website in under 5 minutes while using all open source software. The theme is free, the plugin is free, it’s almost unbelievable. You have to see it with your own eyes. - Adam Preiser, WPCrafter
27
-
28
- = GET A WEBSITE LIVE IN 5 CLICKS! =
29
-
30
- 1.Install and activate Astra Starter Sites Plugin
31
- 2.Pick a website demo that suits your needs
32
- 3.Install required plugins with a single click
33
- 4.Import the website
34
- 5.Done!
35
-
36
- = FULL WEBSITE TEMPLATES FOR =
37
-
38
- Businesses like restaurants, lawyers, agencies, interior designers, artist shops, brandstore, pet services, charity, plumber, dental clinic, construction, fitness trainer, gardening, makeup artist and a lot more. You can take a look at all of them built with different page builders.
39
-
40
- - [Elementor Free Website Templates](https://wpastra.com/ready-websites/?page-builder=elementor&category=free)
41
- - [Beaver Builder Free Website Templates](https://wpastra.com/ready-websites/?page-builder=beaver-builder&category=free)
42
- - [Gutenberg Free Website Templates](https://wpastra.com/ready-websites/?page-builder=gutenberg&category=free)
43
- - [Brizy Free Website Templates](https://wpastra.com/ready-websites/?page-builder=brizy&category=free)
44
-
45
- You can extend this library with premium ready-to-use website demos by purchasing one of the Agency Bundles, i.e. either the Mini Agency Bundle or the Agency Bundle.
46
-
47
- = WHY PEOPLE LOVE THE ASTRA THEME? =
48
-
49
- Over 200,000+ users are empowering their websites with Astra! From beginners to industry experts, everyone is loving Astra for its performance and ease of use.
50
-
51
- = Here are a few reasons why they love Astra - =
52
-
53
- **Faster Performance** - Built with speed and performance in mind, Astra follows the best coding standards and lets you build faster loading and better performing websites.
54
-
55
- **Easy Customization** - With all the settings managed through the customizer, Astra keeps it simple and gives you lots of options to customize everything with a few clicks.
56
-
57
- **Pixel Perfect Design** - Astra reduces your design time by giving you pixel-perfect FREE ready-to-use websites demos within a huge library of starter sites.
58
-
59
- **Deeper Integrations** - Astra works seamlessly with all WooCommerce plugins, LifterLMS, LearnDash etc. This means that you can create and beautify eCommerce websites and those that offer online courses in minutes.
60
-
61
- Fetch the website, tweak images and content and go live!
62
-
63
- Use this imported site as a base for your project and don't waste time starting from scratch!
64
-
65
- _<a href="https://wpastra.com/ready-websites/?utm_source=wp-repo&utm_medium=link&utm_campaign=readme">See list of all available sites to import »</a>_
66
-
67
- #### Video Walkthrough by Adam from WPCrafter:
68
- [youtube https://www.youtube.com/watch?v=zYbz-jxE9_Q]
69
-
70
- == Installation ==
71
-
72
- 1. Upload the plugin files to the `/wp-content/plugins/astra-sites` directory, or install the plugin through the WordPress plugins screen directly.
73
- 2. Activate the plugin through the 'Plugins' screen in WordPress.
74
- 3. Navigate to Appearance -> Astra Sites to preview and import sites.
75
-
76
- == Frequently Asked Questions ==
77
-
78
- = Will the Astra Starter Sites work with my theme? =
79
-
80
- All the website demos are built using the Astra theme. Therefore, in order to use the Astra Starter Sites plugin and import a ready-to-use website, you will need to have the Astra theme installed.
81
-
82
- = Are all the starter sites free? =
83
-
84
- You get over 90+ FREE ready-to-use websites as of now. There are many more premium website demos that can be accessed when you purchase one of our Agency Bundles.
85
-
86
- = How can I import and install the starter sites? =
87
-
88
- Here is an article that will help you [install and import Astra starter sites](https://wpastra.com/docs/installing-importing-astra-sites/?utm_source=wp-repo&utm_medium=link&utm_campaign=readme) on your website.
89
-
90
-
91
- = Can I import a website demo on an existing website? =
92
-
93
- It is recommended to install and import a website demo on a fresh WordPress installation or a blank website to avoid overriding of settings and page design.
94
-
95
- = Can I deactivate the Astra Starter Sites plugin after importing a website? =
96
-
97
- Yes! The Astra Strater Sites plugin acts as a medium through which you can import and install a website from our cloud server. Once you have the website at your end, you can go ahead and deactivate the plugin.
98
-
99
- = Do I need to install any other plugin before importing a website? =
100
-
101
- You just need to activate the Astra theme and import the website through the Astra Starter Sites plugin. During the process of importing, you will come across a step in which you can install necessary plugins with one click.
102
-
103
- = Will you add more website demos? =
104
-
105
- Yes! We are working on many more free website demos built using Elementor, Beaver Builder, Gutenberg and Brizy.
106
-
107
- = What if I do not find a website for the topic I am looking for? =
108
-
109
- We are open to suggestions and would love to work on topics that our users are looking out for. Please feel free to drop your suggestions through the form [here](https://wpastra.com/sites-suggestions/?utm_source=wp-repo&utm_medium=link&utm_campaign=readme).
110
-
111
-
112
- == Screenshots ==
113
-
114
- 1. Select the demo you want to import.
115
- 2. Install and activate the required plugins.
116
- 3. Import the demo.
117
-
118
- == Changelog ==
119
-
120
- v1.2.13 - 12-March-2019
121
- - Improvement: Improved logic to download images in the Elementor templates.
122
- - Improvement: Added description of the Agency sites when license is not activated.
123
- - Fix: Incorrect images was set after batch process complete.
124
-
125
- v1.2.12 - 29-Jan-2019
126
- - Fix: Gutenberg render markup is invalid due to encoded characterless e.g. <, > are decoded into HTML tag.
127
-
128
- v1.2.11 - 24-Jan-2019
129
- - Improvement: Display a maintenance message if the Astra Sites API is unreachable.
130
- - Fix: EventSource abort the import process if default charset is not UTF-8.
131
-
132
- v1.2.10 - 4-Jan-2019
133
- - Fix: Astra Sites not accessible due to incorrect query parameters.
134
-
135
- v1.2.9 - 17-Dec-2018
136
- - Fix: XML not import due to getting different MIME file types on different PHP versions.
137
-
138
- v1.2.8 - 14-Dec-2018
139
- - Improvement: Added admin notice if XMLReader is not installed. XMLReader is required to import the XML of the website.
140
- - Fix: XML not import due to improved verification of MIME file types in WordPress v5.0.1.
141
-
142
- v1.2.7 - 12-July-2018
143
- - Improvement: Added page builder and category filter support to show selected page builder with selected categories.
144
- - Improvement: Added filter `astra_sites_show_filters` to enable/disable the filter list from admin page.
145
-
146
- v1.2.6 - 9-July-2018
147
- - Fix: We have added `wp_slash` to normalize the Elementor post meta. Elementor have also normalize it. So, We have avoided `wp_slash` while importing sites.
148
-
149
- v1.2.5 - 5-July-2018
150
- - Fix: Normalize Elementor post meta by using `wp_slash` to avoid the unslashing data.
151
-
152
- v1.2.4 - 29-June-2018
153
- - Improvement: Removed custom license validation form and used Graupi in-build license validation form.
154
- - Improvement: Set default page builders depends on the packaged purchase.
155
-
156
- v1.2.3 - 13-June-2018
157
- - Improvement: Added windows EDGE browser support for importing the sites.
158
- - Improvement: The log file was not created if server does not support the file handling functions.
159
- - Fix: Load WXR importer on init to avoid redirect loop when loading WooCommerce importer.
160
- - Fix: Clear the Astra Pro plugin cache after site import.
161
-
162
- v1.2.2 - 26-March-2018
163
- - Fix: Correctly load the Elementor Pro 2.0 compatibility class for beta versions.
164
-
165
- v1.2.1 - 23-March-2018
166
- - Improvement: Clear the Astra Pro plugin cache after site import.
167
-
168
- v1.2.0 - 22-March-2018
169
- - Improvement: Added compatibility for Elemetor version 2.0.0. Older versions throw the PHP warning for function process_element_export_import_content().
170
-
171
- v1.1.9 - 12-March-2018
172
- - Fix: String `Select Your Favorite Page Builder` jerk while loading the sites.
173
-
174
- v1.1.8 - 5-March-2018
175
- - Improvements: Updated processing button animation while installation/activating plugin and importing site.
176
- - Improvements: Updated suggestion box message.
177
- - Fix: PHP fatal errors for WXR importer classes `WXR_Import_Info`, `WXR_Importer`, `WP_Importer_Logger_ServerSentEvents` and `WP_Importer_Logger`.
178
-
179
- v1.1.7 - 2-February-2018
180
- - Improvements: Some users reported confusion in the default option of choosing page builder. We have made UX improvements so users now must select the Page Builder first before selecting any website.
181
-
182
- v1.1.6 - 22-January-2018
183
- - New: Added filter `astra_sites_xml_import_options` to change the XML import options.
184
- - Fix: Astra Pro plugin 'Custom Layouts' & 'Page Headers' not setting right display location due to different page, tax, category ids.
185
- - Fix: WooCommerce shop, checkout cart page ids not setting issue.
186
- - Fix: After site import updated demo url from the nav menus.
187
-
188
- v1.1.5 - 11-January-2018
189
- - New: Added SVG file support for importing the SVG images.
190
-
191
- v1.1.4 - 28-Dec-2017
192
- - Improvement: Importing WooCommerce product category images.
193
- - Improvement: Retain WooCommerce cart, checkout & my account pages when importing the ready WooCommerce sites.
194
- - Fix: Disabled WooCommerce plugin setup wizard after plugin install & activate.
195
-
196
- v1.1.3 - 20-Dec-2017
197
- - Improvement: Retain WooCommerce shop page when importing the ready WooCommerce sites.
198
-
199
- v1.1.2 - 24-Nov-2017
200
- - Fix: Handling plugin installation errors.
201
-
202
- v1.1.1 - 23-Nov-2017
203
- - New: Change the api url for Astra sites to https://websitedemos.net/ from https://sites.wpastra.com/
204
-
205
- v1.1.0 - 21-Nov-2017
206
- - New: Import the site content using Event Source (SSE) which ensures faithful imports.
207
- - New: Divided the site import process in separate AJAX calls to reduce the possibility of timeouts.
208
- - New: Generated the import log file. It will be displayed in the UI if the import fails.
209
- - Improvement: Validate all the possible errors.
210
- - Improvement: Updated Astra sites HTML grid structure for WordPress v4.9 compatibility.
211
- - Enhancement: Updated plugin name from Astra Sites - Lite with Astra Starter Sites.
212
-
213
- v1.0.14 - 9-Nov-2017
214
- - New: All the linked images on the Astra Sites will be downloaded to your site, No more loading images from external URLs.
215
- - New: Added suggestion box at as the last column in when listing sites so that you can add a suggest the sites you want.
216
- - New: Added site responsive preview buttons.
217
- - Improvement: Search string will not be removed when switching the page builder when scrolling through sites.
218
- - Improvement: Loading 15 sites instead of 6 Astra sites in the first load.
219
- - Improvement: Removed LazyLoad which is not useful in admin back-end for showing Astra Sites.
220
-
221
- v1.0.13 - 9-Oct-2017
222
- - New: Browsing the Astra Sites in the Admin panel is not faster with JS rendering.
223
-
224
- v1.0.12 - 29-Sept-2017
225
- - New: Added White Label support from <a href="https://wpastra.com/pro/">Astra Pro</a>.
226
- - Improvement: Don't display sites from both the page builders in the same view.
227
- - Fix: Astra Sites admin area not working in the Firefox.
228
-
229
- v1.0.11 - 22-Sept-2017
230
- - New: Single click Install & activate required plugins.
231
- - New: Added filter `astra_sites_menu_item` for adding extra tabs in admin page.
232
- - New: Added back image import feature for `elementor` page builder. In batch image import we import all images from astra site into client site.
233
- - Improvement: Updated JS code with object prototype.
234
- - Fix: Screen bounce on retina devices.
235
-
236
- v1.0.10 - 11-Sept-2017
237
- - Improvement: Added support for retina logo import.
238
- - Fix: Site logo image not displayed in customizer.
239
- - Fix: Updated `Astra Agency` purchase link.
240
-
241
- v1.0.9 - 8-Sept-2017
242
- - New: Added page builder categories for listing sites as per page builder.
243
-
244
- v1.0.8 - 6-Sept-2017
245
- - Fix: Beaver Builder option import.
246
- - Enhancement: Disabled dismiss-able notice visible once for each user.
247
- - Enhancement: Showing error message for for user who have not `manage_plugins` capability.
248
-
249
- v1.0.7 - 1-Sept-2017
250
- - Fix: Custom Menu widget not setting imported widget.
251
-
252
- v1.0.6 - 30-Aug-2017
253
- - New: Addd custom menu for Astra Sites.
254
- - Fix: Validate site options before storing in database.
255
-
256
- v1.0.5 - 29-Aug-2017
257
- - New: Added filter `astra_sites_api_args` for adding extra arguments in api call.
258
- - Enhancement: Plugin name updated from `Astra Sites` with `Astra Free Sites`.
259
- - Fix: PHP error while ignoring users.
260
-
261
- v1.0.4 - 21-Aug-2017
262
- - New: Added filter `astra_sites_api_params` for adding extra params in api call.
263
- - New: Added filter `astra_sites_api_args` for adding extra arguments in api call.
264
- - New: Added filter `astra_sites_category_hide_empty` for showing categories which are not set for any site.
265
-
266
- v1.0.3 - 11-Aug-2017
267
- - Fix: Avoided Astra users from site import process.
268
-
269
- v1.0.2 - 09-Aug-2017
270
- - Fix: Listing appropriate next and previous Astra sites.
271
- - Enhancement: Listing Astra sites though AJAX API call.
272
-
273
- v1.0.1 - 04-Aug-2017
274
- - New: Added Elementor plugin options support.
275
- - New: Added Customizer CSS support.
276
- - Enhancement: Avoided Lite Plugin version if Pro version is Installed. Now added support for Beaver Builder Plugin (Lite Version).
277
- - Enhancement: Astra sites API call validated before import.
278
- - Enhancement: Site logo imported from Astra sites.
279
- - Fix: Bug where widgets created with SiteOrigin plugin were not being imported.
280
-
281
- v1.0.0
282
- - Initial release
 
 
 
1
+ === Astra Starter Sites – Elementor, Beaver Builder & Gutenberg Templates ===
2
+ Contributors: brainstormforce
3
+ Donate link: https://wpastra.com/pro/
4
+ Tags: Elementor,Beaver Builder,Templates,Gutenberg,Astra Starter Sites
5
+ Requires at least: 4.4
6
+ Requires PHP: 5.3
7
+ Tested up to: 5.1
8
+ Stable tag: 1.2.14
9
+ License: GPLv2 or later
10
+ License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
+
12
+ The growing library of 90+ ready-to-use free website templates built for Elementor, Beaver Builder page builder and the default WordPress editor Gutenberg.
13
+
14
+ == Description ==
15
+
16
+ = FREE TEMPLATES FOR ELEMENTOR, BEAVER BUILDER AND GUTENBERG =
17
+
18
+ Create professional designed pixel perfect websites in minutes with the Astra Starter Sites plugin.
19
+
20
+ This plugin gives you access to 90+ pre-made full website demos for your favorite page builder such as Elementor, Beaver Builder, Brizy and the WordPress default editor Gutenberg.
21
+
22
+ All you need to do is select the demo that suits your needs, import, tweak and go live!
23
+
24
+ > I love the fact that the Astra Starter Sites plugin comes with dozens of pre-built sites that were built using Elementor and that can be used to create a full website with one click. - Ben Pines, CMO at Elementor
25
+
26
+ > Astra Sites allows anyone to have a beautiful website in under 5 minutes while using all open source software. The theme is free, the plugin is free, it’s almost unbelievable. You have to see it with your own eyes. - Adam Preiser, WPCrafter
27
+
28
+ = GET A WEBSITE LIVE IN 5 CLICKS! =
29
+
30
+ 1.Install and activate Astra Starter Sites Plugin
31
+ 2.Pick a website demo that suits your needs
32
+ 3.Install required plugins with a single click
33
+ 4.Import the website
34
+ 5.Done!
35
+
36
+ = FULL WEBSITE TEMPLATES FOR =
37
+
38
+ Businesses like restaurants, lawyers, agencies, interior designers, artist shops, brandstore, pet services, charity, plumber, dental clinic, construction, fitness trainer, gardening, makeup artist and a lot more. You can take a look at all of them built with different page builders.
39
+
40
+ - [Elementor Free Website Templates](https://wpastra.com/ready-websites/?page-builder=elementor&category=free)
41
+ - [Beaver Builder Free Website Templates](https://wpastra.com/ready-websites/?page-builder=beaver-builder&category=free)
42
+ - [Gutenberg Free Website Templates](https://wpastra.com/ready-websites/?page-builder=gutenberg&category=free)
43
+ - [Brizy Free Website Templates](https://wpastra.com/ready-websites/?page-builder=brizy&category=free)
44
+
45
+ You can extend this library with premium ready-to-use website demos by purchasing one of the Agency Bundles, i.e. either the Mini Agency Bundle or the Agency Bundle.
46
+
47
+ = WHY PEOPLE LOVE THE ASTRA THEME? =
48
+
49
+ Over 200,000+ users are empowering their websites with Astra! From beginners to industry experts, everyone is loving Astra for its performance and ease of use.
50
+
51
+ = Here are a few reasons why they love Astra - =
52
+
53
+ **Faster Performance** - Built with speed and performance in mind, Astra follows the best coding standards and lets you build faster loading and better performing websites.
54
+
55
+ **Easy Customization** - With all the settings managed through the customizer, Astra keeps it simple and gives you lots of options to customize everything with a few clicks.
56
+
57
+ **Pixel Perfect Design** - Astra reduces your design time by giving you pixel-perfect FREE ready-to-use websites demos within a huge library of starter sites.
58
+
59
+ **Deeper Integrations** - Astra works seamlessly with all WooCommerce plugins, LifterLMS, LearnDash etc. This means that you can create and beautify eCommerce websites and those that offer online courses in minutes.
60
+
61
+ Fetch the website, tweak images and content and go live!
62
+
63
+ Use this imported site as a base for your project and don't waste time starting from scratch!
64
+
65
+ _<a href="https://wpastra.com/ready-websites/?utm_source=wp-repo&utm_medium=link&utm_campaign=readme">See list of all available sites to import »</a>_
66
+
67
+ #### Video Walkthrough by Adam from WPCrafter:
68
+ [youtube https://www.youtube.com/watch?v=zYbz-jxE9_Q]
69
+
70
+ == Installation ==
71
+
72
+ 1. Upload the plugin files to the `/wp-content/plugins/astra-sites` directory, or install the plugin through the WordPress plugins screen directly.
73
+ 2. Activate the plugin through the 'Plugins' screen in WordPress.
74
+ 3. Navigate to Appearance -> Astra Sites to preview and import sites.
75
+
76
+ == Frequently Asked Questions ==
77
+
78
+ = Will the Astra Starter Sites work with my theme? =
79
+
80
+ All the website demos are built using the Astra theme. Therefore, in order to use the Astra Starter Sites plugin and import a ready-to-use website, you will need to have the Astra theme installed.
81
+
82
+ = Are all the starter sites free? =
83
+
84
+ You get over 90+ FREE ready-to-use websites as of now. There are many more premium website demos that can be accessed when you purchase one of our Agency Bundles.
85
+
86
+ = How can I import and install the starter sites? =
87
+
88
+ Here is an article that will help you [install and import Astra starter sites](https://wpastra.com/docs/installing-importing-astra-sites/?utm_source=wp-repo&utm_medium=link&utm_campaign=readme) on your website.
89
+
90
+
91
+ = Can I import a website demo on an existing website? =
92
+
93
+ It is recommended to install and import a website demo on a fresh WordPress installation or a blank website to avoid overriding of settings and page design.
94
+
95
+ = Can I deactivate the Astra Starter Sites plugin after importing a website? =
96
+
97
+ Yes! The Astra Strater Sites plugin acts as a medium through which you can import and install a website from our cloud server. Once you have the website at your end, you can go ahead and deactivate the plugin.
98
+
99
+ = Do I need to install any other plugin before importing a website? =
100
+
101
+ You just need to activate the Astra theme and import the website through the Astra Starter Sites plugin. During the process of importing, you will come across a step in which you can install necessary plugins with one click.
102
+
103
+ = Will you add more website demos? =
104
+
105
+ Yes! We are working on many more free website demos built using Elementor, Beaver Builder, Gutenberg and Brizy.
106
+
107
+ = What if I do not find a website for the topic I am looking for? =
108
+
109
+ We are open to suggestions and would love to work on topics that our users are looking out for. Please feel free to drop your suggestions through the form [here](https://wpastra.com/sites-suggestions/?utm_source=wp-repo&utm_medium=link&utm_campaign=readme).
110
+
111
+
112
+ == Screenshots ==
113
+
114
+ 1. Select the demo you want to import.
115
+ 2. Install and activate the required plugins.
116
+ 3. Import the demo.
117
+
118
+ == Changelog ==
119
+
120
+ v1.2.14 - 13-March-2019
121
+ - Improvement: Added support for the WPForms plugin.
122
+
123
+ v1.2.13 - 12-March-2019
124
+ - Improvement: Improved logic to download images in the Elementor templates.
125
+ - Improvement: Added description of the Agency sites when license is not activated.
126
+ - Fix: Incorrect images was set after batch process complete.
127
+
128
+ v1.2.12 - 29-Jan-2019
129
+ - Fix: Gutenberg render markup is invalid due to encoded characterless e.g. <, > are decoded into HTML tag.
130
+
131
+ v1.2.11 - 24-Jan-2019
132
+ - Improvement: Display a maintenance message if the Astra Sites API is unreachable.
133
+ - Fix: EventSource abort the import process if default charset is not UTF-8.
134
+
135
+ v1.2.10 - 4-Jan-2019
136
+ - Fix: Astra Sites not accessible due to incorrect query parameters.
137
+
138
+ v1.2.9 - 17-Dec-2018
139
+ - Fix: XML not import due to getting different MIME file types on different PHP versions.
140
+
141
+ v1.2.8 - 14-Dec-2018
142
+ - Improvement: Added admin notice if XMLReader is not installed. XMLReader is required to import the XML of the website.
143
+ - Fix: XML not import due to improved verification of MIME file types in WordPress v5.0.1.
144
+
145
+ v1.2.7 - 12-July-2018
146
+ - Improvement: Added page builder and category filter support to show selected page builder with selected categories.
147
+ - Improvement: Added filter `astra_sites_show_filters` to enable/disable the filter list from admin page.
148
+
149
+ v1.2.6 - 9-July-2018
150
+ - Fix: We have added `wp_slash` to normalize the Elementor post meta. Elementor have also normalize it. So, We have avoided `wp_slash` while importing sites.
151
+
152
+ v1.2.5 - 5-July-2018
153
+ - Fix: Normalize Elementor post meta by using `wp_slash` to avoid the unslashing data.
154
+
155
+ v1.2.4 - 29-June-2018
156
+ - Improvement: Removed custom license validation form and used Graupi in-build license validation form.
157
+ - Improvement: Set default page builders depends on the packaged purchase.
158
+
159
+ v1.2.3 - 13-June-2018
160
+ - Improvement: Added windows EDGE browser support for importing the sites.
161
+ - Improvement: The log file was not created if server does not support the file handling functions.
162
+ - Fix: Load WXR importer on init to avoid redirect loop when loading WooCommerce importer.
163
+ - Fix: Clear the Astra Pro plugin cache after site import.
164
+
165
+ v1.2.2 - 26-March-2018
166
+ - Fix: Correctly load the Elementor Pro 2.0 compatibility class for beta versions.
167
+
168
+ v1.2.1 - 23-March-2018
169
+ - Improvement: Clear the Astra Pro plugin cache after site import.
170
+
171
+ v1.2.0 - 22-March-2018
172
+ - Improvement: Added compatibility for Elemetor version 2.0.0. Older versions throw the PHP warning for function process_element_export_import_content().
173
+
174
+ v1.1.9 - 12-March-2018
175
+ - Fix: String `Select Your Favorite Page Builder` jerk while loading the sites.
176
+
177
+ v1.1.8 - 5-March-2018
178
+ - Improvements: Updated processing button animation while installation/activating plugin and importing site.
179
+ - Improvements: Updated suggestion box message.
180
+ - Fix: PHP fatal errors for WXR importer classes `WXR_Import_Info`, `WXR_Importer`, `WP_Importer_Logger_ServerSentEvents` and `WP_Importer_Logger`.
181
+
182
+ v1.1.7 - 2-February-2018
183
+ - Improvements: Some users reported confusion in the default option of choosing page builder. We have made UX improvements so users now must select the Page Builder first before selecting any website.
184
+
185
+ v1.1.6 - 22-January-2018
186
+ - New: Added filter `astra_sites_xml_import_options` to change the XML import options.
187
+ - Fix: Astra Pro plugin 'Custom Layouts' & 'Page Headers' not setting right display location due to different page, tax, category ids.
188
+ - Fix: WooCommerce shop, checkout cart page ids not setting issue.
189
+ - Fix: After site import updated demo url from the nav menus.
190
+
191
+ v1.1.5 - 11-January-2018
192
+ - New: Added SVG file support for importing the SVG images.
193
+
194
+ v1.1.4 - 28-Dec-2017
195
+ - Improvement: Importing WooCommerce product category images.
196
+ - Improvement: Retain WooCommerce cart, checkout & my account pages when importing the ready WooCommerce sites.
197
+ - Fix: Disabled WooCommerce plugin setup wizard after plugin install & activate.
198
+
199
+ v1.1.3 - 20-Dec-2017
200
+ - Improvement: Retain WooCommerce shop page when importing the ready WooCommerce sites.
201
+
202
+ v1.1.2 - 24-Nov-2017
203
+ - Fix: Handling plugin installation errors.
204
+
205
+ v1.1.1 - 23-Nov-2017
206
+ - New: Change the api url for Astra sites to https://websitedemos.net/ from https://sites.wpastra.com/
207
+
208
+ v1.1.0 - 21-Nov-2017
209
+ - New: Import the site content using Event Source (SSE) which ensures faithful imports.
210
+ - New: Divided the site import process in separate AJAX calls to reduce the possibility of timeouts.
211
+ - New: Generated the import log file. It will be displayed in the UI if the import fails.
212
+ - Improvement: Validate all the possible errors.
213
+ - Improvement: Updated Astra sites HTML grid structure for WordPress v4.9 compatibility.
214
+ - Enhancement: Updated plugin name from Astra Sites - Lite with Astra Starter Sites.
215
+
216
+ v1.0.14 - 9-Nov-2017
217
+ - New: All the linked images on the Astra Sites will be downloaded to your site, No more loading images from external URLs.
218
+ - New: Added suggestion box at as the last column in when listing sites so that you can add a suggest the sites you want.
219
+ - New: Added site responsive preview buttons.
220
+ - Improvement: Search string will not be removed when switching the page builder when scrolling through sites.
221
+ - Improvement: Loading 15 sites instead of 6 Astra sites in the first load.
222
+ - Improvement: Removed LazyLoad which is not useful in admin back-end for showing Astra Sites.
223
+
224
+ v1.0.13 - 9-Oct-2017
225
+ - New: Browsing the Astra Sites in the Admin panel is not faster with JS rendering.
226
+
227
+ v1.0.12 - 29-Sept-2017
228
+ - New: Added White Label support from <a href="https://wpastra.com/pro/">Astra Pro</a>.
229
+ - Improvement: Don't display sites from both the page builders in the same view.
230
+ - Fix: Astra Sites admin area not working in the Firefox.
231
+
232
+ v1.0.11 - 22-Sept-2017
233
+ - New: Single click Install & activate required plugins.
234
+ - New: Added filter `astra_sites_menu_item` for adding extra tabs in admin page.
235
+ - New: Added back image import feature for `elementor` page builder. In batch image import we import all images from astra site into client site.
236
+ - Improvement: Updated JS code with object prototype.
237
+ - Fix: Screen bounce on retina devices.
238
+
239
+ v1.0.10 - 11-Sept-2017
240
+ - Improvement: Added support for retina logo import.
241
+ - Fix: Site logo image not displayed in customizer.
242
+ - Fix: Updated `Astra Agency` purchase link.
243
+
244
+ v1.0.9 - 8-Sept-2017
245
+ - New: Added page builder categories for listing sites as per page builder.
246
+
247
+ v1.0.8 - 6-Sept-2017
248
+ - Fix: Beaver Builder option import.
249
+ - Enhancement: Disabled dismiss-able notice visible once for each user.
250
+ - Enhancement: Showing error message for for user who have not `manage_plugins` capability.
251
+
252
+ v1.0.7 - 1-Sept-2017
253
+ - Fix: Custom Menu widget not setting imported widget.
254
+
255
+ v1.0.6 - 30-Aug-2017
256
+ - New: Addd custom menu for Astra Sites.
257
+ - Fix: Validate site options before storing in database.
258
+
259
+ v1.0.5 - 29-Aug-2017
260
+ - New: Added filter `astra_sites_api_args` for adding extra arguments in api call.
261
+ - Enhancement: Plugin name updated from `Astra Sites` with `Astra Free Sites`.
262
+ - Fix: PHP error while ignoring users.
263
+
264
+ v1.0.4 - 21-Aug-2017
265
+ - New: Added filter `astra_sites_api_params` for adding extra params in api call.
266
+ - New: Added filter `astra_sites_api_args` for adding extra arguments in api call.
267
+ - New: Added filter `astra_sites_category_hide_empty` for showing categories which are not set for any site.
268
+
269
+ v1.0.3 - 11-Aug-2017
270
+ - Fix: Avoided Astra users from site import process.
271
+
272
+ v1.0.2 - 09-Aug-2017
273
+ - Fix: Listing appropriate next and previous Astra sites.
274
+ - Enhancement: Listing Astra sites though AJAX API call.
275
+
276
+ v1.0.1 - 04-Aug-2017
277
+ - New: Added Elementor plugin options support.
278
+ - New: Added Customizer CSS support.
279
+ - Enhancement: Avoided Lite Plugin version if Pro version is Installed. Now added support for Beaver Builder Plugin (Lite Version).
280
+ - Enhancement: Astra sites API call validated before import.
281
+ - Enhancement: Site logo imported from Astra sites.
282
+ - Fix: Bug where widgets created with SiteOrigin plugin were not being imported.
283
+
284
+ v1.0.0
285
+ - Initial release