PluginProbe
Elementor Website Builder – more than just a page builder / 3.19.0-dev3
Elementor Website Builder – more than just a page builder v3.19.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
← All changes | modules/ai/module.php +165 -782 4.2.23.19.0-dev3 View file →
@@ -1,17 +1,14 @@
1 1 <?php
2 2 namespace Elementor\Modules\Ai;
3 3
4 -use Elementor\Controls_Manager;
5 4 use Elementor\Core\Base\Module as BaseModule;
6 5 use Elementor\Core\Common\Modules\Connect\Module as ConnectModule;
7 -use Elementor\Element_Base;
8 -use Elementor\Modules\Ai\Feature_Intro\Product_Image_Unification_Intro;
9 -use Elementor\Plugin;
6 +use Elementor\Core\Experiments\Manager as Experiments_Manager;
10 7 use Elementor\Core\Utils\Collection;
11 8 use Elementor\Modules\Ai\Connect\Ai;
9 +use Elementor\Plugin;
12 10 use Elementor\User;
13 -use Elementor\Utils;
14 11
15 12 if ( ! defined( 'ABSPATH' ) ) {
16 13 exit; // Exit if accessed directly.
17 14 }
@@ -28,10 +25,11 @@
28 25 self::HISTORY_TYPE_CODE,
29 26 self::HISTORY_TYPE_IMAGE,
30 27 self::HISTORY_TYPE_BLOCK,
31 28 ];
32 - const MIN_PAGES_FOR_CREATE_WITH_AI_BANNER = 10;
33 29
30 + const LAYOUT_EXPERIMENT = 'ai-layout';
31 +
34 32 public function get_name() {
35 33 return 'ai';
36 34 }
37 35
@@ -37,21 +35,10 @@
37 35
38 36 public function __construct() {
39 37 parent::__construct();
40 38
41 - ( new SitePlannerConnect\Module() );
39 + $this->register_layout_experiment();
42 40
43 - if ( is_admin() ) {
44 - ( new Preferences() )->register();
45 - add_action( 'elementor/import-export/import-kit/runner/after-run', [ $this, 'handle_kit_install' ] );
46 - }
47 -
48 - if ( ! $this->is_ai_enabled() ) {
49 - return;
50 - }
51 -
52 - add_filter( 'elementor/core/admin/homescreen', [ $this, 'add_create_with_ai_banner_to_homescreen' ] );
53 -
54 41 add_action( 'elementor/connect/apps/register', function ( ConnectModule $connect_module ) {
55 42 $connect_module->register_app( 'ai', Ai::get_class_name() );
56 43 } );
57 44
@@ -58,12 +45,9 @@
58 45 add_action( 'elementor/ajax/register_actions', function( $ajax ) {
59 46 $handlers = [
60 47 'ai_get_user_information' => [ $this, 'ajax_ai_get_user_information' ],
61 48 'ai_get_remote_config' => [ $this, 'ajax_ai_get_remote_config' ],
62 - 'ai_get_remote_frontend_config' => [ $this, 'ajax_ai_get_remote_frontend_config' ],
63 49 'ai_get_completion_text' => [ $this, 'ajax_ai_get_completion_text' ],
64 - 'ai_get_excerpt' => [ $this, 'ajax_ai_get_excerpt' ],
65 - 'ai_get_featured_image' => [ $this, 'ajax_ai_get_featured_image' ],
66 50 'ai_get_edit_text' => [ $this, 'ajax_ai_get_edit_text' ],
67 51 'ai_get_custom_code' => [ $this, 'ajax_ai_get_custom_code' ],
68 52 'ai_get_custom_css' => [ $this, 'ajax_ai_get_custom_css' ],
69 53 'ai_set_get_started' => [ $this, 'ajax_ai_set_get_started' ],
@@ -71,9 +55,8 @@
71 55 'ai_get_image_prompt_enhancer' => [ $this, 'ajax_ai_get_image_prompt_enhancer' ],
72 56 'ai_get_text_to_image' => [ $this, 'ajax_ai_get_text_to_image' ],
73 57 'ai_get_image_to_image' => [ $this, 'ajax_ai_get_image_to_image' ],
74 58 'ai_get_image_to_image_mask' => [ $this, 'ajax_ai_get_image_to_image_mask' ],
75 - 'ai_get_image_to_image_mask_cleanup' => [ $this, 'ajax_ai_get_image_to_image_mask_cleanup' ],
76 59 'ai_get_image_to_image_outpainting' => [ $this, 'ajax_ai_get_image_to_image_outpainting' ],
77 60 'ai_get_image_to_image_upscale' => [ $this, 'ajax_ai_get_image_to_image_upscale' ],
78 61 'ai_get_image_to_image_remove_background' => [ $this, 'ajax_ai_get_image_to_image_remove_background' ],
79 62 'ai_get_image_to_image_replace_background' => [ $this, 'ajax_ai_get_image_to_image_replace_background' ],
@@ -82,11 +65,8 @@
82 65 'ai_get_layout_prompt_enhancer' => [ $this, 'ajax_ai_get_layout_prompt_enhancer' ],
83 66 'ai_get_history' => [ $this, 'ajax_ai_get_history' ],
84 67 'ai_delete_history_item' => [ $this, 'ajax_ai_delete_history_item' ],
85 68 'ai_toggle_favorite_history_item' => [ $this, 'ajax_ai_toggle_favorite_history_item' ],
86 - 'ai_get_product_image_unification' => [ $this, 'ajax_ai_get_product_image_unification' ],
87 - 'ai_get_animation' => [ $this, 'ajax_ai_get_animation' ],
88 - 'ai_get_image_to_image_isolate_objects' => [ $this, 'ajax_ai_get_product_image_unification' ],
89 69 ];
90 70
91 71 foreach ( $handlers as $tag => $callback ) {
92 72 $ajax->register_ajax_action( $tag, $callback );
@@ -94,9 +74,12 @@
94 74 } );
95 75
96 76 add_action( 'elementor/editor/before_enqueue_scripts', function() {
97 77 $this->enqueue_main_script();
98 - $this->enqueue_layout_script();
78 +
79 + if ( $this->is_layout_active() ) {
80 + $this->enqueue_layout_script();
81 + }
99 82 } );
100 83
101 84 add_action( 'elementor/editor/after_enqueue_styles', function() {
102 85 wp_enqueue_style(
@@ -107,352 +90,40 @@
107 90 );
108 91 } );
109 92
110 93 add_action( 'elementor/preview/enqueue_styles', function() {
111 - wp_enqueue_style(
112 - 'elementor-ai-layout-preview',
113 - $this->get_css_assets_url( 'modules/ai/layout-preview' ),
114 - [],
115 - ELEMENTOR_VERSION
116 - );
94 + if ( $this->is_layout_active() ) {
95 + wp_enqueue_style(
96 + 'elementor-ai-layout-preview',
97 + $this->get_css_assets_url( 'modules/ai/layout-preview' ),
98 + [],
99 + ELEMENTOR_VERSION
100 + );
101 + }
117 102 } );
118 103
119 - if ( is_admin() ) {
120 - add_action( 'wp_enqueue_media', [ $this, 'enqueue_ai_media_library' ] );
121 - add_action( 'admin_head', [ $this, 'enqueue_ai_media_library_upload_screen' ] );
122 -
123 - if ( current_user_can( 'edit_products' ) || current_user_can( 'publish_products' ) ) {
124 - add_action( 'admin_init', [ $this, 'enqueue_ai_products_page_scripts' ] );
125 - add_action( 'current_screen', [ $this, 'enqueue_ai_single_product_page_scripts' ] );
126 - add_action( 'wp_ajax_elementor-ai-get-product-images', [ $this, 'get_product_images_ajax' ] );
127 - add_action( 'wp_ajax_elementor-ai-set-product-images', [ $this, 'set_product_images_ajax' ] );
128 - Product_Image_Unification_Intro::add_hooks();
104 + add_filter( 'elementor/document/save/data', function ( $data ) {
105 + if ( $this->is_layout_active() ) {
106 + return $this->remove_temporary_containers( $data );
129 107 }
130 - }
131 108
132 - add_action( 'enqueue_block_editor_assets', function() {
133 - wp_enqueue_script( 'elementor-ai-gutenberg',
134 - $this->get_js_assets_url( 'ai-gutenberg' ),
135 - [
136 - 'jquery',
137 - 'elementor-v2-ui',
138 - 'elementor-v2-icons',
139 - 'wp-blocks',
140 - 'wp-element',
141 - 'wp-editor',
142 - 'wp-data',
143 - 'wp-components',
144 - 'wp-compose',
145 - 'wp-i18n',
146 - 'wp-hooks',
147 - 'elementor-ai-media-library',
148 - ],
149 - ELEMENTOR_VERSION, true );
150 -
151 - wp_localize_script(
152 - 'elementor-ai-gutenberg',
153 - 'ElementorAiConfig',
154 - [
155 - 'is_get_started' => User::get_introduction_meta( 'ai_get_started' ),
156 - 'connect_url' => $this->get_ai_connect_url(),
157 - ]
158 - );
159 -
160 - wp_set_script_translations( 'elementor-ai-gutenberg', 'elementor' );
161 - });
162 -
163 - add_filter( 'elementor/document/save/data', function ( $data ) {
164 - return $this->remove_temporary_containers( $data );
109 + return $data;
165 110 } );
166 -
167 - add_action( 'elementor/element/common/section_effects/after_section_start', [ $this, 'register_ai_motion_effect_control' ], 10, 1 );
168 - add_action( 'elementor/element/container/section_effects/after_section_start', [ $this, 'register_ai_motion_effect_control' ], 10, 1 );
169 - add_action( 'elementor/element/common/_section_transform/after_section_end', [ $this, 'register_ai_hover_effect_control' ], 10, 1 );
170 - add_action( 'elementor/element/container/_section_transform/after_section_end', [ $this, 'register_ai_hover_effect_control' ], 10, 1 );
171 111 }
172 112
173 - public function is_ai_enabled() {
174 - if ( ! Plugin::$instance->experiments->is_feature_active( 'container' ) ) {
175 - return false;
176 - }
177 -
178 - return Preferences::is_ai_enabled( get_current_user_id() );
179 - }
180 -
181 - public function handle_kit_install( $imported_data ) {
182 - if ( ! $this->is_ai_enabled() ) {
183 - return;
184 - }
185 -
186 - if ( ! isset( $imported_data['status'] ) || 'success' !== $imported_data['status'] ) {
187 - return;
188 - }
189 -
190 - if ( ! isset( $imported_data['runner'] ) || 'site-settings' !== $imported_data['runner'] ) {
191 - return;
192 - }
193 -
194 - if ( ! isset( $imported_data['configData']['lastImportedSession']['instance_data']['site_settings']['settings']['ai'] ) ) {
195 - return;
196 - }
197 -
198 - $is_connected = $this->get_ai_app()->is_connected() && User::get_introduction_meta( 'ai_get_started' );
199 -
200 - if ( ! $is_connected ) {
201 - return;
202 - }
203 -
204 - $last_imported_session = $imported_data['configData']['lastImportedSession'];
205 - $imported_ai_data = $last_imported_session['instance_data']['site_settings']['settings']['ai'];
206 -
207 - $this->get_ai_app()->send_event( [
208 - 'name' => 'kit_installed',
209 - 'data' => $imported_ai_data,
210 - 'client' => [
211 - 'name' => 'elementor',
212 - 'version' => ELEMENTOR_VERSION,
213 - 'session_id' => $last_imported_session['session_id'],
113 + private function register_layout_experiment() {
114 + Plugin::$instance->experiments->add_feature( [
115 + 'name' => static::LAYOUT_EXPERIMENT,
116 + 'title' => esc_html__( 'Build with AI', 'elementor' ),
117 + 'description' => esc_html__( 'Tap into the potential of AI to easily create and customize containers to your specifications, right within Elementor. This feature comes packed with handy AI tools, including generation, variations, and URL references.', 'elementor' ),
118 + 'default' => Experiments_Manager::STATE_ACTIVE,
119 + 'release_status' => Experiments_Manager::RELEASE_STATUS_BETA,
120 + 'dependencies' => [
121 + 'container',
214 122 ],
215 123 ] );
216 124 }
217 125
218 - public function register_ai_hover_effect_control( Element_Base $element ) {
219 - if ( ! $element->get_controls( 'ai_hover_animation' ) ) {
220 - $element->add_control(
221 - 'ai_hover_animation',
222 - [
223 - 'tabs_wrapper' => '_tabs_positioning',
224 - 'inner_tab' => '_tab_positioning_hover',
225 - 'label' => esc_html__( 'Animate With AI', 'elementor' ),
226 - 'type' => Controls_Manager::RAW_HTML,
227 - 'raw' => '
228 -<style>
229 - .elementor-control-ai_hover_animation .elementor-control-content {
230 - display: flex;
231 - flex-direction: row;
232 - justify-content: space-between;
233 - align-items: center;
234 - }
235 - .elementor-control-ai_hover_animation .elementor-control-raw-html {
236 - display: none;
237 - }
238 -</style>',
239 - 'render_type' => 'none',
240 - 'ai' => [
241 - 'active' => true,
242 - 'type' => 'hover_animation',
243 - ],
244 - ],
245 - [
246 - 'position' => [
247 - 'of' => '_transform_rotate_popover_hover',
248 - 'type' => 'control',
249 - 'at' => 'before',
250 - ],
251 - ]
252 - );
253 - }
254 - }
255 - public function register_ai_motion_effect_control( $element ) {
256 - if ( Utils::has_pro() && ! $element->get_controls( 'ai_animation' ) ) {
257 - $element->add_control(
258 - 'ai_animation',
259 - [
260 - 'label' => esc_html__( 'Animate With AI', 'elementor' ),
261 - 'type' => Controls_Manager::RAW_HTML,
262 - 'raw' => '
263 - <style>
264 - .elementor-control-ai_animation .elementor-control-content {
265 - display: flex;
266 - flex-direction: row;
267 - justify-content: space-between;
268 - align-items: center;
269 - }
270 - .elementor-control-ai_animation .elementor-control-raw-html {
271 - display: none;
272 - }
273 - </style>',
274 - 'render_type' => 'none',
275 - 'ai' => [
276 - 'active' => true,
277 - 'type' => 'animation',
278 - ],
279 - ]
280 - );
281 - }
282 - }
283 -
284 - private function get_current_screen() {
285 - $is_wc = class_exists( 'WooCommerce' ) && post_type_exists( 'product' );
286 - if ( ! $is_wc ) {
287 - return 'other';
288 - }
289 -
290 - $is_products_page = isset( $_GET['post_type'] ) && 'product' === $_GET['post_type'];
291 - if ( $is_products_page ) {
292 - return 'wc-products';
293 - }
294 -
295 - $screen = get_current_screen();
296 - $is_single_product_page = isset( $screen->post_type ) && ( 'product' === $screen->post_type && 'post' === $screen->base );
297 - if ( $is_single_product_page ) {
298 - return 'wc-single-product';
299 - }
300 -
301 - return 'other';
302 - }
303 -
304 - public function enqueue_ai_products_page_scripts() {
305 - if ( 'wc-products' !== $this->get_current_screen() ) {
306 - return;
307 - }
308 -
309 - $this->add_wc_scripts();
310 - }
311 -
312 - public function enqueue_ai_single_product_page_scripts() {
313 - if ( 'wc-single-product' !== $this->get_current_screen() ) {
314 - return;
315 - }
316 -
317 - $this->add_wc_scripts();
318 - }
319 -
320 - private function add_products_bulk_action( $bulk_actions ) {
321 - $bulk_actions['elementor-ai-unify-product-images'] = __( 'Unify with Elementor AI', 'elementor' );
322 - return $bulk_actions;
323 - }
324 -
325 - public function get_product_images_ajax() {
326 - check_ajax_referer( 'elementor-ai-unify-product-images_nonce', 'nonce' );
327 -
328 - $post_ids = isset( $_POST['post_ids'] ) ? array_map( 'intval', $_POST['post_ids'] ) : [];
329 - $is_galley_only = isset( $_POST['is_galley_only'] ) && sanitize_text_field( wp_unslash( $_POST['is_galley_only'] ) );
330 -
331 - $image_ids = [];
332 -
333 - foreach ( $post_ids as $post_id ) {
334 - if ( $is_galley_only ) {
335 - $product = wc_get_product( $post_id );
336 - $gallery_image_ids = $product->get_gallery_image_ids();
337 - foreach ( $gallery_image_ids as $image_id ) {
338 - $image_ids[] = [
339 - 'productId' => $post_id,
340 - 'id' => $image_id,
341 - 'image_url' => wp_get_attachment_url( $image_id ),
342 - ];
343 - }
344 - continue;
345 - }
346 -
347 - $image_id = get_post_thumbnail_id( $post_id );
348 -
349 - if ( ! $image_id ) {
350 - $product = wc_get_product( $post_id );
351 - $gallery_image_ids = $product->get_gallery_image_ids();
352 - if ( ! empty( $gallery_image_ids ) ) {
353 - $image_id = $gallery_image_ids[0];
354 - }
355 - }
356 -
357 - $image_ids[] = [
358 - 'productId' => $post_id,
359 - 'id' => $image_id ? $image_id : 'No Image',
360 - 'image_url' => $image_id ? wp_get_attachment_url( $image_id ) : 'No Image',
361 - ];
362 - }
363 -
364 - wp_send_json_success( [ 'product_images' => array_slice( $image_ids, 0, 10 ) ] );
365 -
366 - wp_die();
367 - }
368 -
369 - private function get_attachment_id_by_url( $url ) {
370 - $attachments = get_posts( [
371 - 'post_type' => 'attachment',
372 - 'meta_query' => [
373 - [
374 - 'key' => '_wp_attached_file',
375 - 'value' => basename( $url ),
376 - 'compare' => 'LIKE',
377 - ],
378 - ],
379 - 'fields' => 'ids',
380 - 'numberposts' => 1,
381 - ] );
382 -
383 - return ! empty( $attachments ) ? $attachments[0] : null;
384 - }
385 -
386 - public function set_product_images_ajax() {
387 - check_ajax_referer( 'elementor-ai-unify-product-images_nonce', 'nonce' );
388 -
389 - $product_id = isset( $_POST['productId'] ) ? sanitize_text_field( wp_unslash( $_POST['productId'] ) ) : '';
390 - $image_url = isset( $_POST['image_url'] ) ? sanitize_text_field( wp_unslash( $_POST['image_url'] ) ) : '';
391 - $image_to_add = isset( $_POST['image_to_add'] ) ? intval( wp_unslash( $_POST['image_to_add'] ) ) : null;
392 - $image_to_remove = isset( $_POST['image_to_remove'] ) ? intval( wp_unslash( $_POST['image_to_remove'] ) ) : null;
393 - $is_product_gallery = isset( $_POST['is_product_gallery'] ) && sanitize_text_field( wp_unslash( $_POST['is_product_gallery'] ) ) === 'true';
394 -
395 - if ( ! $product_id || ! $image_url ) {
396 - throw new \Exception( 'Product ID and Image URL are required' );
397 - }
398 -
399 - $product = wc_get_product( $product_id );
400 - if ( ! $product ) {
401 - throw new \Exception( 'Product not found' );
402 - }
403 -
404 - $attachment_id = $this->get_attachment_id_by_url( $image_url );
405 - if ( is_wp_error( $attachment_id ) ) {
406 - throw new \Exception( 'Image upload failed' );
407 - }
408 -
409 - if ( $is_product_gallery ) {
410 - $this->update_product_gallery( $product, $image_to_remove, $image_to_add );
411 - } else {
412 - $product->set_image_id( $attachment_id );
413 - $product->save();
414 - }
415 -
416 - wp_send_json_success( [
417 - 'message' => __( 'Image added successfully', 'elementor' ),
418 - ] );
419 - }
420 -
421 - public function enqueue_ai_media_library_upload_screen() {
422 - $screen = get_current_screen();
423 - if ( ! $screen || 'upload' !== $screen->id ) {
424 - return;
425 - }
426 -
427 - $this->enqueue_ai_media_library();
428 - }
429 -
430 - public function enqueue_ai_media_library() {
431 - wp_enqueue_script( 'elementor-ai-media-library',
432 - $this->get_js_assets_url( 'ai-media-library' ),
433 - [
434 - 'jquery',
435 - 'elementor-v2-ui',
436 - 'elementor-v2-icons',
437 - 'media-grid',
438 - ],
439 - ELEMENTOR_VERSION,
440 - true
441 - );
442 -
443 - wp_localize_script(
444 - 'elementor-ai-media-library',
445 - 'ElementorAiConfig',
446 - [
447 - 'is_get_started' => User::get_introduction_meta( 'ai_get_started' ),
448 - 'connect_url' => $this->get_ai_connect_url(),
449 - ]
450 - );
451 -
452 - wp_set_script_translations( 'elementor-ai-media-library', 'elementor' );
453 - }
454 -
455 126 private function enqueue_main_script() {
456 127 wp_enqueue_script(
457 128 'elementor-ai',
458 129 $this->get_js_assets_url( 'ai' ),
@@ -476,8 +147,13 @@
476 147 'is_get_started' => User::get_introduction_meta( 'ai_get_started' ),
477 148 'connect_url' => $this->get_ai_connect_url(),
478 149 ];
479 150
151 + if ( $this->get_ai_app()->is_connected() ) {
152 + // Use a cached version, don't call the API on every editor load.
153 + $config['usage'] = $this->get_ai_app()->get_cached_usage();
154 + }
155 +
480 156 wp_localize_script(
481 157 'elementor-ai',
482 158 'ElementorAiConfig',
483 159 $config
@@ -507,10 +183,14 @@
507 183
508 184 wp_set_script_translations( 'elementor-ai-layout', 'elementor' );
509 185 }
510 186
187 + private function is_layout_active() {
188 + return Plugin::$instance->experiments->is_feature_active( self::LAYOUT_EXPERIMENT );
189 + }
190 +
511 191 private function remove_temporary_containers( $data ) {
512 - if ( empty( $data['elements'] ) || ! is_array( $data['elements'] ) ) {
192 + if ( empty( $data['elements'] ) ) {
513 193 return $data;
514 194 }
515 195
516 196 // If for some reason the document has been saved during an AI Layout session,
@@ -568,25 +248,8 @@
568 248
569 249 return $app->get_remote_config();
570 250 }
571 251
572 - public function ajax_ai_get_remote_frontend_config( $data ) {
573 - $callback = function () use ( $data ) {
574 - return $this->get_ai_app()->get_remote_frontend_config( $data );
575 - };
576 -
577 - return Utils::get_cached_callback( $callback, 'ai_remote_frontend_config-' . get_current_user_id(), HOUR_IN_SECONDS );
578 - }
579 -
580 - public function verify_upload_permissions( $data ) {
581 - $referer = wp_get_referer();
582 -
583 - if ( str_contains( $referer, 'wp-admin/upload.php' ) && current_user_can( 'upload_files' ) ) {
584 - return;
585 - }
586 - $this->verify_permissions( $data['editor_post_id'] );
587 - }
588 -
589 252 private function verify_permissions( $editor_post_id ) {
590 253 $document = Plugin::$instance->documents->get( $editor_post_id );
591 254
592 255 if ( ! $document ) {
@@ -592,19 +255,15 @@
592 255 if ( ! $document ) {
593 256 throw new \Exception( 'Document not found' );
594 257 }
595 258
596 - if ( $document->is_built_with_elementor() ) {
597 - if ( ! $document->is_editable_by_current_user() ) {
598 - throw new \Exception( 'Access denied' );
599 - }
600 - } elseif ( ! current_user_can( 'edit_post', $editor_post_id ) ) {
601 - throw new \Exception( 'Access denied' );
259 + if ( ! $document->is_built_with_elementor() || ! $document->is_editable_by_current_user() ) {
260 + throw new \Exception( 'Access denied' );
602 261 }
603 262 }
604 263
605 264 public function ajax_ai_get_image_prompt_enhancer( $data ) {
606 - $this->verify_upload_permissions( $data );
265 + $this->verify_permissions( $data['editor_post_id'] );
607 266
608 267 $app = $this->get_ai_app();
609 268
610 269 if ( empty( $data['prompt'] ) ) {
@@ -613,12 +272,13 @@
613 272
614 273 if ( ! $app->is_connected() ) {
615 274 throw new \Exception( 'not_connected' );
616 275 }
617 - $request_ids = $this->get_request_ids( $data['payload'] );
618 276
619 - $result = $app->get_image_prompt_enhanced( $data['prompt'], [], $request_ids );
620 - $this->throw_on_error( $result );
277 + $result = $app->get_image_prompt_enhanced( $data['prompt'] );
278 + if ( is_wp_error( $result ) ) {
279 + throw new \Exception( $result->get_error_message() );
280 + }
621 281
622 282 return [
623 283 'text' => $result['text'],
624 284 'response_id' => $result['responseId'],
@@ -630,9 +290,9 @@
630 290 $this->verify_permissions( $data['editor_post_id'] );
631 291
632 292 $app = $this->get_ai_app();
633 293
634 - if ( empty( $data['payload']['prompt'] ) ) {
294 + if ( empty( $data['prompt'] ) ) {
635 295 throw new \Exception( 'Missing prompt' );
636 296 }
637 297
638 298 if ( ! $app->is_connected() ) {
@@ -640,39 +300,13 @@
640 300 }
641 301
642 302 $context = $this->get_request_context( $data );
643 303
644 - $request_ids = $this->get_request_ids( $data['payload'] );
645 -
646 - $result = $app->get_completion_text( $data['payload']['prompt'], $context, $request_ids );
647 - $this->throw_on_error( $result );
648 -
649 - return [
650 - 'text' => $result['text'],
651 - 'response_id' => $result['responseId'],
652 - 'usage' => $result['usage'],
653 - ];
654 - }
655 -
656 -
657 - public function ajax_ai_get_excerpt( $data ): array {
658 - $app = $this->get_ai_app();
659 -
660 - if ( empty( $data['payload']['content'] ) ) {
661 - throw new \Exception( 'Missing content' );
304 + $result = $app->get_completion_text( $data['prompt'], $context );
305 + if ( is_wp_error( $result ) ) {
306 + throw new \Exception( $result->get_error_message() );
662 307 }
663 308
664 - if ( ! $app->is_connected() ) {
665 - throw new \Exception( 'Not connected' );
666 - }
667 -
668 - $context = $this->get_request_context( $data );
669 -
670 - $request_ids = $this->get_request_ids( $data['payload'] );
671 -
672 - $result = $app->get_excerpt( $data['payload']['content'], $context, $request_ids );
673 - $this->throw_on_error( $result );
674 -
675 309 return [
676 310 'text' => $result['text'],
677 311 'response_id' => $result['responseId'],
678 312 'usage' => $result['usage'],
@@ -678,36 +312,9 @@
678 312 'usage' => $result['usage'],
679 313 ];
680 314 }
681 315
682 - public function ajax_ai_get_featured_image( $data ): array {
683 - $this->verify_upload_permissions( $data );
684 -
685 - if ( empty( $data['payload']['prompt'] ) ) {
686 - throw new \Exception( 'Missing prompt' );
687 - }
688 -
689 - $app = $this->get_ai_app();
690 -
691 - if ( ! $app->is_connected() ) {
692 - throw new \Exception( 'not_connected' );
693 - }
694 -
695 - $context = $this->get_request_context( $data );
696 - $request_ids = $this->get_request_ids( $data['payload'] );
697 -
698 - $result = $app->get_featured_image( $data, $context, $request_ids );
699 -
700 - $this->throw_on_error( $result );
701 -
702 - return [
703 - 'images' => $result['images'],
704 - 'response_id' => $result['responseId'],
705 - 'usage' => $result['usage'],
706 - ];
707 - }
708 -
709 - private function get_ai_app(): Ai {
316 + private function get_ai_app() : Ai {
710 317 return Plugin::$instance->common->get_component( 'connect' )->get_app( 'ai' );
711 318 }
712 319
713 320 private function get_request_context( $data ) {
@@ -717,26 +324,18 @@
717 324
718 325 return $data['context'];
719 326 }
720 327
721 - private function get_request_ids( $data ) {
722 - if ( empty( $data['requestIds'] ) ) {
723 - return new \stdClass();
724 - }
725 -
726 - return $data['requestIds'];
727 - }
728 -
729 328 public function ajax_ai_get_edit_text( $data ) {
730 329 $this->verify_permissions( $data['editor_post_id'] );
731 330
732 331 $app = $this->get_ai_app();
733 332
734 - if ( empty( $data['payload']['input'] ) ) {
333 + if ( empty( $data['input'] ) ) {
735 334 throw new \Exception( 'Missing input' );
736 335 }
737 336
738 - if ( empty( $data['payload']['instruction'] ) ) {
337 + if ( empty( $data['instruction'] ) ) {
739 338 throw new \Exception( 'Missing instruction' );
740 339 }
741 340
742 341 if ( ! $app->is_connected() ) {
@@ -744,13 +343,13 @@
744 343 }
745 344
746 345 $context = $this->get_request_context( $data );
747 346
748 - $request_ids = $this->get_request_ids( $data['payload'] );
347 + $result = $app->get_edit_text( $data['input'], $data['instruction'], $context );
348 + if ( is_wp_error( $result ) ) {
349 + throw new \Exception( $result->get_error_message() );
350 + }
749 351
750 - $result = $app->get_edit_text( $data, $context, $request_ids );
751 - $this->throw_on_error( $result );
752 -
753 352 return [
754 353 'text' => $result['text'],
755 354 'response_id' => $result['responseId'],
756 355 'usage' => $result['usage'],
@@ -759,13 +358,13 @@
759 358
760 359 public function ajax_ai_get_custom_code( $data ) {
761 360 $app = $this->get_ai_app();
762 361
763 - if ( empty( $data['payload']['prompt'] ) ) {
362 + if ( empty( $data['prompt'] ) ) {
764 363 throw new \Exception( 'Missing prompt' );
765 364 }
766 365
767 - if ( empty( $data['payload']['language'] ) ) {
366 + if ( empty( $data['language'] ) ) {
768 367 throw new \Exception( 'Missing language' );
769 368 }
770 369
771 370 if ( ! $app->is_connected() ) {
@@ -773,13 +372,13 @@
773 372 }
774 373
775 374 $context = $this->get_request_context( $data );
776 375
777 - $request_ids = $this->get_request_ids( $data['payload'] );
376 + $result = $app->get_custom_code( $data['prompt'], $data['language'], $context );
377 + if ( is_wp_error( $result ) ) {
378 + throw new \Exception( $result->get_error_message() );
379 + }
778 380
779 - $result = $app->get_custom_code( $data, $context, $request_ids );
780 - $this->throw_on_error( $result );
781 -
782 381 return [
783 382 'text' => $result['text'],
784 383 'response_id' => $result['responseId'],
785 384 'usage' => $result['usage'],
@@ -790,17 +389,17 @@
790 389 $this->verify_permissions( $data['editor_post_id'] );
791 390
792 391 $app = $this->get_ai_app();
793 392
794 - if ( empty( $data['payload']['prompt'] ) ) {
393 + if ( empty( $data['prompt'] ) ) {
795 394 throw new \Exception( 'Missing prompt' );
796 395 }
797 396
798 - if ( empty( $data['payload']['html_markup'] ) ) {
397 + if ( empty( $data['html_markup'] ) ) {
799 398 $data['html_markup'] = '';
800 399 }
801 400
802 - if ( empty( $data['payload']['element_id'] ) ) {
401 + if ( empty( $data['element_id'] ) ) {
803 402 throw new \Exception( 'Missing element_id' );
804 403 }
805 404
806 405 if ( ! $app->is_connected() ) {
@@ -807,12 +406,13 @@
807 406 throw new \Exception( 'not_connected' );
808 407 }
809 408
810 409 $context = $this->get_request_context( $data );
811 - $request_ids = $this->get_request_ids( $data['payload'] );
812 410
813 - $result = $app->get_custom_css( $data, $context, $request_ids );
814 - $this->throw_on_error( $result );
411 + $result = $app->get_custom_css( $data['prompt'], $data['html_markup'], $data['element_id'], $context );
412 + if ( is_wp_error( $result ) ) {
413 + throw new \Exception( $result->get_error_message() );
414 + }
815 415
816 416 return [
817 417 'text' => $result['text'],
818 418 'response_id' => $result['responseId'],
@@ -846,11 +446,11 @@
846 446 return [];
847 447 }
848 448
849 449 public function ajax_ai_get_text_to_image( $data ) {
850 - $this->verify_upload_permissions( $data );
450 + $this->verify_permissions( $data['editor_post_id'] );
851 451
852 - if ( empty( $data['payload']['prompt'] ) ) {
452 + if ( empty( $data['prompt'] ) ) {
853 453 throw new \Exception( 'Missing prompt' );
854 454 }
855 455
856 456 $app = $this->get_ai_app();
@@ -859,13 +459,14 @@
859 459 throw new \Exception( 'not_connected' );
860 460 }
861 461
862 462 $context = $this->get_request_context( $data );
863 - $request_ids = $this->get_request_ids( $data['payload'] );
864 463
865 - $result = $app->get_text_to_image( $data, $context, $request_ids );
464 + $result = $app->get_text_to_image( $data['prompt'], $data['promptSettings'], $context );
866 465
867 - $this->throw_on_error( $result );
466 + if ( is_wp_error( $result ) ) {
467 + throw new \Exception( $result->get_error_message() );
468 + }
868 469
869 470 return [
870 471 'images' => $result['images'],
871 472 'response_id' => $result['responseId'],
@@ -873,17 +474,21 @@
873 474 ];
874 475 }
875 476
876 477 public function ajax_ai_get_image_to_image( $data ) {
877 - $this->verify_upload_permissions( $data );
478 + $this->verify_permissions( $data['editor_post_id'] );
878 479
879 480 $app = $this->get_ai_app();
880 481
881 - if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) {
482 + if ( empty( $data['prompt'] ) ) {
483 + throw new \Exception( 'Missing prompt' );
484 + }
485 +
486 + if ( empty( $data['image'] ) || empty( $data['image']['id'] ) ) {
882 487 throw new \Exception( 'Missing Image' );
883 488 }
884 489
885 - if ( empty( $data['payload']['settings'] ) ) {
490 + if ( empty( $data['promptSettings'] ) ) {
886 491 throw new \Exception( 'Missing prompt settings' );
887 492 }
888 493
889 494 if ( ! $app->is_connected() ) {
@@ -890,17 +495,18 @@
890 495 throw new \Exception( 'not_connected' );
891 496 }
892 497
893 498 $context = $this->get_request_context( $data );
894 - $request_ids = $this->get_request_ids( $data['payload'] );
895 499
896 500 $result = $app->get_image_to_image( [
897 - 'prompt' => $data['payload']['prompt'],
898 - 'promptSettings' => $data['payload']['settings'],
899 - 'attachment_id' => $data['payload']['image']['id'],
900 - ], $context, $request_ids );
501 + 'prompt' => $data['prompt'],
502 + 'promptSettings' => $data['promptSettings'],
503 + 'attachment_id' => $data['image']['id'],
504 + ], $context );
901 505
902 - $this->throw_on_error( $result );
506 + if ( is_wp_error( $result ) ) {
507 + throw new \Exception( $result->get_error_message() );
508 + }
903 509
904 510 return [
905 511 'images' => $result['images'],
906 512 'response_id' => $result['responseId'],
@@ -908,17 +514,17 @@
908 514 ];
909 515 }
910 516
911 517 public function ajax_ai_get_image_to_image_upscale( $data ) {
912 - $this->verify_upload_permissions( $data );
518 + $this->verify_permissions( $data['editor_post_id'] );
913 519
914 520 $app = $this->get_ai_app();
915 521
916 - if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) {
522 + if ( empty( $data['image'] ) || empty( $data['image']['id'] ) ) {
917 523 throw new \Exception( 'Missing Image' );
918 524 }
919 525
920 - if ( empty( $data['payload']['promptSettings'] ) ) {
526 + if ( empty( $data['promptSettings'] ) ) {
921 527 throw new \Exception( 'Missing prompt settings' );
922 528 }
923 529
924 530 if ( ! $app->is_connected() ) {
@@ -925,16 +531,17 @@
925 531 throw new \Exception( 'not_connected' );
926 532 }
927 533
928 534 $context = $this->get_request_context( $data );
929 - $request_ids = $this->get_request_ids( $data['payload'] );
930 535
931 536 $result = $app->get_image_to_image_upscale( [
932 - 'promptSettings' => $data['payload']['promptSettings'],
933 - 'attachment_id' => $data['payload']['image']['id'],
934 - ], $context, $request_ids );
537 + 'promptSettings' => $data['promptSettings'],
538 + 'attachment_id' => $data['image']['id'],
539 + ], $context );
935 540
936 - $this->throw_on_error( $result );
541 + if ( is_wp_error( $result ) ) {
542 + throw new \Exception( $result->get_error_message() );
543 + }
937 544
938 545 return [
939 546 'images' => $result['images'],
940 547 'response_id' => $result['responseId'],
@@ -942,17 +549,17 @@
942 549 ];
943 550 }
944 551
945 552 public function ajax_ai_get_image_to_image_replace_background( $data ) {
946 - $this->verify_upload_permissions( $data );
553 + $this->verify_permissions( $data['editor_post_id'] );
947 554
948 555 $app = $this->get_ai_app();
949 556
950 - if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) {
557 + if ( empty( $data['image'] ) || empty( $data['image']['id'] ) ) {
951 558 throw new \Exception( 'Missing Image' );
952 559 }
953 560
954 - if ( empty( $data['payload']['prompt'] ) ) {
561 + if ( empty( $data['prompt'] ) ) {
955 562 throw new \Exception( 'Prompt Missing' );
956 563 }
957 564
958 565 if ( ! $app->is_connected() ) {
@@ -959,16 +566,17 @@
959 566 throw new \Exception( 'not_connected' );
960 567 }
961 568
962 569 $context = $this->get_request_context( $data );
963 - $request_ids = $this->get_request_ids( $data['payload'] );
964 570
965 571 $result = $app->get_image_to_image_replace_background( [
966 - 'attachment_id' => $data['payload']['image']['id'],
967 - 'prompt' => $data['payload']['prompt'],
968 - ], $context, $request_ids );
572 + 'attachment_id' => $data['image']['id'],
573 + 'prompt' => $data['prompt'],
574 + ], $context );
969 575
970 - $this->throw_on_error( $result );
576 + if ( is_wp_error( $result ) ) {
577 + throw new \Exception( $result->get_error_message() );
578 + }
971 579
972 580 return [
973 581 'images' => $result['images'],
974 582 'response_id' => $result['responseId'],
@@ -976,13 +584,13 @@
976 584 ];
977 585 }
978 586
979 587 public function ajax_ai_get_image_to_image_remove_background( $data ) {
980 - $this->verify_upload_permissions( $data );
588 + $this->verify_permissions( $data['editor_post_id'] );
981 589
982 590 $app = $this->get_ai_app();
983 591
984 - if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) {
592 + if ( empty( $data['image'] ) || empty( $data['image']['id'] ) ) {
985 593 throw new \Exception( 'Missing Image' );
986 594 }
987 595
988 596 if ( ! $app->is_connected() ) {
@@ -989,14 +597,16 @@
989 597 throw new \Exception( 'not_connected' );
990 598 }
991 599
992 600 $context = $this->get_request_context( $data );
993 - $request_ids = $this->get_request_ids( $data['payload'] );
601 +
994 602 $result = $app->get_image_to_image_remove_background( [
995 - 'attachment_id' => $data['payload']['image']['id'],
996 - ], $context, $request_ids );
603 + 'attachment_id' => $data['image']['id'],
604 + ], $context );
997 605
998 - $this->throw_on_error( $result );
606 + if ( is_wp_error( $result ) ) {
607 + throw new \Exception( $result->get_error_message() );
608 + }
999 609
1000 610 return [
1001 611 'images' => $result['images'],
1002 612 'response_id' => $result['responseId'],
@@ -1004,75 +614,44 @@
1004 614 ];
1005 615 }
1006 616
1007 617 public function ajax_ai_get_image_to_image_mask( $data ) {
1008 - $this->verify_upload_permissions( $data );
618 + $this->verify_permissions( $data['editor_post_id'] );
1009 619
1010 620 $app = $this->get_ai_app();
1011 621
1012 - if ( empty( $data['payload']['prompt'] ) ) {
622 + if ( empty( $data['prompt'] ) ) {
1013 623 throw new \Exception( 'Missing prompt' );
1014 624 }
1015 625
1016 - if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) {
626 + if ( empty( $data['image'] ) || empty( $data['image']['id'] ) ) {
1017 627 throw new \Exception( 'Missing Image' );
1018 628 }
1019 629
1020 - if ( empty( $data['payload']['settings'] ) ) {
630 + if ( empty( $data['promptSettings'] ) ) {
1021 631 throw new \Exception( 'Missing prompt settings' );
1022 632 }
1023 633
1024 - if ( empty( $data['payload']['mask'] ) ) {
1025 - throw new \Exception( 'Missing Mask' );
1026 - }
1027 -
1028 - $context = $this->get_request_context( $data );
1029 - $request_ids = $this->get_request_ids( $data['payload'] );
1030 -
1031 - $result = $app->get_image_to_image_mask( [
1032 - 'prompt' => $data['payload']['prompt'],
1033 - 'attachment_id' => $data['payload']['image']['id'],
1034 - 'mask' => $data['payload']['mask'],
1035 - ], $context, $request_ids );
1036 -
1037 - $this->throw_on_error( $result );
1038 -
1039 - return [
1040 - 'images' => $result['images'],
1041 - 'response_id' => $result['responseId'],
1042 - 'usage' => $result['usage'],
1043 - ];
1044 - }
1045 - public function ajax_ai_get_image_to_image_mask_cleanup( $data ) {
1046 - $this->verify_upload_permissions( $data );
1047 -
1048 - $app = $this->get_ai_app();
1049 -
1050 - if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) {
1051 - throw new \Exception( 'Missing Image' );
1052 - }
1053 -
1054 - if ( empty( $data['payload']['settings'] ) ) {
1055 - throw new \Exception( 'Missing prompt settings' );
1056 - }
1057 -
1058 634 if ( ! $app->is_connected() ) {
1059 635 throw new \Exception( 'not_connected' );
1060 636 }
1061 637
1062 - if ( empty( $data['payload']['mask'] ) ) {
638 + if ( empty( $data['mask'] ) ) {
1063 639 throw new \Exception( 'Missing Mask' );
1064 640 }
1065 641
1066 642 $context = $this->get_request_context( $data );
1067 - $request_ids = $this->get_request_ids( $data['payload'] );
1068 643
1069 - $result = $app->get_image_to_image_mask_cleanup( [
1070 - 'attachment_id' => $data['payload']['image']['id'],
1071 - 'mask' => $data['payload']['mask'],
1072 - ], $context, $request_ids );
644 + $result = $app->get_image_to_image_mask( [
645 + 'prompt' => $data['prompt'],
646 + 'promptSettings' => $data['promptSettings'],
647 + 'attachment_id' => $data['image']['id'],
648 + 'mask' => $data['mask'],
649 + ], $context );
1073 650
1074 - $this->throw_on_error( $result );
651 + if ( is_wp_error( $result ) ) {
652 + throw new \Exception( $result->get_error_message() );
653 + }
1075 654
1076 655 return [
1077 656 'images' => $result['images'],
1078 657 'response_id' => $result['responseId'],
@@ -1078,32 +657,35 @@
1078 657 'response_id' => $result['responseId'],
1079 658 'usage' => $result['usage'],
1080 659 ];
1081 660 }
1082 -
1083 661 public function ajax_ai_get_image_to_image_outpainting( $data ) {
1084 - $this->verify_upload_permissions( $data );
662 + $this->verify_permissions( $data['editor_post_id'] );
1085 663
1086 664 $app = $this->get_ai_app();
1087 665
666 + if ( empty( $data['prompt'] ) ) {
667 + throw new \Exception( 'Missing prompt' );
668 + }
669 +
1088 670 if ( ! $app->is_connected() ) {
1089 671 throw new \Exception( 'not_connected' );
1090 672 }
1091 673
1092 - if ( empty( $data['payload']['mask'] ) ) {
674 + if ( empty( $data['mask'] ) ) {
1093 675 throw new \Exception( 'Missing Expended Image' );
1094 676 }
1095 677
1096 678 $context = $this->get_request_context( $data );
1097 - $request_ids = $this->get_request_ids( $data['payload'] );
679 +
1098 680 $result = $app->get_image_to_image_out_painting( [
1099 - 'size' => $data['payload']['size'],
1100 - 'position' => $data['payload']['position'],
1101 - 'mask' => $data['payload']['mask'],
1102 - 'image_base64' => $data['payload']['image_base64'],
1103 - ], $context, $request_ids );
681 + 'prompt' => $data['prompt'],
682 + 'mask' => $data['mask'],
683 + ], $context );
1104 684
1105 - $this->throw_on_error( $result );
685 + if ( is_wp_error( $result ) ) {
686 + throw new \Exception( $result->get_error_message() );
687 + }
1106 688
1107 689 return [
1108 690 'images' => $result['images'],
1109 691 'response_id' => $result['responseId'],
@@ -1111,10 +693,8 @@
1111 693 ];
1112 694 }
1113 695
1114 696 public function ajax_ai_upload_image( $data ) {
1115 - $this->verify_upload_permissions( $data );
1116 -
1117 697 if ( empty( $data['image'] ) ) {
1118 698 throw new \Exception( 'Missing image data' );
1119 699 }
1120 700
@@ -1126,14 +706,14 @@
1126 706
1127 707 $image_data = $this->upload_image( $image['image_url'], $data['prompt'], $data['editor_post_id'] );
1128 708
1129 709 if ( is_wp_error( $image_data ) ) {
1130 - throw new \Exception( esc_html( $image_data->get_error_message() ) );
710 + throw new \Exception( $image_data->get_error_message() );
1131 711 }
1132 712
1133 713 if ( ! empty( $image['use_gallery_image'] ) && ! empty( $image['id'] ) ) {
1134 - $app = $this->get_ai_app();
1135 - $app->set_used_gallery_image( $image['id'] );
714 + $app = $this->get_ai_app();
715 + $app->set_used_gallery_image( $image['id'] );
1136 716 }
1137 717
1138 718 return [
1139 719 'image' => array_merge( $image_data, $data ),
@@ -1154,9 +734,9 @@
1154 734 }
1155 735
1156 736 $result = $app->generate_layout(
1157 737 $data,
1158 - $this->prepare_generate_layout_context( $data )
738 + $this->prepare_generate_layout_context()
1159 739 );
1160 740
1161 741 if ( is_wp_error( $result ) ) {
1162 742 $message = $result->get_error_message();
@@ -1162,12 +742,11 @@
1162 742 $message = $result->get_error_message();
1163 743
1164 744 if ( is_array( $message ) ) {
1165 745 $message = implode( ', ', $message );
1166 - throw new \Exception( esc_html( $message ) );
1167 746 }
1168 747
1169 - $this->throw_on_error( $result );
748 + throw new \Exception( $message );
1170 749 }
1171 750
1172 751 $elements = $result['text']['elements'] ?? [];
1173 752 $base_template_id = $result['baseTemplateId'] ?? null;
@@ -1227,12 +806,14 @@
1227 806
1228 807 $result = $app->get_layout_prompt_enhanced(
1229 808 $data['prompt'],
1230 809 $data['enhance_type'],
1231 - $this->prepare_generate_layout_context( $data )
810 + $this->prepare_generate_layout_context()
1232 811 );
1233 812
1234 - $this->throw_on_error( $result );
813 + if ( is_wp_error( $result ) ) {
814 + throw new \Exception( $result->get_error_message() );
815 + }
1235 816
1236 817 return [
1237 818 'text' => $result['text'] ?? $data['prompt'],
1238 819 'response_id' => $result['responseId'] ?? '',
@@ -1239,14 +820,13 @@
1239 820 'usage' => $result['usage'] ?? '',
1240 821 ];
1241 822 }
1242 823
1243 - private function prepare_generate_layout_context( $data ) {
1244 - $request_context = $this->get_request_context( $data );
824 + private function prepare_generate_layout_context() {
1245 825 $kit = Plugin::$instance->kits_manager->get_active_kit();
1246 826
1247 827 if ( ! $kit ) {
1248 - return $request_context;
828 + return [];
1249 829 }
1250 830
1251 831 $kits_data = Collection::make( $kit->get_data()['settings'] ?? [] );
1252 832
@@ -1299,14 +879,14 @@
1299 879 ],
1300 880 ];
1301 881 } );
1302 882
1303 - $request_context['globals'] = [
1304 - 'colors' => $colors->all(),
1305 - 'typography' => $typography->all(),
883 + return [
884 + 'globals' => [
885 + 'colors' => $colors->all(),
886 + 'typography' => $typography->all(),
887 + ],
1306 888 ];
1307 -
1308 - return $request_context;
1309 889 }
1310 890
1311 891 private function upload_image( $image_url, $image_title, $parent_post_id = 0 ) {
1312 892 if ( ! current_user_can( 'upload_files' ) ) {
@@ -1312,24 +892,10 @@
1312 892 if ( ! current_user_can( 'upload_files' ) ) {
1313 893 throw new \Exception( 'Not Allowed to Upload images' );
1314 894 }
1315 895
1316 - $uploads_manager = new \Elementor\Core\Files\Uploads_Manager();
1317 - if ( $uploads_manager::are_unfiltered_uploads_enabled() ) {
1318 - Plugin::$instance->uploads_manager->set_elementor_upload_state( true );
1319 - add_filter( 'wp_handle_sideload_prefilter', [ Plugin::$instance->uploads_manager, 'handle_elementor_upload' ] );
1320 - add_filter( 'image_sideload_extensions', function( $extensions ) {
1321 - $extensions[] = 'svg';
1322 - return $extensions;
1323 - });
1324 - }
1325 -
1326 896 $attachment_id = media_sideload_image( $image_url, $parent_post_id, $image_title, 'id' );
1327 897
1328 - if ( is_wp_error( $attachment_id ) ) {
1329 - return new \WP_Error( 'upload_error', $attachment_id->get_error_message() );
1330 - }
1331 -
1332 898 if ( ! empty( $attachment_id['error'] ) ) {
1333 899 return new \WP_Error( 'upload_error', $attachment_id['error'] );
1334 900 }
1335 901
@@ -1334,10 +900,10 @@
1334 900 }
1335 901
1336 902 return [
1337 903 'id' => $attachment_id,
1338 - 'url' => esc_url( wp_get_attachment_image_url( $attachment_id, 'full' ) ),
1339 - 'alt' => esc_attr( $image_title ),
904 + 'url' => wp_get_attachment_image_url( $attachment_id, 'full' ),
905 + 'alt' => $image_title,
1340 906 'source' => 'library',
1341 907 ];
1342 908 }
1343 909
@@ -1361,9 +927,9 @@
1361 927
1362 928 $result = $app->get_history_by_type( $type, $page, $limit, $context );
1363 929
1364 930 if ( is_wp_error( $result ) ) {
1365 - throw new \Exception( esc_html( $result->get_error_message() ) );
931 + throw new \Exception( $result->get_error_message() );
1366 932 }
1367 933
1368 934 return $result;
1369 935 }
@@ -1383,9 +949,9 @@
1383 949
1384 950 $result = $app->delete_history_item( $data['id'], $context );
1385 951
1386 952 if ( is_wp_error( $result ) ) {
1387 - throw new \Exception( esc_html( $result->get_error_message() ) );
953 + throw new \Exception( $result->get_error_message() );
1388 954 }
1389 955
1390 956 return [];
1391 957 }
@@ -1405,193 +971,10 @@
1405 971
1406 972 $result = $app->toggle_favorite_history_item( $data['id'], $context );
1407 973
1408 974 if ( is_wp_error( $result ) ) {
1409 - throw new \Exception( esc_html( $result->get_error_message() ) );
975 + throw new \Exception( $result->get_error_message() );
1410 976 }
1411 977
1412 978 return [];
1413 - }
1414 -
1415 - public function ajax_ai_get_product_image_unification( $data ): array {
1416 - if ( ! empty( $data['payload']['postId'] ) ) {
1417 - $data['editor_post_id'] = $data['payload']['postId'];
1418 - }
1419 - $this->verify_upload_permissions( $data );
1420 -
1421 - $app = $this->get_ai_app();
1422 -
1423 - if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) {
1424 - throw new \Exception( 'Missing Image' );
1425 - }
1426 -
1427 - if ( empty( $data['payload']['settings'] ) ) {
1428 - throw new \Exception( 'Missing prompt settings' );
1429 - }
1430 -
1431 - if ( ! $app->is_connected() ) {
1432 - throw new \Exception( 'not_connected' );
1433 - }
1434 -
1435 - $context = $this->get_request_context( $data );
1436 - $request_ids = $this->get_request_ids( $data['payload'] );
1437 -
1438 - $result = $app->get_unify_product_images( [
1439 - 'promptSettings' => $data['payload']['settings'],
1440 - 'attachment_id' => $data['payload']['image']['id'],
1441 - 'featureIdentifier' => $data['payload']['featureIdentifier'] ?? '',
1442 - ], $context, $request_ids );
1443 -
1444 - $this->throw_on_error( $result );
1445 -
1446 - return [
1447 - 'images' => $result['images'],
1448 - 'response_id' => $result['responseId'],
1449 - 'usage' => $result['usage'],
1450 - ];
1451 - }
1452 -
1453 - public function ajax_ai_get_animation( $data ): array {
1454 - $this->verify_upload_permissions( $data );
1455 -
1456 - $app = $this->get_ai_app();
1457 -
1458 - if ( empty( $data['payload']['prompt'] ) ) {
1459 - throw new \Exception( 'Missing prompt' );
1460 - }
1461 -
1462 - if ( empty( $data['payload']['motionEffectType'] ) ) {
1463 - throw new \Exception( 'Missing animation type' );
1464 - }
1465 -
1466 - if ( ! $app->is_connected() ) {
1467 - throw new \Exception( 'not_connected' );
1468 - }
1469 -
1470 - $context = $this->get_request_context( $data );
1471 -
1472 - $request_ids = $this->get_request_ids( $data['payload'] );
1473 -
1474 - $result = $app->get_animation( $data, $context, $request_ids );
1475 - $this->throw_on_error( $result );
1476 -
1477 - return [
1478 - 'text' => $result['text'],
1479 - 'response_id' => $result['responseId'],
1480 - 'usage' => $result['usage'],
1481 - ];
1482 - }
1483 -
1484 - /**
1485 - * @param mixed $result
1486 - */
1487 - private function throw_on_error( $result ): void {
1488 - if ( is_wp_error( $result ) ) {
1489 - wp_send_json_error( [
1490 - 'message' => esc_html( $result->get_error_message() ),
1491 - 'extra_data' => $result->get_error_data(),
1492 - ] );
1493 - }
1494 - }
1495 -
1496 - /**
1497 - * @return void
1498 - */
1499 - public function add_wc_scripts(): void {
1500 - wp_enqueue_script( 'elementor-ai-unify-product-images',
1501 - $this->get_js_assets_url( 'ai-unify-product-images' ),
1502 - [
1503 - 'jquery',
1504 - 'elementor-v2-ui',
1505 - 'elementor-v2-icons',
1506 - 'wp-components',
1507 - 'elementor-common',
1508 - ],
1509 - ELEMENTOR_VERSION,
1510 - true
1511 - );
1512 -
1513 - wp_localize_script(
1514 - 'elementor-ai-unify-product-images',
1515 - 'UnifyProductImagesConfig',
1516 - [
1517 - 'get_product_images_url' => admin_url( 'admin-ajax.php' ),
1518 - 'set_product_images_url' => admin_url( 'admin-ajax.php' ),
1519 - 'nonce' => wp_create_nonce( 'elementor-ai-unify-product-images_nonce' ),
1520 - 'placeholder' => ELEMENTOR_ASSETS_URL . 'images/app/ai/product-image-unification-example.gif?' . ELEMENTOR_VERSION,
1521 - 'is_get_started' => User::get_introduction_meta( 'ai_get_started' ),
1522 - 'connect_url' => $this->get_ai_connect_url(),
1523 - ]
1524 - );
1525 -
1526 - add_filter( 'bulk_actions-edit-product', function ( $data ) {
1527 - return $this->add_products_bulk_action( $data );
1528 - });
1529 -
1530 - wp_set_script_translations( 'elementor-ai-unify-product-images', 'elementor' );
1531 - }
1532 -
1533 - /**
1534 - * @param $product
1535 - * @param int|null $image_to_remove
1536 - * @param int|null $image_to_add
1537 - * @return void
1538 - */
1539 - private function update_product_gallery( $product, ?int $image_to_remove, ?int $image_to_add ): void {
1540 - $gallery_image_ids = $product->get_gallery_image_ids();
1541 -
1542 - $index = array_search( $image_to_remove, $gallery_image_ids, true );
1543 - if ( false !== $index ) {
1544 - unset( $gallery_image_ids[ $index ] );
1545 - }
1546 -
1547 - if ( ! in_array( $image_to_add, $gallery_image_ids, true ) ) {
1548 - $gallery_image_ids[] = $image_to_add;
1549 - }
1550 -
1551 - $product->set_gallery_image_ids( $gallery_image_ids );
1552 - $product->save();
1553 - }
1554 -
1555 - private function should_display_create_with_ai_banner() {
1556 - $elementor_pages = new \WP_Query( [
1557 - 'post_type' => 'page',
1558 - 'post_status' => 'publish',
1559 - 'fields' => 'ids',
1560 - 'posts_per_page' => self::MIN_PAGES_FOR_CREATE_WITH_AI_BANNER + 1,
1561 - ] );
1562 -
1563 - if ( $elementor_pages->post_count > self::MIN_PAGES_FOR_CREATE_WITH_AI_BANNER ) {
1564 - return false;
1565 - }
1566 -
1567 - if ( Utils::is_custom_kit_applied() ) {
1568 - return false;
1569 - }
1570 -
1571 - return true;
1572 - }
1573 -
1574 - private function get_create_with_ai_banner_data() {
1575 - return [
1576 - 'title' => 'Create and launch your site faster with AI',
1577 - 'description' => 'Share your vision with our AI Chat and watch as it becomes a brief, sitemap, and wireframes in minutes:',
1578 - 'input_placeholder' => 'Start describing the site you want to create...',
1579 - 'button_title' => 'Create with AI',
1580 - 'button_cta_url' => 'http://planner.elementor.com/chat.html',
1581 - 'background_image' => ELEMENTOR_ASSETS_URL . 'images/app/ai/ai-site-creator-homepage-bg.svg',
1582 - 'utm_source' => 'editor-home',
1583 - 'utm_medium' => 'wp-dash',
1584 - 'utm_campaign' => 'generate-with-ai',
1585 - ];
1586 - }
1587 -
1588 - public function add_create_with_ai_banner_to_homescreen( $home_screen_data ) {
1589 - if ( $this->should_display_create_with_ai_banner() ) {
1590 - $home_screen_data['create_with_ai'] = $this->get_create_with_ai_banner_data();
1591 - } else {
1592 - $home_screen_data['create_with_ai'] = null;
1593 - }
1594 -
1595 - return $home_screen_data;
1596 979 }
1597 980 }