PluginProbe
aBlocks – Gutenberg Blocks, User Dashboard Builder, Popup Builder, Form Builder & Animation Builder / 2.14.0
aBlocks – Gutenberg Blocks, User Dashboard Builder, Popup Builder, Form Builder & Animation Builder v2.14.0
2.14.0 2.13.0 2.13.1 2.12.0 2.11.1 2.11.0 2.10.0 2.9.0 2.7.4 2.7.5 2.7.6 2.7.7 2.8.0 2.8.1 2.9.1 trunk 1.0 1.0-beta1 1.0-beta2 1.0-beta3 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 All 81 releases
← All changes | includes/ajax/demo-import.php +444 -0 2.7.7 → 2.14.0 View file →
@@ -1,0 +1,444 @@
1 +<?php
2 +
3 +namespace ABlocks\Ajax;
4 +
5 +if ( ! defined( 'ABSPATH' ) ) {
6 + exit;
7 +}
8 +
9 +use ABlocks\Classes\AbstractAjaxHandler;
10 +use ABlocks\Classes\Sanitizer;
11 +use ABlocks\Helper;
12 +use ABlocks\import\CustomizerImporter;
13 +use ABlocks\import\ThemeOptions\CodeStar;
14 +use ABlocks\import\ThemeOptions\Redux;
15 +use ABlocks\import\WidgetImporter;
16 +use ABlocksThemeBuilder\Database;
17 +
18 +class DemoImport extends AbstractAjaxHandler {
19 +
20 + public function __construct() {
21 + $this->actions = array(
22 + 'get_demo_list' => array(
23 + 'callback' => array( $this, 'get_demo_list' ),
24 + 'capability' => 'ablocks_import_templates',
25 + 'fields' => array(
26 + 'type' => 'string',
27 + 'cost_type' => 'string',
28 + 'page' => 'integer',
29 + 'per_page' => 'integer',
30 + 'category' => 'string',
31 + 'dev' => 'string',
32 + 'q' => 'string',
33 + )
34 + ),
35 + 'get_single_demo' => array(
36 + 'callback' => array( $this, 'get_single_demo' ),
37 + 'capability' => 'ablocks_import_templates',
38 + 'fields' => array(
39 + 'id' => 'integer',
40 + 'with_images' => 'string',
41 + )
42 + ),
43 + 'get_demo_categories' => array(
44 + 'callback' => array( $this, 'get_demo_categories' ),
45 + 'capability' => 'ablocks_import_templates',
46 + 'fields' => array(
47 + 'type' => 'string',
48 + )
49 + ),
50 + 'get_theme_demos' => array(
51 + 'callback' => array( $this, 'get_theme_demos' ),
52 + 'capability' => 'ablocks_import_templates',
53 + ),
54 + 'check_dependencies' => array(
55 + 'callback' => array( $this, 'check_dependencies' ),
56 + 'capability' => 'ablocks_import_templates',
57 + 'fields' => array(
58 + 'dependencies' => 'array|string',
59 + )
60 + ),
61 + 'install_and_active' => array(
62 + 'callback' => array( $this, 'install_and_active' ),
63 + // A demo's dependencies are plugins. Importing templates is a
64 + // design permission; installing plugins is not, and must never
65 + // become reachable through one.
66 + 'capability' => 'install_plugins',
67 + 'fields' => array(
68 + 'dependency' => 'array|string',
69 + )
70 + ),
71 + 'import_template' => array(
72 + 'callback' => array( $this, 'import_template' ),
73 + 'capability' => 'ablocks_import_templates',
74 + 'fields' => array(
75 + 'file_url' => 'string',
76 + 'customizer_file_url' => 'string',
77 + 'widget_file_url' => 'string',
78 + 'codestar_file_url' => 'string',
79 + 'redux_options' => 'json',
80 + 'with_images' => 'boolean',
81 + )
82 + ),
83 + );
84 + }
85 +
86 + /**
87 + * Get demo list data from database, if not exists, then get & store data from API.
88 + *
89 + * @param array $data Query Data for API.
90 + *
91 + * @return void
92 + */
93 + public function get_demo_list( array $data ) {
94 + $args = [
95 + 'type' => $data['type'] ?? 'pattern',
96 + 'cost_type' => $data['cost_type'] ?? 'all',
97 + 'page' => $data['page'] ?? 1,
98 + ];
99 +
100 + if ( isset( $data['category'] ) ) {
101 + $args['category'] = $data['category'];
102 + }
103 +
104 + if ( isset( $data['dev'] ) ) {
105 + $args['dev'] = $data['dev'];
106 + }
107 +
108 + if ( isset( $data['q'] ) ) {
109 + $args['q'] = $data['q'];
110 + }
111 +
112 + if ( isset( $data['per_page'] ) ) {
113 + $args['per_page'] = $data['per_page'];
114 + }
115 +
116 + $hash = md5( wp_json_encode( $args ) );
117 + $key = "ablocks_demo_$hash";
118 + $has_response = get_transient( $key );
119 + if ( $has_response ) {
120 + wp_send_json_success( $has_response );
121 + }
122 +
123 + $url = 'https://' . ABLOCKS_TEMPLATE_LIB_HOST . '/wp-json/ablocks_server/v1/ablocks';
124 + $url = add_query_arg( $args, $url );
125 + $this->handle_list_response( $url, $key );
126 + }
127 +
128 + /**
129 + * Get single demo data from database, if not exists, then get & store data from API.
130 + *
131 + * @param array $data inside data `id` is required.
132 + *
133 + * @return void
134 + */
135 + public function get_single_demo( array $data ) {
136 + if ( ! $data['id'] ) {
137 + wp_send_json_error( __( 'id is required.', 'ablocks' ) );
138 + }
139 + $id = absint( $data['id'] );
140 + $with_images = isset( $data['with_images'] ) && true === (bool) $data['with_images'];
141 +
142 + $key = 'ablocks_demo_item_' . $id;
143 + $has_response = get_transient( $key );
144 + if ( $has_response ) {
145 + if ( $with_images && ! isset( $has_response['remote_images_parsed'] ) ) {
146 + $has_response['content'] = Helper::parse_remote_images( $has_response['content'] );
147 + $has_response['remote_images_parsed'] = true;
148 + set_transient( $key, $has_response, WEEK_IN_SECONDS );
149 + }
150 + unset( $has_response['remote_images_parsed'] );
151 + wp_send_json_success( $has_response );
152 + }
153 +
154 + $url = 'https://' . ABLOCKS_TEMPLATE_LIB_HOST . '/wp-json/ablocks_server/v1/ablocks/' . $id;
155 + $response = wp_safe_remote_get( $url );
156 + if ( is_wp_error( $response ) ) {
157 + wp_send_json_error( $response->get_error_message() );
158 + }
159 +
160 + $response_code = wp_remote_retrieve_response_code( $response );
161 + $response = wp_remote_retrieve_body( $response );
162 + $response = json_decode( $response, true );
163 + if ( $response_code !== 200 ) {
164 + wp_send_json_error( $response );
165 + }
166 +
167 + $response = $response['data'];
168 + if ( $with_images ) {
169 + $content = $response['content'] ?? null;
170 + if ( $content ) {
171 + $response['content'] = Helper::parse_remote_images( wp_unslash( $content ) );
172 + $response['remote_images_parsed'] = true;
173 + }
174 + }
175 + set_transient( $key, $response, WEEK_IN_SECONDS );
176 + unset( $response['remote_images_parsed'] );
177 + wp_send_json_success( $response );
178 + }
179 +
180 + /**
181 + * Get demo category list data from database, if not exists, then get & store data from API.
182 + *
183 + * @param array $data Query Data for Category list API.
184 + *
185 + * @return void
186 + */
187 + public function get_demo_categories( array $data ) {
188 + $type = $data['type'] ?? 'pattern';
189 + $key = "ablocks_demo_categories_$type";
190 + $has_response = get_transient( $key );
191 + if ( $has_response ) {
192 + wp_send_json_success( $has_response );
193 + }
194 +
195 + $url = 'https://' . ABLOCKS_TEMPLATE_LIB_HOST . '/wp-json/ablocks_server/v1/categories';
196 + $url = add_query_arg( 'type', $type, $url );
197 + $this->handle_list_response( $url, $key );
198 + }
199 +
200 + /**
201 + * Get theme demos.
202 + *
203 + * @return void
204 + */
205 + public function get_theme_demos() {
206 + $demo_config = Helper::get_theme_demo_config();
207 + if ( ! $demo_config ) {
208 + wp_send_json_error( [
209 + 'message' => 'Current theme demo isn\'t configured.',
210 + ] );
211 + }
212 +
213 + $demos = $demo_config['demos'];
214 + $categories = [];
215 + foreach ( $demos as &$demo ) {
216 + $demo_categories = [];
217 + foreach ( $demo['categories'] as $category ) {
218 + if ( is_array( $category ) ) {
219 + $categories[] = $category;
220 + $demo_categories[] = $category;
221 + } else {
222 + $demo_category = [
223 + 'label' => ucfirst( $category ),
224 + 'slug' => str_replace( ' ', '-', trim( $category ) ),
225 + ];
226 + $categories[] = $demo_category;
227 + $demo_categories[] = $demo_category;
228 + }
229 + }
230 + $demo['categories'] = $demo_categories;
231 + }
232 +
233 + $preloaded_categories = array_map( fn( $category ) => is_array( $category ) ? $category : [
234 + 'label' => ucfirst( $category ),
235 + 'slug' => str_replace( ' ', '-', trim( $category ) ),
236 + ], $demo_config['preloaded_demo_category'] );
237 +
238 + $categories_slugs = array_map( fn( $category ) => $category['slug'], $categories );
239 + foreach ( $preloaded_categories as $preloaded_category ) {
240 + if ( ! in_array( $preloaded_category['slug'], $categories_slugs, true ) ) {
241 + $categories[] = $preloaded_category;
242 + }
243 + }
244 +
245 + wp_send_json_success( array(
246 + 'categories' => $categories,
247 + 'preloaded_demo' => $demo_config['preloaded_demo'],
248 + 'preloaded_demo_categories' => $preloaded_categories,
249 + 'demos' => $demos,
250 + ) );
251 + }
252 +
253 + /**
254 + * Check dependencies before importing pattern/page/template.
255 + *
256 + * @param array $data Dependency Data.
257 + *
258 + * @return void
259 + */
260 + public function check_dependencies( array $data ) {
261 + if ( ! isset( $data['dependencies'] ) ) {
262 + return;
263 + }
264 +
265 + $dependencies = Sanitizer::sanitize_array_field( $data['dependencies'] );
266 + foreach ( $dependencies as $index => $dependency ) {
267 + $type = 'check_' . ( $dependency['type'] ?? 'plugin' );
268 + $status = Helper::$type( $dependency['slug'] );
269 + $dependencies[ $index ]['status'] = $status;
270 + if ( isset( $dependency['id'] ) ) {
271 + $dependencies[ $index ]['id'] = (int) $dependency['id'];
272 + }
273 + }
274 +
275 + wp_send_json_success( $dependencies );
276 + }
277 +
278 + /**
279 + * Install and active theme/plugin from ajax request.
280 + *
281 + * @param array $data post-data.
282 + *
283 + * @return void
284 + */
285 + public function install_and_active( array $data ) {
286 + if ( ! isset( $data['dependency'] ) ) {
287 + return;
288 + }
289 + $dependency = Sanitizer::sanitize_array_field( $data['dependency'] );
290 + $method = 'install_and_active_' . ( $dependency['type'] ?? 'plugin' );
291 + $activated = Helper::$method( $dependency['slug'] );
292 + if ( is_wp_error( $activated ) ) {
293 + wp_send_json_error( array(
294 + 'message' => $activated->get_error_message(),
295 + ) );
296 + }
297 +
298 + wp_send_json_success();
299 + }
300 +
301 + /**
302 + * Import template from file url.
303 + *
304 + * @param array $data Import data.
305 + *
306 + * @return void
307 + */
308 + public function import_template( array $data ) {
309 + if ( ! isset( $data['file_url'] ) ) {
310 + return;
311 + }
312 +
313 + $file_url = $data['file_url'];
314 + $content_file_path = Helper::remote_to_tmp_file( $file_url );
315 +
316 + $customizer_file_url = $data['customizer_file_url'] ?? '';
317 + $customizer_file_path = Helper::remote_to_tmp_file( $customizer_file_url );
318 + $widget_file_url = $data['widget_file_url'] ?? '';
319 + $widget_file_path = Helper::remote_to_tmp_file( $widget_file_url );
320 + $codestar_file_url = $data['codestar_file_url'] ?? '';
321 + $codestar_file_path = Helper::remote_to_tmp_file( $codestar_file_url );
322 + $with_images = isset( $data['with_images'] ) && true === $data['with_images'];
323 +
324 + // Start the event stream.
325 + header( 'Content-Type: text/event-stream, charset=UTF-8' );
326 + header( 'Cache-Control: no-store' );
327 + header( 'Connection: keep-alive' );
328 +
329 + // Turn off PHP output compression.
330 + // phpcs:disable WordPress.PHP.IniSet.Risky
331 + ini_set( 'output_buffering', 'off' );
332 + ini_set( 'zlib.output_compression', false );
333 + // phpcs:enable WordPress.PHP.IniSet.Risky
334 +
335 + if ( $GLOBALS['is_nginx'] ) {
336 + // Setting this header instructs Nginx to disable fast-cgi buffering
337 + // and disable gzip for this request.
338 + header( 'X-Accel-Buffering: no' );
339 + header( 'Content-Encoding: none' );
340 + }
341 +
342 + echo esc_html( ':' . str_repeat( ' ', 2048 ) . "\n\n" ); // 2KB padding for IE.
343 +
344 + set_time_limit( 0 );
345 +
346 + // Ensure we're not buffered.
347 + wp_ob_end_flush_all();
348 + flush();
349 +
350 + if ( is_wp_error( $content_file_path ) ) {
351 + Helper::emit_sse_message( [
352 + 'action' => 'complete',
353 + 'error' => is_string( $codestar_file_path->get_error_message() ) && ! empty( $codestar_file_path->get_error_message() ) ? $codestar_file_path->get_error_code() : __( 'Invalid content path.', 'ablocks' ),
354 + ] );
355 + exit;
356 + }
357 +
358 + do_action( 'ablocks/import/before_template_import_start', $data );
359 +
360 + if ( ! Helper::get_addon_active_status( 'theme-builder' ) && ! Helper::is_fse_theme() ) {
361 + $saved_addons = json_decode( get_option( ABLOCKS_ADDONS_SETTINGS_NAME, '{}' ), true );
362 + if ( ! is_array( $saved_addons ) ) {
363 + $saved_addons = [];
364 + }
365 +
366 + $addon_slug = 'theme-builder';
367 + $saved_addons[ $addon_slug ] = true;
368 + do_action( "ablocks/addons/activated_$addon_slug" );
369 +
370 + update_option( ABLOCKS_ADDONS_SETTINGS_NAME, wp_json_encode( $saved_addons ) );
371 + ( new Database() )->create_ablocks_tb_post_type();
372 + ( new Database() )->register_ablocks_tb_meta();
373 + }
374 +
375 + $template_import = Helper::import_template( $content_file_path, $with_images );
376 + if ( ! is_wp_error( $template_import ) ) {
377 + if ( ! empty( $customizer_file_path ) && ! is_wp_error( $customizer_file_path ) ) {
378 + CustomizerImporter::import( $customizer_file_path );
379 + }
380 + if ( ! empty( $widget_file_path ) && ! is_wp_error( $widget_file_path ) ) {
381 + WidgetImporter::import( $widget_file_path );
382 + }
383 + if ( ! empty( $codestar_file_path ) ) {
384 + CodeStar::import( $codestar_file_path );
385 + }
386 + if ( isset( $data['redux_options'] ) && is_array( $data['redux_options'] ) && count( $data['redux_options'] ) > 0 ) {
387 + Redux::import( $data['redux_options'] );
388 + }
389 + }
390 + do_action( 'ablocks/import/template_import_finished', $data );
391 +
392 + // Let the browser know we're done.
393 + $complete = [
394 + 'action' => 'complete',
395 + 'error' => false,
396 + ];
397 + if ( is_wp_error( $template_import ) ) {
398 + $complete['error'] = $template_import->get_error_message();
399 + }
400 + Helper::emit_sse_message( $complete );
401 + exit;
402 + }
403 +
404 + /**
405 + * Handle common list response.
406 + *
407 + * @param string $url URL.
408 + * @param string $key Transient key.
409 + *
410 + * @return void
411 + */
412 + private function handle_list_response( string $url, string $key ): void {
413 + global $wp_version;
414 + $response = wp_safe_remote_get( $url, array(
415 + 'headers' => array(
416 + 'Accept' => 'application/json',
417 + 'user-agent' => sprintf(
418 + 'aBlocks/%1$s (%2$s; WordPress/%3$s) %4$s',
419 + ABLOCKS_VERSION,
420 + get_option( 'blogname' ),
421 + $wp_version,
422 + home_url()
423 + ),
424 + ),
425 + ) );
426 + if ( is_wp_error( $response ) ) {
427 + wp_send_json_error( [
428 + 'message' => $response->get_error_message()
429 + ] );
430 + }
431 +
432 + $response_code = wp_remote_retrieve_response_code( $response );
433 + $response = wp_remote_retrieve_body( $response );
434 + $response = json_decode( $response, true );
435 + if ( $response_code !== 200 || isset( $response['message'] ) ) {
436 + wp_send_json_error( [
437 + 'message' => $response['message']
438 + ] );
439 + }
440 +
441 + set_transient( $key, $response, WEEK_IN_SECONDS );
442 + wp_send_json_success( $response );
443 + }
444 +}