PluginProbe
Elementor Website Builder – more than just a page builder / 3.28.0-dev3
Elementor Website Builder – more than just a page builder v3.28.0-dev3
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 3.28.0-dev3, at modules/ai/connect/ai.php

905 lines 22.2 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 'context' => wp_json_encode( $context ),
475 'ids' => $request_ids,
476 'api_version' => ELEMENTOR_VERSION,
477 'site_lang' => get_bloginfo( 'language' ),
478 ],
479 $final_path,
480 'image'
481 );
482
483 if ( $image_file !== $final_path ) {
484 unlink( $final_path );
485 }
486
487 return $result;
488 }
489
490 /**
491 * Get Image To Image Upscale get_image_to_image_upscale
492 *
493 * @param $image_data
494 * @param $context
495 * @param $request_ids
496 * @return mixed|\WP_Error
497 * @throws \Exception If image file not found.
498 */
499 public function get_image_to_image_upscale( $image_data, $context, $request_ids ) {
500 $image_file = get_attached_file( $image_data['attachment_id'] );
501
502 if ( ! $image_file ) {
503 throw new \Exception( 'Image file not found' );
504 }
505
506 $result = $this->ai_request(
507 'POST',
508 'image/image-to-image/upscale',
509 [
510 self::IMAGE_RESOLUTION => $image_data['promptSettings']['upscale_to'],
511 'context' => wp_json_encode( $context ),
512 'ids' => $request_ids,
513 'api_version' => ELEMENTOR_VERSION,
514 'site_lang' => get_bloginfo( 'language' ),
515 ],
516 $image_file,
517 'image'
518 );
519
520 return $result;
521 }
522
523 /**
524 * Get Image To Image Remove Background get_image_to_image_remove_background
525 *
526 * @param $image_data
527 * @param $context
528 * @param $request_ids
529 * @return mixed|\WP_Error
530 * @throws \Exception If image file not found.
531 */
532 public function get_image_to_image_remove_background( $image_data, $context, $request_ids ) {
533 $image_file = get_attached_file( $image_data['attachment_id'] );
534
535 if ( ! $image_file ) {
536 throw new \Exception( 'Image file not found' );
537 }
538
539 $result = $this->ai_request(
540 'POST',
541 'image/image-to-image/remove-background',
542 [
543 'context' => wp_json_encode( $context ),
544 'ids' => $request_ids,
545 'api_version' => ELEMENTOR_VERSION,
546 'site_lang' => get_bloginfo( 'language' ),
547 ],
548 $image_file,
549 'image'
550 );
551
552 return $result;
553 }
554
555 /**
556 * Get Image To Image Remove Text get_image_to_image_remove_text
557 *
558 * @param $image_data
559 * @param $context
560 * @param $request_ids
561 * @return mixed|\WP_Error
562 * @throws \Exception If image file not found.
563 */
564 public function get_image_to_image_replace_background( $image_data, $context, $request_ids ) {
565 $image_file = get_attached_file( $image_data['attachment_id'] );
566
567 if ( ! $image_file ) {
568 throw new \Exception( 'Image file not found' );
569 }
570
571 $result = $this->ai_request(
572 'POST',
573 'image/image-to-image/replace-background',
574 [
575 self::PROMPT => $image_data[ self::PROMPT ],
576 'context' => wp_json_encode( $context ),
577 'ids' => $request_ids,
578 'api_version' => ELEMENTOR_VERSION,
579 'site_lang' => get_bloginfo( 'language' ),
580 ],
581 $image_file,
582 'image'
583 );
584
585 return $result;
586 }
587
588 /**
589 * Store Temp File store_temp_file
590 * used to store a temp file for the AI request and deletes it once the request is done
591 *
592 * @param $file_content
593 * @param $file_ext
594 *
595 * @return string
596 */
597 private function store_temp_file( $file_content, $file_ext = '' ) {
598 $temp_file = str_replace( '.tmp', '', wp_tempnam() . $file_ext );
599 file_put_contents( $temp_file, $file_content );
600 // make sure the temp file is deleted on shutdown
601 register_shutdown_function( function () use ( $temp_file ) {
602 if ( file_exists( $temp_file ) ) {
603 unlink( $temp_file );
604 }
605 } );
606 return $temp_file;
607 }
608
609 /**
610 * Get Image To Image Out Painting get_image_to_image_out_painting
611 *
612 * @param $image_data
613 * @param $context
614 * @param $request_ids
615 * @return mixed|\WP_Error
616 * @throws \Exception If image file not found.
617 */
618 public function get_image_to_image_out_painting( $image_data, $context, $request_ids ) {
619 $img_content = str_replace( ' ', '+', $image_data['mask'] );
620 $img_content = substr( $img_content, strpos( $img_content, ',' ) + 1 );
621 $img_content = base64_decode( $img_content );
622 $mask_file = $this->store_temp_file( $img_content, '.png' );
623
624 if ( ! $mask_file ) {
625 throw new \Exception( 'Expended Image file not found' );
626 }
627
628 $result = $this->ai_request(
629 'POST',
630 'image/image-to-image/outpainting',
631 [
632 'context' => wp_json_encode( $context ),
633 'ids' => $request_ids,
634 'api_version' => ELEMENTOR_VERSION,
635 'site_lang' => get_bloginfo( 'language' ),
636 'size' => wp_json_encode( $image_data['size'] ),
637 'position' => wp_json_encode( $image_data['position'] ),
638 'image_base64' => $image_data['image_base64'],
639 $image_data['image'],
640 ],
641 [
642 [
643 'name' => 'image',
644 'type' => 'image',
645 'path' => $mask_file,
646 ],
647 ]
648 );
649
650 return $result;
651 }
652
653 /**
654 * Get Image To Image Mask get_image_to_image_mask
655 *
656 * @param $image_data
657 * @param $context
658 * @param $request_ids
659 * @return mixed|\WP_Error
660 * @throws \Exception If image file not found.
661 */
662 public function get_image_to_image_mask( $image_data, $context, $request_ids ) {
663 $image_file = get_attached_file( $image_data['attachment_id'] );
664 $mask_file = $this->store_temp_file( $image_data['mask'], '.svg' );
665
666 if ( ! $image_file ) {
667 throw new \Exception( 'Image file not found' );
668 }
669
670 if ( ! $mask_file ) {
671 throw new \Exception( 'Mask file not found' );
672 }
673
674 $result = $this->ai_request(
675 'POST',
676 'image/image-to-image/inpainting',
677 [
678 self::PROMPT => $image_data[ self::PROMPT ],
679 'context' => wp_json_encode( $context ),
680 'ids' => $request_ids,
681 'api_version' => ELEMENTOR_VERSION,
682 'site_lang' => get_bloginfo( 'language' ),
683 'image_base64' => $image_data['image_base64'],
684 ],
685 [
686 [
687 'name' => 'image',
688 'type' => 'image',
689 'path' => $image_file,
690 ],
691 [
692 'name' => 'mask_image',
693 'type' => 'image/svg+xml',
694 'path' => $mask_file,
695 ],
696 ]
697 );
698
699 return $result;
700 }
701 public function get_image_to_image_mask_cleanup( $image_data, $context, $request_ids ) {
702 $image_file = get_attached_file( $image_data['attachment_id'] );
703 $mask_file = $this->store_temp_file( $image_data['mask'], '.svg' );
704
705 if ( ! $image_file ) {
706 throw new \Exception( 'Image file not found' );
707 }
708
709 if ( ! $mask_file ) {
710 throw new \Exception( 'Mask file not found' );
711 }
712
713 $result = $this->ai_request(
714 'POST',
715 'image/image-to-image/cleanup',
716 [
717 self::PROMPT => $image_data[ self::PROMPT ],
718 'context' => wp_json_encode( $context ),
719 'ids' => $request_ids,
720 'api_version' => ELEMENTOR_VERSION,
721 'site_lang' => get_bloginfo( 'language' ),
722 'image_base64' => $image_data['image_base64'],
723 ],
724 [
725 [
726 'name' => 'image',
727 'type' => 'image',
728 'path' => $image_file,
729 ],
730 [
731 'name' => 'mask_image',
732 'type' => 'image/svg+xml',
733 'path' => $mask_file,
734 ],
735 ]
736 );
737
738 return $result;
739 }
740
741 public function generate_layout( $data, $context ) {
742 $endpoint = 'generate/layout';
743
744 $body = [
745 'prompt' => $data['prompt'],
746 'variationType' => (int) $data['variationType'],
747 'ids' => $data['ids'],
748 ];
749
750 if ( ! empty( $data['prevGeneratedIds'] ) ) {
751 $body['generatedBaseTemplatesIds'] = $data['prevGeneratedIds'];
752 }
753
754 if ( ! empty( $data['attachments'] ) ) {
755 $attachment = $data['attachments'][0];
756
757 switch ( $attachment['type'] ) {
758 case 'json':
759 $endpoint = 'generate/generate-json-variation';
760
761 $body['json'] = [
762 'type' => 'elementor',
763 'elements' => [ $attachment['content'] ],
764 'label' => $attachment['label'],
765 'source' => $attachment['source'],
766 ];
767 break;
768 case 'url':
769 $endpoint = 'generate/html-to-elementor';
770
771 $html = wp_json_encode( $attachment['content'] );
772
773 $body['html'] = $html;
774 $body['htmlFetchedUrl'] = $attachment['label'];
775
776 break;
777 }
778 }
779
780 $context['currentContext'] = $data['currentContext'];
781 $context['features'] = [
782 'supportedFeatures' => [ 'Taxonomy' ],
783 ];
784
785 if ( ElementorUtils::has_pro() ) {
786 $context['features']['subscriptions'] = [ 'Pro' ];
787 }
788
789 if ( Plugin::instance()->experiments->get_active_features()['nested-elements'] ) {
790 $context['features']['supportedFeatures'][] = 'Nested';
791 }
792
793 if ( Plugin::instance()->experiments->get_active_features()['mega-menu'] ) {
794 $context['features']['supportedFeatures'][] = 'MegaMenu';
795 }
796
797 if ( class_exists( 'WC' ) ) {
798 $context['features']['supportedFeatures'][] = 'WooCommerce';
799 }
800
801 $metadata = [
802 'context' => $context,
803 'api_version' => ELEMENTOR_VERSION,
804 'site_lang' => get_bloginfo( 'language' ),
805 'config' => [
806 'generate' => [
807 'all' => true,
808 ],
809 ],
810 ];
811
812 $body = array_merge( $body, $metadata );
813
814 // Temp hack for platforms that filters the http_request_args, and it breaks JSON requests.
815 remove_all_filters( 'http_request_args' );
816
817 return $this->ai_request(
818 'POST',
819 $endpoint,
820 $body,
821 false,
822 '',
823 'json'
824 );
825 }
826
827 public function get_layout_prompt_enhanced( $prompt, $enhance_type, $context ) {
828 return $this->ai_request(
829 'POST',
830 'generate/enhance-prompt',
831 [
832 'prompt' => $prompt,
833 'enhance_type' => $enhance_type,
834 'context' => wp_json_encode( $context ),
835 'api_version' => ELEMENTOR_VERSION,
836 'site_lang' => get_bloginfo( 'language' ),
837 ],
838 false,
839 '',
840 'json'
841 );
842 }
843
844 public function get_history_by_type( $type, $page, $limit, $context = [] ) {
845 $endpoint = Module::HISTORY_TYPE_ALL === $type
846 ? 'history'
847 : add_query_arg( [
848 'page' => $page,
849 'limit' => $limit,
850 ], "history/{$type}" );
851
852 return $this->ai_request(
853 'POST',
854 $endpoint,
855 [
856 'context' => wp_json_encode( $context ),
857 'api_version' => ELEMENTOR_VERSION,
858 'site_lang' => get_bloginfo( 'language' ),
859 ]
860 );
861 }
862
863 public function delete_history_item( $id, $context = [] ) {
864 return $this->ai_request(
865 'DELETE', 'history/' . $id,
866 [
867 'context' => wp_json_encode( $context ),
868 'api_version' => ELEMENTOR_VERSION,
869 'site_lang' => get_bloginfo( 'language' ),
870 ]
871 );
872 }
873
874 public function toggle_favorite_history_item( $id, $context = [] ) {
875 return $this->ai_request(
876 'POST', sprintf( 'history/%s/favorite', $id ),
877 [
878 'context' => wp_json_encode( $context ),
879 'api_version' => ELEMENTOR_VERSION,
880 'site_lang' => get_bloginfo( 'language' ),
881 ]
882 );
883 }
884
885 public function get_animation( $data, $context, $request_ids ) {
886 return $this->ai_request(
887 'POST',
888 'text/get-motion-effect',
889 [
890 'prompt' => $data['payload']['prompt'],
891 'motionEffectType' => $data['payload']['motionEffectType'],
892 'context' => wp_json_encode( $context ),
893 'ids' => $request_ids,
894 'api_version' => ELEMENTOR_VERSION,
895 'site_lang' => get_bloginfo( 'language' ),
896 ],
897 false,
898 '',
899 'json'
900 );
901 }
902
903 protected function init() {}
904 }
905