PluginProbe ʕ •ᴥ•ʔ
Kubio AI Page Builder / 2.8.2
Kubio AI Page Builder v2.8.2
2.8.4 2.8.3 2.8.2 2.8.1 trunk 1.0.0 1.0.1 1.1.0 1.2.0 1.2.1 1.2.2 1.2.3 1.3.0 1.3.1 1.3.2 1.4.0 1.4.1 1.4.2 1.4.3 1.5.0 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.7.0 1.7.1 1.7.2 1.7.3 1.8.0 1.8.1 1.8.2 1.9.0 2.0.0 2.1.1 2.1.2 2.1.3 2.2.0 2.2.3 2.2.4 2.2.5 2.3.0 2.3.1 2.3.3 2.3.4 2.4.0 2.4.1 2.4.2 2.4.3 2.4.5 2.5.0 2.5.1 2.5.2 2.5.3 2.6.0 2.6.1 2.6.2 2.6.3 2.6.5 2.6.6 2.6.7 2.7.0 2.7.1 2.7.2 2.7.3 2.8.0
kubio / lib / src / DemoSites / DemoSitesImporter.php
kubio / lib / src / DemoSites Last commit date
DemoSites.php 1 year ago DemoSitesHelpers.php 1 month ago DemoSitesImportBlockMap.php 1 year ago DemoSitesImporter.php 1 year ago DemoSitesLogger.php 4 years ago DemoSitesRepository.php 1 year ago WXRExporter.php 1 year ago WXRImporter.php 1 year ago
DemoSitesImporter.php
584 lines
1 <?php
2
3 namespace Kubio\DemoSites;
4
5 use IlluminateAgnostic\Arr\Support\Arr;
6 use Kubio\Core\Importer;
7 use Kubio\Flags;
8
9 class DemoSitesImporter {
10 private $logger = null;
11 private $slug = 0;
12 private $log_file_path;
13
14 private $importer;
15 private $wxr_file;
16 private $before_import_executed = false;
17 private $options;
18 private $config;
19
20 public function __construct( $type = 'ajax', $config = array() ) {
21 if ( $type === 'ajax' ) {
22 // pick up only a few keys from the request.
23 $this->config = wp_parse_args(
24 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
25 $_REQUEST,
26 array(
27 'is_stepped' => true,
28 'first_call' => false,
29 'before_import_action' => '',
30 'fetch_attachments' => false,
31 )
32 );
33 } else {
34 $this->config = wp_parse_args(
35 $config,
36 array(
37 'is_stepped' => false,
38 'fetch_attachments' => false,
39 )
40 );
41
42 // on cli we only set these once.
43 $this->setLogger();
44 $this->setImporter( $this->config );
45 $this->maybeCleanupData();
46
47 DemoSitesHelpers::setImportStartTime();
48
49 $this->log_file_path = DemoSitesHelpers::getLogFile();
50 $this->logger->logger_file = $this->log_file_path;
51 }
52
53 $this->slug = Arr::get( $this->config, 'slug', 0 );
54 add_action( 'wp_ajax_kubio-demo-site-import-data', array( $this, 'ajaxImportDemoData' ) );
55 }
56
57 public static function load() {
58 new static();
59 }
60
61 /**
62 * This is the ajax callback added to `wp_ajax_kubio-demo-site-import-data` and it will import a demo-data by a
63 * given slug, and it will kill the execution with a json message on success ore failure.
64 *
65 */
66 public function ajaxImportDemoData() {
67 $this->setLogger();
68 $this->setImporter( $this->config );
69 $this->maybeCleanupData();
70
71 DemoSitesHelpers::verifyAjaxCall();
72
73 // Is this a new AJAX call to continue the previous import?
74 $use_existing_importer_data = $this->useExistingImporterData();
75
76 if ( ! $use_existing_importer_data ) {
77 DemoSitesHelpers::setImportStartTime();
78
79 $this->log_file_path = DemoSitesHelpers::getLogFile();
80 }
81
82 $this->logger->logger_file = $this->log_file_path;
83
84 $this->setIniMemoryLimit();
85
86 if ( ! $use_existing_importer_data ) {
87 // phpcs:ignore WordPress.Security.NonceVerification.Missing
88 $kds_file = Arr::get( $_FILES, 'kds_file', null );
89 if ( ! $kds_file ) {
90 $this->prepareRemoteImport();
91 } else {
92 $this->prepareManualImport( $kds_file );
93 }
94 }
95
96 DemoSitesHelpers::setImportDataTransient( $this->getCurrentImportData() );
97
98 if ( ! $this->before_import_executed ) {
99
100 $before_import_action = Arr::get( $this->config, 'before_import_action', null );
101
102 if ( ! $before_import_action ) {
103 $response = array(
104 'status' => 'requires-new-ajax-call',
105 'before_import_action' => 'init',
106 );
107 wp_send_json( $response );
108 } else {
109 $this->executeBeforeImportAction( $before_import_action );
110 }
111
112 $this->before_import_executed = true;
113 DemoSitesHelpers::setImportDataTransient( $this->getCurrentImportData() );
114 $response = array(
115 'status' => 'requires-new-ajax-call',
116 'log' => 'Before import executed',
117 );
118 wp_send_json( $response );
119
120 }
121
122 if ( $this->wxr_file && file_exists( $this->wxr_file ) ) {
123 add_action( 'kubio/demo-site-import/post-process', array( $this, 'postProcessContentImport' ) );
124 $this->importer->import_content( $this->wxr_file );
125 }
126
127 $this->afterImport();
128 }
129
130 /**
131 * This method is used to import a demo-data design via WP CLI for a given slug.
132 * eg: `wp kubio:import-design accounting-demo-site`
133 *
134 * @return false|string
135 */
136 public function cliImportDemoData( $args ) {
137 $this->setIniMemoryLimit();
138
139 if ( isset( $args['is_custom'] ) && $args['is_custom'] ) {
140 $this->loadKDSFile( $args['kds_url'] );
141 } else {
142 $this->prepareRemoteImport();
143 }
144
145 DemoSitesHelpers::setImportDataTransient( $this->getCurrentImportData() );
146
147 if ( $this->wxr_file && file_exists( $this->wxr_file ) ) {
148 add_action( 'kubio/demo-site-import/post-process', array( $this, 'postProcessContentImport' ) );
149 $this->importer->import_content( $this->wxr_file );
150 }
151
152 return $this->afterImport( false );
153 }
154
155 /**
156 * A methods which sets `$this->logger` as an instance of `DemoSitesLogger`
157 */
158 private function setLogger() {
159 $this->logger = new DemoSitesLogger();
160 $this->logger->min_level = 'info';
161 $this->logger->logger_file = '';
162 }
163
164 /**
165 * A methods which sets `$this->importer` as an instance of `WXRImporter`
166 */
167 private function setImporter( $config ) {
168 if ( ! class_exists( '\WP_Importer' ) ) {
169 require ABSPATH . '/wp-admin/includes/class-wp-importer.php';
170 }
171
172 $this->importer = new WXRImporter(
173 array(
174 'fetch_attachments' => Arr::get( $config, 'fetch_attachments', true ),
175 'is_stepped' => Arr::get( $config, 'is_stepped', true ),
176 ),
177 $this->logger
178 );
179 }
180
181 /**
182 * In the first call try to delete old transients.
183 */
184 private function maybeCleanupData() {
185 if ( Arr::get( $this->config, 'first_call', null ) ) {
186 delete_transient( DemoSitesHelpers::IMPORT_TRANSIENT );
187 $this->importer->delete_import_data_transient();
188 }
189 }
190
191 /**
192 * Try to set a ini value of 512M for `memory_limit`.
193 * If it is not allowed warn in the logs about it.
194 */
195 private function setIniMemoryLimit() {
196 // phpcs:ignore Squiz.PHP.DiscouragedFunctions.Discouraged
197 if ( ! @ini_set( 'memory_limit', '512M' ) ) {
198 DemoSitesHelpers::appendToFile(
199 esc_html__( 'Warn: Unable set memory_limit', 'kubio' ),
200 $this->log_file_path
201 );
202 }
203 }
204
205 private function useExistingImporterData() {
206 if ( $data = get_transient( DemoSitesHelpers::IMPORT_TRANSIENT ) ) {
207 $this->log_file_path = empty( $data['log_file_path'] ) ? '' : $data['log_file_path'];
208 $this->slug = empty( $data['slug'] ) ? null : $data['slug'];
209 $this->wxr_file = empty( $data['wxr_file'] ) ? array() : $data['wxr_file'];
210 $this->options = empty( $data['options'] ) ? array() : $data['options'];
211 $this->before_import_executed = empty( $data['before_import_executed'] ) ? array() : $data['before_import_executed'];
212
213 return true;
214 }
215
216 return false;
217 }
218
219 private function prepareRemoteImport() {
220 $this->logger->info( 'Prepare remote import' );
221
222 $demo = $this->getDemo();
223 if ( $demo !== null ) {
224 $kds = Arr::get( $demo, 'kds_url', null );
225 $this->loadKDSFile( $kds );
226 } else {
227 // Send JSON Error response to the AJAX call.
228 DemoSitesHelpers::sendAjaxError( esc_html__( 'No import files specified!', 'kubio' ) );
229 }
230 }
231
232
233 private function loadKDSFile( $kds ) {
234 if ( $kds ) {
235 $result = DemoSitesHelpers::extractImporterFilesFromSource( $kds );
236
237 if ( is_wp_error( $result ) ) {
238 DemoSitesHelpers::sendAjaxError( $result->get_error_message() );
239 }
240
241 list( $wxr_file, $extra_options ) = $result;
242
243 if ( is_wp_error( $wxr_file ) ) {
244 DemoSitesHelpers::logErrorAndSendAjaxResponse(
245 $wxr_file->get_error_message(),
246 $this->log_file_path,
247 esc_html__( 'Downloaded files', 'kubio' )
248 );
249 } else {
250 $this->wxr_file = $wxr_file;
251 $this->options = $extra_options;
252 }
253 } else {
254 DemoSitesHelpers::logErrorAndSendAjaxResponse(
255 esc_html__( 'Import file undefined', 'kubio' ),
256 $this->log_file_path,
257 esc_html__( 'Downloaded files', 'kubio' )
258 );
259 }
260
261 DemoSitesHelpers::appendToFile(
262 sprintf( /* translators: %s - the name of the selected import. */
263 __( 'The import files for: %s were successfully downloaded!', 'kubio' ),
264 $kds
265 ),
266 $this->log_file_path,
267 esc_html__( 'Downloaded files', 'kubio' )
268 );
269 }
270
271 private function getDemo() {
272 $demos = apply_filters( 'kubio/demo-sites/list', array() );
273 $slug = $this->slug;
274
275 return Arr::get( $demos, $slug, null );
276 }
277
278 private function prepareManualImport( $kds_file ) {
279
280 DemoSitesHelpers::appendToFile(
281 __( 'Manual kds import!', 'kubio' ),
282 $this->log_file_path,
283 esc_html__( 'Manual import', 'kubio' )
284 );
285
286 list( $wxr_file, $extra_options ) = DemoSitesHelpers::useUploadedKDSFile( Arr::get( $kds_file, 'tmp_name', null ) );
287 $this->wxr_file = $wxr_file;
288 $this->options = $extra_options;
289 }
290
291 /**
292 * Get the current state of selected data.
293 *
294 * @return array
295 */
296 public function getCurrentImportData() {
297 return array(
298 'log_file_path' => $this->log_file_path,
299 'slug' => $this->slug,
300 'wxr_file' => $this->wxr_file,
301 'options' => $this->options,
302 'before_import_executed' => $this->before_import_executed,
303 );
304 }
305
306 public function getBeforeImportActions() {
307 return array( 'init', 'prepare_templates', 'prepare_template_parts', 'prepare_menus', 'prepare_pages' );
308 }
309
310 /**
311 * This method executes the valid given $action, logs in case of error, and returns the status of ajax/cli queue.
312 * Based on the $ajax parameter it will kill the execution with an `wp_send_json` response or it will print the json.
313 *
314 * @param $action
315 * @param bool $ajax
316 * @return false|string|void
317 */
318 public function executeBeforeImportAction( $action, $ajax = true ) {
319 $actions = $this->getBeforeImportActions();
320 $action_index = array_search( $action, $actions );
321
322 if ( $action_index === false ) {
323 DemoSitesHelpers::sendAjaxError( __( 'Importer action not found', 'kubio' ) );
324 }
325
326 $this->logger->info( "Executing before import step: {$action}" );
327
328 switch ( $action ) {
329
330 case 'init':
331 $site_url = Arr::get( $this->options, 'site_url' );
332 if ( $site_url ) {
333 wp_remote_get( $site_url );
334 }
335 break;
336
337 case 'prepare_templates':
338 $this->prepareTemplates();
339 break;
340
341 case 'prepare_template_parts':
342 $this->prepareTemplateParts();
343 break;
344
345 case 'prepare_pages':
346 $this->preparePages();
347 break;
348
349 case 'prepare_menus':
350 $this->prepareMenus();
351 break;
352 }
353
354 if ( $action_index + 1 < count( $actions ) ) {
355 $response = array(
356 'status' => 'requires-new-ajax-call',
357 'before_import_action' => $actions[ $action_index + 1 ],
358 );
359
360 if ( $ajax ) {
361 wp_send_json( $response );
362 }
363
364 return wp_json_encode( $response );
365 }
366 }
367
368 private function prepareTemplates() {
369 $stylesheet = get_stylesheet();
370 $ids = get_posts(
371 array(
372 'post_type' => 'wp_template',
373 'post_status' => array( 'publish' ),
374 'posts_per_page' => - 1,
375 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
376 'tax_query' => array(
377 array(
378 'taxonomy' => 'wp_theme',
379 'field' => 'name',
380 'terms' => array( $stylesheet ),
381 ),
382 ),
383 'fields' => 'ids',
384 )
385 );
386
387 foreach ( $ids as $id ) {
388 wp_delete_post( $id, true );
389 }
390 }
391
392 private function prepareTemplateParts() {
393 $stylesheet = get_stylesheet();
394 $ids = get_posts(
395 array(
396 'post_type' => 'wp_template_part',
397 'post_status' => array( 'publish' ),
398 'posts_per_page' => - 1,
399 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
400 'tax_query' => array(
401 array(
402 'taxonomy' => 'wp_theme',
403 'field' => 'name',
404 'terms' => array( $stylesheet ),
405 ),
406 ),
407 'fields' => 'ids',
408 )
409 );
410
411 foreach ( $ids as $id ) {
412 wp_delete_post( $id, true );
413 }
414 }
415
416 private function preparePages() {
417 $ids = get_posts(
418 array(
419 'post_type' => 'page',
420 'post_status' => array( 'publish', 'draft' ),
421 'posts_per_page' => - 1,
422 'fields' => 'ids',
423 )
424 );
425
426 foreach ( $ids as $id ) {
427 wp_delete_post( $id, false );
428 }
429 }
430
431 private function prepareMenus() {
432 $menus = wp_get_nav_menus();
433
434 /** @var \WP_Term $menu */
435 foreach ( $menus as $menu ) {
436 $index = - 1;
437 do {
438 ++$index;
439 list($base_name) = sscanf( $menu->name, '%s - %s' );
440
441 $new_name = sprintf(
442 '%s - %s',
443 $base_name,
444 // translators: %s - menu item name e.g. "Home", "Contact"
445 $index ? sprintf( __( 'Old %s', 'kubio' ), $index ) : __( 'Old', 'kubio' )
446 );
447
448 } while ( ! ! get_term_by( 'name', $new_name, 'nav_menu' ) );
449
450 wp_update_nav_menu_object(
451 $menu->term_id,
452 array(
453 'menu-name' => $new_name,
454 )
455 );
456 }
457 }
458
459 /**
460 * Send a JSON response with final report or simply returns the json if $ajax is false.
461 *
462 * @param bool $ajax
463 * @return false|string
464 */
465 private function afterImport( $ajax = true ) {
466
467 $this->useExistingImporterData();
468
469 if ( $this->slug ) {
470 Flags::set( 'last_imported_starter', $this->slug );
471 }
472
473 // Delete importer data transient for current import.
474 delete_transient( DemoSitesHelpers::IMPORT_TRANSIENT );
475
476 $response = array(
477 'status' => 'finished',
478 );
479
480 if ( $ajax ) {
481 wp_send_json( $response );
482 }
483
484 return wp_json_encode( $response );
485 }
486
487 //this updates the count column in the wp_term_taxonomy table because in some cases it was still at 0 showing empty menus
488 public function updateMenuItemsCount( $wxr_importer ) {
489 $update_taxonomy = 'nav_menu';
490 $menus_id_map = Arr::get( $wxr_importer->get_mapping(), 'menus_map', array() );
491 wp_update_term_count_now( $menus_id_map, $update_taxonomy );
492 }
493 /**
494 * @param WXRImporter $wxr_importer
495 */
496 public function postProcessContentImport( $wxr_importer ) {
497 $this->updateThemeMods( $wxr_importer );
498 $this->updateLogos( $wxr_importer );
499 $this->updateFrontPages( $wxr_importer );
500 $this->updateGlobalNonKubioTemplates();
501 $this->updateMenuItemsCount( $wxr_importer );
502 }
503
504
505 private function updateGlobalNonKubioTemplates() {
506 wp_cache_flush();
507 $blog_templates = array(
508 'singular' => 'single',
509 'home' => 'index',
510 );
511
512 foreach ( $blog_templates as $template => $replacement ) {
513 if ( kubio_has_block_template( $template ) ) {
514 $replacement_template = kubio_get_block_template( $replacement );
515 if ( $replacement_template ) {
516 Importer::createTemplate( $template, $replacement_template->content, true, 'kubio' );
517 }
518 }
519 }
520 }
521
522 /**
523 * @param WXRImporter $wxr_importer
524 */
525 private function updateThemeMods( $wxr_importer ) {
526
527 $theme_mods = Arr::get( $this->options, 'customizer', array() );
528
529 unset( $theme_mods[0] );
530
531 // update nav menu locations
532 $menus_id_map = Arr::get( $wxr_importer->get_mapping(), 'menus_map', array() );
533 $nav_menu_locations = Arr::get( $theme_mods, 'nav_menu_locations', array() );
534 foreach ( $nav_menu_locations as $location => $term_id ) {
535 $next_term_id = Arr::get( $menus_id_map, $term_id, null );
536
537 if ( $next_term_id ) {
538 $nav_menu_locations[ $location ] = (int) $next_term_id;
539 } else {
540 unset( $nav_menu_locations[ $location ] );
541 }
542 }
543 $theme_mods['nav_menu_locations'] = $nav_menu_locations;
544
545 $theme = get_option( 'stylesheet' );
546
547 update_option( "theme_mods_$theme", $theme_mods );
548 }
549
550 /**
551 * @param WXRImporter $wxr_importer
552 */
553 private function updateLogos( $wxr_importer ) {
554 $alternate_logo_image = kubio_get_global_data( 'alternateLogo' );
555 $post_mapping = Arr::get( $wxr_importer->get_mapping(), 'post', array() );
556 if ( $alternate_logo_image ) {
557 kubio_set_global_data( 'alternateLogo', Arr::get( $post_mapping, $alternate_logo_image, $alternate_logo_image ) );
558 }
559
560 $logos_options = array( 'site_logo', 'site_icon' );
561
562 foreach ( $logos_options as $option ) {
563 $value = Arr::get( $this->options, "options.{$option}", 0 );
564 $value = Arr::get( $post_mapping, $value, $value );
565 update_option( $option, is_numeric( $value ) ? intval( $value ) : $value );
566 }
567 }
568
569 /**
570 * @param WXRImporter $wxr_importer
571 */
572 private function updateFrontPages( $wxr_importer ) {
573 $page_options = array( 'page_on_front', 'page_for_posts', 'show_on_front' );
574
575 $post_mapping = Arr::get( $wxr_importer->get_mapping(), 'post', array() );
576
577 foreach ( $page_options as $option ) {
578 $value = Arr::get( $this->options, "options.{$option}", 0 );
579 $value = Arr::get( $post_mapping, $value, $value );
580 update_option( $option, is_numeric( $value ) ? intval( $value ) : $value );
581 }
582 }
583 }
584