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

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