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