PluginProbe
Elementor Website Builder – more than just a page builder / 4.2.2
Elementor Website Builder – more than just a page builder v4.2.2
4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 4.1.0-beta1 4.1.0-dev1 4.0.7 All 451 releases
elementor / modules / ai / connect / ai.php

ai.php in Elementor Website Builder – more than just a page builder 4.2.2, at modules/ai/connect/ai.php

907 lines 22.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Elementor\Modules\Ai\Connect;
3
4 use Elementor\Core\Common\Modules\Connect\Apps\Library;
5 use Elementor\Modules\Ai\Module;
6 use Elementor\Utils as ElementorUtils;
7 use Elementor\Plugin;
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit; // Exit if accessed directly.
11 }
12
13 class Ai extends Library {
14 const API_URL = 'https://my.elementor.com/api/v2/ai/';
15
16 const STYLE_PRESET = 'style_preset';
17 const IMAGE_TYPE = 'image_type';
18 const IMAGE_STRENGTH = 'image_strength';
19 const ASPECT_RATIO = 'ratio';
20 const IMAGE_RESOLUTION = 'image_resolution';
21
22 const IMAGE_BACKGROUND_COLOR = 'background_color';
23
24 const PROMPT = 'prompt';
25
26 public function get_title() {
27 return esc_html__( 'AI', 'elementor' );
28 }
29
30 protected function get_api_url() {
31 return static::API_URL . '/';
32 }
33
34 public function get_usage() {
35 return $this->ai_request(
36 'POST',
37 'status/check',
38 [
39 'api_version' => ELEMENTOR_VERSION,
40 'site_lang' => get_bloginfo( 'language' ),
41 ]
42 );
43 }
44
45 public function get_remote_config() {
46 return $this->ai_request(
47 'GET',
48 'remote-config/config',
49 [
50 'api_version' => ELEMENTOR_VERSION,
51 'site_lang' => get_bloginfo( 'language' ),
52 ]
53 );
54 }
55
56 public function get_remote_frontend_config( $data ) {
57 return $this->ai_request(
58 'POST',
59 'remote-config/frontend-config',
60 [
61 'client_name' => $data['payload']['client_name'],
62 'client_version' => $data['payload']['client_version'],
63 'client_session_id' => $data['payload']['client_session_id'],
64
65 'api_version' => ELEMENTOR_VERSION,
66 'site_lang' => get_bloginfo( 'language' ),
67 ],
68 false,
69 '',
70 'json'
71 );
72 }
73
74 /**
75 * @param array $event_data {
76 * @type string $name
77 * @type array $data
78 * @type array $client {
79 * @type string $name
80 * @type string $version
81 * @type string $session_id
82 * }
83 * }
84 */
85 public function send_event( array $event_data ): void {
86 $this->ai_request(
87 'POST',
88 'client-events/events',
89 [
90 'payload' => $event_data,
91 'api_version' => ELEMENTOR_VERSION,
92 'site_lang' => get_bloginfo( 'language' ),
93 ],
94 false,
95 '',
96 'json'
97 );
98 }
99
100 /**
101 * Get file upload get_file_payload
102 *
103 * @param $filename
104 * @param $file_type
105 * @param $file_path
106 * @param $boundary
107 *
108 * @return string
109 */
110 private function get_file_payload( $filename, $file_type, $file_path, $boundary ) {
111 $name = $filename ?? basename( $file_path );
112 $mine_type = 'image' === $file_type ? image_type_to_mime_type( exif_imagetype( $file_path ) ) : $file_type;
113 $payload = '';
114 // Upload the file
115 $payload .= '--' . $boundary;
116 $payload .= "\r\n";
117 $payload .= 'Content-Disposition: form-data; name="' . esc_attr( $name ) . '"; filename="' . esc_attr( $name ) . '"' . "\r\n";
118 $payload .= 'Content-Type: ' . $mine_type . "\r\n";
119 $payload .= "\r\n";
120 $payload .= file_get_contents( $file_path );
121 $payload .= "\r\n";
122
123 return $payload;
124 }
125
126 private function get_upload_request_body( $body, $file, $boundary, $file_name = '' ) {
127 $payload = '';
128 // add all body fields as standard POST fields:
129 foreach ( $body as $name => $value ) {
130 $payload .= '--' . $boundary;
131 $payload .= "\r\n";
132 $payload .= 'Content-Disposition: form-data; name="' . esc_attr( $name ) . '"' . "\r\n\r\n";
133 $payload .= $value;
134 $payload .= "\r\n";
135 }
136
137 if ( is_array( $file ) ) {
138 foreach ( $file as $key => $file_data ) {
139 $payload .= $this->get_file_payload( $file_data['name'], $file_data['type'], $file_data['path'], $boundary );
140 }
141 } else {
142 $image_mime = image_type_to_mime_type( exif_imagetype( $file ) );
143 // @todo: add validation for supported image types
144
145 if ( empty( $file_name ) ) {
146 $file_name = basename( $file );
147 }
148 $payload .= $this->get_file_payload( $file_name, $image_mime, $file, $boundary );
149 }
150
151 $payload .= '--' . $boundary . '--';
152
153 return $payload;
154 }
155
156 private function ai_request( $method, $endpoint, $body, $file = false, $file_name = '', $format = 'default' ) {
157 $headers = [
158 'x-elementor-ai-version' => '2',
159 ];
160
161 if ( $file ) {
162 $boundary = wp_generate_password( 24, false );
163 $body = $this->get_upload_request_body( $body, $file, $boundary, $file_name );
164 // add content type header
165 $headers['Content-Type'] = 'multipart/form-data; boundary=' . $boundary;
166 } elseif ( 'json' === $format ) {
167 $headers['Content-Type'] = 'application/json';
168 $body = wp_json_encode( $body );
169 }
170
171 return $this->http_request(
172 $method,
173 $endpoint,
174 [
175 'timeout' => 100,
176 'headers' => $headers,
177 'body' => $body,
178
179 ],
180 [
181 'return_type' => static::HTTP_RETURN_TYPE_ARRAY,
182 'with_error_data' => true,
183 ]
184 );
185 }
186
187 public function set_get_started() {
188 return $this->ai_request(
189 'POST',
190 'status/get-started',
191 [
192 'api_version' => ELEMENTOR_VERSION,
193 'site_lang' => get_bloginfo( 'language' ),
194 ]
195 );
196 }
197
198 public function set_status_feedback( $response_id ) {
199 return $this->ai_request(
200 'POST',
201 'status/feedback/' . $response_id,
202 [
203 'api_version' => ELEMENTOR_VERSION,
204 'site_lang' => get_bloginfo( 'language' ),
205 ]
206 );
207 }
208
209 public function set_used_gallery_image( $image_id ) {
210 return $this->ai_request(
211 'POST',
212 'status/used-gallery-image/' . $image_id,
213 [
214 'api_version' => ELEMENTOR_VERSION,
215 'site_lang' => get_bloginfo( 'language' ),
216 ]
217 );
218 }
219
220 public function get_completion_text( $prompt, $context, $request_ids ) {
221 return $this->ai_request(
222 'POST',
223 'text/completion',
224 [
225 'prompt' => $prompt,
226 'context' => wp_json_encode( $context ),
227 'ids' => $request_ids,
228 'api_version' => ELEMENTOR_VERSION,
229 'site_lang' => get_bloginfo( 'language' ),
230 ],
231 false,
232 '',
233 'json'
234 );
235 }
236
237 public function get_excerpt( $prompt, $context, $request_ids ) {
238 $excerpt_length = apply_filters( 'excerpt_length', 55 );
239 return $this->ai_request(
240 'POST',
241 'text/get-excerpt',
242 [
243 'content' => $prompt,
244 'maxLength' => $excerpt_length,
245 'context' => wp_json_encode( $context ),
246 'ids' => $request_ids,
247 'api_version' => ELEMENTOR_VERSION,
248 'site_lang' => get_bloginfo( 'language' ),
249 ],
250 false,
251 '',
252 'json'
253 );
254 }
255
256 /**
257 * Get Image Prompt Enhanced get_image_prompt_enhanced
258 *
259 * @param $prompt
260 *
261 * @return mixed|\WP_Error
262 */
263 public function get_image_prompt_enhanced( $prompt, $context, $request_ids ) {
264 return $this->ai_request(
265 'POST',
266 'text/enhance-image-prompt',
267 [
268 'prompt' => $prompt,
269 'context' => wp_json_encode( $context ),
270 'ids' => $request_ids,
271 'api_version' => ELEMENTOR_VERSION,
272 'site_lang' => get_bloginfo( 'language' ),
273 ]
274 );
275 }
276
277 public function get_edit_text( $data, $context, $request_ids ) {
278 return $this->ai_request(
279 'POST',
280 'text/edit',
281 [
282 'input' => $data['payload']['input'],
283 'instruction' => $data['payload']['instruction'],
284 'context' => wp_json_encode( $context ),
285 'ids' => $request_ids,
286 'api_version' => ELEMENTOR_VERSION,
287 'site_lang' => get_bloginfo( 'language' ),
288 ],
289 false,
290 '',
291 'json'
292 );
293 }
294
295 public function get_custom_code( $data, $context, $request_ids ) {
296 return $this->ai_request(
297 'POST',
298 'text/custom-code',
299 [
300 'prompt' => $data['payload']['prompt'],
301 'language' => $data['payload']['language'],
302 'context' => wp_json_encode( $context ),
303 'ids' => $request_ids,
304 'api_version' => ELEMENTOR_VERSION,
305 'site_lang' => get_bloginfo( 'language' ),
306 ],
307 false,
308 '',
309 'json'
310 );
311 }
312
313 public function get_custom_css( $data, $context, $request_ids ) {
314 return $this->ai_request(
315 'POST',
316 'text/custom-css',
317 [
318 'prompt' => $data['payload']['prompt'],
319 'html_markup' => $data['payload']['html_markup'],
320 'element_id' => $data['payload']['element_id'],
321 'context' => wp_json_encode( $context ),
322 'ids' => $request_ids,
323 'api_version' => ELEMENTOR_VERSION,
324 'site_lang' => get_bloginfo( 'language' ),
325 ],
326 false,
327 '',
328 'json'
329 );
330 }
331
332 /**
333 * Get text to image get_text_to_image
334 *
335 * @param $prompt
336 * @param $prompt_settings
337 *
338 * @return mixed|\WP_Error
339 */
340 public function get_text_to_image( $data, $context, $request_ids ) {
341 return $this->ai_request(
342 'POST',
343 'image/text-to-image',
344 [
345 self::PROMPT => $data['payload']['prompt'],
346 self::IMAGE_TYPE => $data['payload']['settings'][ self::IMAGE_TYPE ] . '/' . $data['payload']['settings'][ self::STYLE_PRESET ],
347 self::ASPECT_RATIO => $data['payload']['settings'][ self::ASPECT_RATIO ],
348 'context' => wp_json_encode( $context ),
349 'ids' => $request_ids,
350 'api_version' => ELEMENTOR_VERSION,
351 'site_lang' => get_bloginfo( 'language' ),
352 ],
353 false,
354 '',
355 'json'
356 );
357 }
358
359 /**
360 * Get_Featured_Image get_featured_image
361 *
362 * @param $data
363 * @param $context
364 * @param $request_ids
365 * @return mixed|\WP_Error
366 */
367 public function get_featured_image( $data, $context, $request_ids ) {
368 return $this->ai_request(
369 'POST',
370 'image/text-to-image/featured-image',
371 [
372 self::PROMPT => $data['payload']['prompt'],
373 self::IMAGE_TYPE => $data['payload']['settings'][ self::IMAGE_TYPE ] . '/' . $data['payload']['settings'][ self::STYLE_PRESET ],
374 self::ASPECT_RATIO => $data['payload']['settings'][ self::ASPECT_RATIO ],
375 'context' => wp_json_encode( $context ),
376 'ids' => $request_ids,
377 'api_version' => ELEMENTOR_VERSION,
378 'site_lang' => get_bloginfo( 'language' ),
379 ],
380 false,
381 '',
382 'json'
383 );
384 }
385
386 /**
387 * Get Image To Image get_image_to_image
388 *
389 * @param $image_data
390 * @param $context
391 * @param $request_ids
392 * @return mixed|\WP_Error
393 * @throws \Exception If image file not found.
394 */
395 public function get_image_to_image( $image_data, $context, $request_ids ) {
396 $image_file = get_attached_file( $image_data['attachment_id'] );
397
398 if ( ! $image_file ) {
399 throw new \Exception( 'Image file not found' );
400 }
401
402 $result = $this->ai_request(
403 'POST',
404 'image/image-to-image',
405 [
406 self::PROMPT => $image_data[ self::PROMPT ],
407 self::IMAGE_TYPE => $image_data['promptSettings'][ self::IMAGE_TYPE ] . '/' . $image_data['promptSettings'][ self::STYLE_PRESET ],
408 self::IMAGE_STRENGTH => $image_data['promptSettings'][ self::IMAGE_STRENGTH ],
409 self::ASPECT_RATIO => $image_data['promptSettings'][ self::ASPECT_RATIO ],
410 'context' => wp_json_encode( $context ),
411 'ids' => $request_ids,
412 'api_version' => ELEMENTOR_VERSION,
413 'site_lang' => get_bloginfo( 'language' ),
414 ],
415 $image_file,
416 'image'
417 );
418
419 return $result;
420 }
421
422
423 private function resizeImageIfNeeded( $original_url ) {
424 try {
425 $max_file_size = 4194304;
426 $current_size = filesize( $original_url );
427
428 if ( $current_size <= $max_file_size ) {
429 return $original_url;
430 }
431
432 $image_editor = wp_get_image_editor( $original_url );
433
434 if ( is_wp_error( $image_editor ) ) {
435 return $original_url;
436 }
437
438 $dimensions = $image_editor->get_size();
439 $original_width = $dimensions['width'];
440 $original_height = $dimensions['height'];
441
442 $scaling_factor = sqrt( $max_file_size / $current_size );
443
444 $new_width = (int) ( $original_width * $scaling_factor );
445 $new_height = (int) ( $original_height * $scaling_factor );
446
447 $image_editor->resize( $new_width, $new_height, true );
448
449 $file_extension = pathinfo( $original_url, PATHINFO_EXTENSION );
450 $temp_image = tempnam( sys_get_temp_dir(), 'resized_' ) . '.' . $file_extension;
451
452 $image_editor->save( $temp_image );
453 return $temp_image;
454 } catch ( \Exception $e ) {
455 return $original_url;
456 }
457 }
458
459 public function get_unify_product_images( $image_data, $context, $request_ids ) {
460 $image_file = get_attached_file( $image_data['attachment_id'] );
461
462 if ( ! $image_file ) {
463 throw new \Exception( 'Image file not found' );
464 }
465
466 $final_path = $this->resizeImageIfNeeded( $image_file );
467
468 $result = $this->ai_request(
469 'POST',
470 'image/image-to-image/unify-product-images',
471 [
472 'aspectRatio' => $image_data['promptSettings'][ self::ASPECT_RATIO ],
473 'backgroundColor' => $image_data['promptSettings'][ self::IMAGE_BACKGROUND_COLOR ],
474 'featureIdentifier' => $image_data['featureIdentifier'],
475 'context' => wp_json_encode( $context ),
476 'ids' => $request_ids,
477 'api_version' => ELEMENTOR_VERSION,
478 'site_lang' => get_bloginfo( 'language' ),
479 ],
480 $final_path,
481 'image'
482 );
483
484 if ( $image_file !== $final_path ) {
485 unlink( $final_path );
486 }
487
488 return $result;
489 }
490
491 /**
492 * Get Image To Image Upscale get_image_to_image_upscale
493 *
494 * @param $image_data
495 * @param $context
496 * @param $request_ids
497 * @return mixed|\WP_Error
498 * @throws \Exception If image file not found.
499 */
500 public function get_image_to_image_upscale( $image_data, $context, $request_ids ) {
501 $image_file = get_attached_file( $image_data['attachment_id'] );
502
503 if ( ! $image_file ) {
504 throw new \Exception( 'Image file not found' );
505 }
506
507 $result = $this->ai_request(
508 'POST',
509 'image/image-to-image/upscale',
510 [
511 self::IMAGE_RESOLUTION => $image_data['promptSettings']['upscale_to'],
512 'context' => wp_json_encode( $context ),
513 'ids' => $request_ids,
514 'api_version' => ELEMENTOR_VERSION,
515 'site_lang' => get_bloginfo( 'language' ),
516 ],
517 $image_file,
518 'image'
519 );
520
521 return $result;
522 }
523
524 /**
525 * Get Image To Image Remove Background get_image_to_image_remove_background
526 *
527 * @param $image_data
528 * @param $context
529 * @param $request_ids
530 * @return mixed|\WP_Error
531 * @throws \Exception If image file not found.
532 */
533 public function get_image_to_image_remove_background( $image_data, $context, $request_ids ) {
534 $image_file = get_attached_file( $image_data['attachment_id'] );
535
536 if ( ! $image_file ) {
537 throw new \Exception( 'Image file not found' );
538 }
539
540 $result = $this->ai_request(
541 'POST',
542 'image/image-to-image/remove-background',
543 [
544 'context' => wp_json_encode( $context ),
545 'ids' => $request_ids,
546 'api_version' => ELEMENTOR_VERSION,
547 'site_lang' => get_bloginfo( 'language' ),
548 ],
549 $image_file,
550 'image'
551 );
552
553 return $result;
554 }
555
556 /**
557 * Get Image To Image Remove Text get_image_to_image_remove_text
558 *
559 * @param $image_data
560 * @param $context
561 * @param $request_ids
562 * @return mixed|\WP_Error
563 * @throws \Exception If image file not found.
564 */
565 public function get_image_to_image_replace_background( $image_data, $context, $request_ids ) {
566 $image_file = get_attached_file( $image_data['attachment_id'] );
567
568 if ( ! $image_file ) {
569 throw new \Exception( 'Image file not found' );
570 }
571
572 $result = $this->ai_request(
573 'POST',
574 'image/image-to-image/replace-background',
575 [
576 self::PROMPT => $image_data[ self::PROMPT ],
577 'context' => wp_json_encode( $context ),
578 'ids' => $request_ids,
579 'api_version' => ELEMENTOR_VERSION,
580 'site_lang' => get_bloginfo( 'language' ),
581 ],
582 $image_file,
583 'image'
584 );
585
586 return $result;
587 }
588
589 /**
590 * Store Temp File store_temp_file
591 * used to store a temp file for the AI request and deletes it once the request is done
592 *
593 * @param $file_content
594 * @param $file_ext
595 *
596 * @return string
597 */
598 private function store_temp_file( $file_content, $file_ext = '' ) {
599 $temp_file = str_replace( '.tmp', '', wp_tempnam() . $file_ext );
600 file_put_contents( $temp_file, $file_content );
601 // make sure the temp file is deleted on shutdown
602 register_shutdown_function( function () use ( $temp_file ) {
603 if ( file_exists( $temp_file ) ) {
604 unlink( $temp_file );
605 }
606 } );
607 return $temp_file;
608 }
609
610 /**
611 * Get Image To Image Out Painting get_image_to_image_out_painting
612 *
613 * @param $image_data
614 * @param $context
615 * @param $request_ids
616 * @return mixed|\WP_Error
617 * @throws \Exception If image file not found.
618 */
619 public function get_image_to_image_out_painting( $image_data, $context, $request_ids ) {
620 $img_content = str_replace( ' ', '+', $image_data['mask'] );
621 $img_content = substr( $img_content, strpos( $img_content, ',' ) + 1 );
622 $img_content = base64_decode( $img_content );
623 $mask_file = $this->store_temp_file( $img_content, '.png' );
624
625 if ( ! $mask_file ) {
626 throw new \Exception( 'Expended Image file not found' );
627 }
628
629 $result = $this->ai_request(
630 'POST',
631 'image/image-to-image/outpainting',
632 [
633 'context' => wp_json_encode( $context ),
634 'ids' => $request_ids,
635 'api_version' => ELEMENTOR_VERSION,
636 'site_lang' => get_bloginfo( 'language' ),
637 'size' => wp_json_encode( $image_data['size'] ),
638 'position' => wp_json_encode( $image_data['position'] ),
639 'image_base64' => $image_data['image_base64'],
640 $image_data['image'],
641 ],
642 [
643 [
644 'name' => 'image',
645 'type' => 'image',
646 'path' => $mask_file,
647 ],
648 ]
649 );
650
651 return $result;
652 }
653
654 /**
655 * Get Image To Image Mask get_image_to_image_mask
656 *
657 * @param $image_data
658 * @param $context
659 * @param $request_ids
660 * @return mixed|\WP_Error
661 * @throws \Exception If image file not found.
662 */
663 public function get_image_to_image_mask( $image_data, $context, $request_ids ) {
664 $image_file = get_attached_file( $image_data['attachment_id'] );
665 $mask_file = $this->store_temp_file( $image_data['mask'], '.svg' );
666
667 if ( ! $image_file ) {
668 throw new \Exception( 'Image file not found' );
669 }
670
671 if ( ! $mask_file ) {
672 throw new \Exception( 'Mask file not found' );
673 }
674
675 $result = $this->ai_request(
676 'POST',
677 'image/image-to-image/inpainting',
678 [
679 self::PROMPT => $image_data[ self::PROMPT ],
680 'context' => wp_json_encode( $context ),
681 'ids' => $request_ids,
682 'api_version' => ELEMENTOR_VERSION,
683 'site_lang' => get_bloginfo( 'language' ),
684 'image_base64' => $image_data['image_base64'],
685 ],
686 [
687 [
688 'name' => 'image',
689 'type' => 'image',
690 'path' => $image_file,
691 ],
692 [
693 'name' => 'mask_image',
694 'type' => 'image/svg+xml',
695 'path' => $mask_file,
696 ],
697 ]
698 );
699
700 return $result;
701 }
702 public function get_image_to_image_mask_cleanup( $image_data, $context, $request_ids ) {
703 $image_file = get_attached_file( $image_data['attachment_id'] );
704 $mask_file = $this->store_temp_file( $image_data['mask'], '.svg' );
705
706 if ( ! $image_file ) {
707 throw new \Exception( 'Image file not found' );
708 }
709
710 if ( ! $mask_file ) {
711 throw new \Exception( 'Mask file not found' );
712 }
713
714 $result = $this->ai_request(
715 'POST',
716 'image/image-to-image/cleanup',
717 [
718 self::PROMPT => $image_data[ self::PROMPT ],
719 'context' => wp_json_encode( $context ),
720 'ids' => $request_ids,
721 'api_version' => ELEMENTOR_VERSION,
722 'site_lang' => get_bloginfo( 'language' ),
723 'image_base64' => $image_data['image_base64'],
724 ],
725 [
726 [
727 'name' => 'image',
728 'type' => 'image',
729 'path' => $image_file,
730 ],
731 [
732 'name' => 'mask_image',
733 'type' => 'image/svg+xml',
734 'path' => $mask_file,
735 ],
736 ]
737 );
738
739 return $result;
740 }
741
742 public function generate_layout( $data, $context ) {
743 $endpoint = 'generate/layout';
744
745 $body = [
746 'prompt' => $data['prompt'],
747 'variationType' => (int) $data['variationType'],
748 'ids' => $data['ids'],
749 ];
750
751 if ( ! empty( $data['prevGeneratedIds'] ) ) {
752 $body['generatedBaseTemplatesIds'] = $data['prevGeneratedIds'];
753 }
754
755 if ( ! empty( $data['attachments'] ) ) {
756 $attachment = $data['attachments'][0];
757
758 switch ( $attachment['type'] ) {
759 case 'json':
760 $endpoint = 'generate/generate-json-variation';
761
762 $body['json'] = [
763 'type' => 'elementor',
764 'elements' => [ $attachment['content'] ],
765 'label' => $attachment['label'],
766 'source' => $attachment['source'],
767 ];
768 break;
769 case 'url':
770 $endpoint = 'generate/html-to-elementor';
771
772 $html = wp_json_encode( $attachment['content'] );
773
774 $body['html'] = $html;
775 $body['htmlFetchedUrl'] = $attachment['label'];
776
777 break;
778 }
779 }
780
781 $context['currentContext'] = $data['currentContext'];
782 $context['features'] = [
783 'supportedFeatures' => [ 'Taxonomy' ],
784 ];
785
786 if ( ElementorUtils::has_pro() ) {
787 $context['features']['subscriptions'] = [ 'Pro' ];
788 }
789
790 if ( Plugin::instance()->experiments->get_active_features()['nested-elements'] ) {
791 $context['features']['supportedFeatures'][] = 'Nested';
792 }
793
794 if ( Plugin::instance()->experiments->get_active_features()['mega-menu'] ) {
795 $context['features']['supportedFeatures'][] = 'MegaMenu';
796 }
797
798 if ( class_exists( 'WC' ) ) {
799 $context['features']['supportedFeatures'][] = 'WooCommerce';
800 }
801
802 $metadata = [
803 'context' => $context,
804 'api_version' => ELEMENTOR_VERSION,
805 'site_lang' => get_bloginfo( 'language' ),
806 'config' => [
807 'generate' => [
808 'all' => true,
809 ],
810 ],
811 ];
812
813 $body = array_merge( $body, $metadata );
814
815 // Temp hack for platforms that filters the http_request_args, and it breaks JSON requests.
816 remove_all_filters( 'http_request_args' );
817
818 return $this->ai_request(
819 'POST',
820 $endpoint,
821 $body,
822 false,
823 '',
824 'json'
825 );
826 }
827
828 public function get_layout_prompt_enhanced( $prompt, $enhance_type, $context ) {
829 return $this->ai_request(
830 'POST',
831 'generate/enhance-prompt',
832 [
833 'prompt' => $prompt,
834 'enhance_type' => $enhance_type,
835 'context' => wp_json_encode( $context ),
836 'api_version' => ELEMENTOR_VERSION,
837 'site_lang' => get_bloginfo( 'language' ),
838 ],
839 false,
840 '',
841 'json'
842 );
843 }
844
845 public function get_history_by_type( $type, $page, $limit, $context = [] ) {
846 $endpoint = Module::HISTORY_TYPE_ALL === $type
847 ? 'history'
848 : add_query_arg( [
849 'page' => $page,
850 'limit' => $limit,
851 ], "history/{$type}" );
852
853 return $this->ai_request(
854 'POST',
855 $endpoint,
856 [
857 'context' => wp_json_encode( $context ),
858 'api_version' => ELEMENTOR_VERSION,
859 'site_lang' => get_bloginfo( 'language' ),
860 ]
861 );
862 }
863
864 public function delete_history_item( $id, $context = [] ) {
865 return $this->ai_request(
866 'DELETE', 'history/' . $id,
867 [
868 'context' => wp_json_encode( $context ),
869 'api_version' => ELEMENTOR_VERSION,
870 'site_lang' => get_bloginfo( 'language' ),
871 ]
872 );
873 }
874
875 public function toggle_favorite_history_item( $id, $context = [] ) {
876 $sanitized_id = str_replace( '%', '%%', $id );
877 return $this->ai_request(
878 'POST', sprintf( 'history/%s/favorite', $sanitized_id ),
879 [
880 'context' => wp_json_encode( $context ),
881 'api_version' => ELEMENTOR_VERSION,
882 'site_lang' => get_bloginfo( 'language' ),
883 ]
884 );
885 }
886
887 public function get_animation( $data, $context, $request_ids ) {
888 return $this->ai_request(
889 'POST',
890 'text/get-motion-effect',
891 [
892 'prompt' => $data['payload']['prompt'],
893 'motionEffectType' => $data['payload']['motionEffectType'],
894 'context' => wp_json_encode( $context ),
895 'ids' => $request_ids,
896 'api_version' => ELEMENTOR_VERSION,
897 'site_lang' => get_bloginfo( 'language' ),
898 ],
899 false,
900 '',
901 'json'
902 );
903 }
904
905 protected function init() {}
906 }
907