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-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 +188 -781 4.0.73.19.2 View file →
@@ -1,15 +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\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 11 use Elementor\Utils;
14 12
15 13 if ( ! defined( 'ABSPATH' ) ) {
@@ -28,10 +26,11 @@
28 26 self::HISTORY_TYPE_CODE,
29 27 self::HISTORY_TYPE_IMAGE,
30 28 self::HISTORY_TYPE_BLOCK,
31 29 ];
32 - const MIN_PAGES_FOR_CREATE_WITH_AI_BANNER = 10;
33 30
31 + const LAYOUT_EXPERIMENT = 'ai-layout';
32 +
34 33 public function get_name() {
35 34 return 'ai';
36 35 }
37 36
@@ -37,21 +36,10 @@
37 36
38 37 public function __construct() {
39 38 parent::__construct();
40 39
41 - ( new SitePlannerConnect\Module() );
40 + $this->register_layout_experiment();
42 41
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 42 add_action( 'elementor/connect/apps/register', function ( ConnectModule $connect_module ) {
55 43 $connect_module->register_app( 'ai', Ai::get_class_name() );
56 44 } );
57 45
@@ -58,12 +46,9 @@
58 46 add_action( 'elementor/ajax/register_actions', function( $ajax ) {
59 47 $handlers = [
60 48 'ai_get_user_information' => [ $this, 'ajax_ai_get_user_information' ],
61 49 'ai_get_remote_config' => [ $this, 'ajax_ai_get_remote_config' ],
62 - 'ai_get_remote_frontend_config' => [ $this, 'ajax_ai_get_remote_frontend_config' ],
63 50 '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 51 'ai_get_edit_text' => [ $this, 'ajax_ai_get_edit_text' ],
67 52 'ai_get_custom_code' => [ $this, 'ajax_ai_get_custom_code' ],
68 53 'ai_get_custom_css' => [ $this, 'ajax_ai_get_custom_css' ],
69 54 'ai_set_get_started' => [ $this, 'ajax_ai_set_get_started' ],
@@ -71,9 +56,8 @@
71 56 'ai_get_image_prompt_enhancer' => [ $this, 'ajax_ai_get_image_prompt_enhancer' ],
72 57 'ai_get_text_to_image' => [ $this, 'ajax_ai_get_text_to_image' ],
73 58 'ai_get_image_to_image' => [ $this, 'ajax_ai_get_image_to_image' ],
74 59 '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 60 'ai_get_image_to_image_outpainting' => [ $this, 'ajax_ai_get_image_to_image_outpainting' ],
77 61 'ai_get_image_to_image_upscale' => [ $this, 'ajax_ai_get_image_to_image_upscale' ],
78 62 'ai_get_image_to_image_remove_background' => [ $this, 'ajax_ai_get_image_to_image_remove_background' ],
79 63 'ai_get_image_to_image_replace_background' => [ $this, 'ajax_ai_get_image_to_image_replace_background' ],
@@ -82,11 +66,8 @@
82 66 'ai_get_layout_prompt_enhancer' => [ $this, 'ajax_ai_get_layout_prompt_enhancer' ],
83 67 'ai_get_history' => [ $this, 'ajax_ai_get_history' ],
84 68 'ai_delete_history_item' => [ $this, 'ajax_ai_delete_history_item' ],
85 69 '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 70 ];
90 71
91 72 foreach ( $handlers as $tag => $callback ) {
92 73 $ajax->register_ajax_action( $tag, $callback );
@@ -94,9 +75,12 @@
94 75 } );
95 76
96 77 add_action( 'elementor/editor/before_enqueue_scripts', function() {
97 78 $this->enqueue_main_script();
98 - $this->enqueue_layout_script();
79 +
80 + if ( $this->is_layout_active() ) {
81 + $this->enqueue_layout_script();
82 + }
99 83 } );
100 84
101 85 add_action( 'elementor/editor/after_enqueue_styles', function() {
102 86 wp_enqueue_style(
@@ -107,352 +91,40 @@
107 91 );
108 92 } );
109 93
110 94 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 - );
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 + }
117 103 } );
118 104
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();
105 + add_filter( 'elementor/document/save/data', function ( $data ) {
106 + if ( $this->is_layout_active() ) {
107 + return $this->remove_temporary_containers( $data );
129 108 }
130 - }
131 109
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 );
110 + return $data;
165 111 } );
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 112 }
172 113
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'],
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',
214 123 ],
215 124 ] );
216 125 }
217 126
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 127 private function enqueue_main_script() {
456 128 wp_enqueue_script(
457 129 'elementor-ai',
458 130 $this->get_js_assets_url( 'ai' ),
@@ -476,8 +148,13 @@
476 148 'is_get_started' => User::get_introduction_meta( 'ai_get_started' ),
477 149 'connect_url' => $this->get_ai_connect_url(),
478 150 ];
479 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 +
480 157 wp_localize_script(
481 158 'elementor-ai',
482 159 'ElementorAiConfig',
483 160 $config
@@ -483,8 +160,31 @@
483 160 $config
484 161 );
485 162
486 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 + }
487 187 }
488 188
489 189 private function enqueue_layout_script() {
490 190 wp_enqueue_script(
@@ -507,10 +207,14 @@
507 207
508 208 wp_set_script_translations( 'elementor-ai-layout', 'elementor' );
509 209 }
510 210
211 + private function is_layout_active() {
212 + return Plugin::$instance->experiments->is_feature_active( self::LAYOUT_EXPERIMENT );
213 + }
214 +
511 215 private function remove_temporary_containers( $data ) {
512 - if ( empty( $data['elements'] ) || ! is_array( $data['elements'] ) ) {
216 + if ( empty( $data['elements'] ) ) {
513 217 return $data;
514 218 }
515 219
516 220 // If for some reason the document has been saved during an AI Layout session,
@@ -568,25 +272,8 @@
568 272
569 273 return $app->get_remote_config();
570 274 }
571 275
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 276 private function verify_permissions( $editor_post_id ) {
590 277 $document = Plugin::$instance->documents->get( $editor_post_id );
591 278
592 279 if ( ! $document ) {
@@ -592,19 +279,15 @@
592 279 if ( ! $document ) {
593 280 throw new \Exception( 'Document not found' );
594 281 }
595 282
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' );
283 + if ( ! $document->is_built_with_elementor() || ! $document->is_editable_by_current_user() ) {
284 + throw new \Exception( 'Access denied' );
602 285 }
603 286 }
604 287
605 288 public function ajax_ai_get_image_prompt_enhancer( $data ) {
606 - $this->verify_upload_permissions( $data );
289 + $this->verify_permissions( $data['editor_post_id'] );
607 290
608 291 $app = $this->get_ai_app();
609 292
610 293 if ( empty( $data['prompt'] ) ) {
@@ -613,12 +296,13 @@
613 296
614 297 if ( ! $app->is_connected() ) {
615 298 throw new \Exception( 'not_connected' );
616 299 }
617 - $request_ids = $this->get_request_ids( $data['payload'] );
618 300
619 - $result = $app->get_image_prompt_enhanced( $data['prompt'], [], $request_ids );
620 - $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 + }
621 305
622 306 return [
623 307 'text' => $result['text'],
624 308 'response_id' => $result['responseId'],
@@ -630,9 +314,9 @@
630 314 $this->verify_permissions( $data['editor_post_id'] );
631 315
632 316 $app = $this->get_ai_app();
633 317
634 - if ( empty( $data['payload']['prompt'] ) ) {
318 + if ( empty( $data['prompt'] ) ) {
635 319 throw new \Exception( 'Missing prompt' );
636 320 }
637 321
638 322 if ( ! $app->is_connected() ) {
@@ -640,39 +324,13 @@
640 324 }
641 325
642 326 $context = $this->get_request_context( $data );
643 327
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' );
328 + $result = $app->get_completion_text( $data['prompt'], $context );
329 + if ( is_wp_error( $result ) ) {
330 + throw new \Exception( $result->get_error_message() );
662 331 }
663 332
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 333 return [
676 334 'text' => $result['text'],
677 335 'response_id' => $result['responseId'],
678 336 'usage' => $result['usage'],
@@ -678,36 +336,9 @@
678 336 'usage' => $result['usage'],
679 337 ];
680 338 }
681 339
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 {
340 + private function get_ai_app() : Ai {
710 341 return Plugin::$instance->common->get_component( 'connect' )->get_app( 'ai' );
711 342 }
712 343
713 344 private function get_request_context( $data ) {
@@ -717,26 +348,18 @@
717 348
718 349 return $data['context'];
719 350 }
720 351
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 352 public function ajax_ai_get_edit_text( $data ) {
730 353 $this->verify_permissions( $data['editor_post_id'] );
731 354
732 355 $app = $this->get_ai_app();
733 356
734 - if ( empty( $data['payload']['input'] ) ) {
357 + if ( empty( $data['input'] ) ) {
735 358 throw new \Exception( 'Missing input' );
736 359 }
737 360
738 - if ( empty( $data['payload']['instruction'] ) ) {
361 + if ( empty( $data['instruction'] ) ) {
739 362 throw new \Exception( 'Missing instruction' );
740 363 }
741 364
742 365 if ( ! $app->is_connected() ) {
@@ -744,13 +367,13 @@
744 367 }
745 368
746 369 $context = $this->get_request_context( $data );
747 370
748 - $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 + }
749 375
750 - $result = $app->get_edit_text( $data, $context, $request_ids );
751 - $this->throw_on_error( $result );
752 -
753 376 return [
754 377 'text' => $result['text'],
755 378 'response_id' => $result['responseId'],
756 379 'usage' => $result['usage'],
@@ -759,13 +382,13 @@
759 382
760 383 public function ajax_ai_get_custom_code( $data ) {
761 384 $app = $this->get_ai_app();
762 385
763 - if ( empty( $data['payload']['prompt'] ) ) {
386 + if ( empty( $data['prompt'] ) ) {
764 387 throw new \Exception( 'Missing prompt' );
765 388 }
766 389
767 - if ( empty( $data['payload']['language'] ) ) {
390 + if ( empty( $data['language'] ) ) {
768 391 throw new \Exception( 'Missing language' );
769 392 }
770 393
771 394 if ( ! $app->is_connected() ) {
@@ -773,13 +396,13 @@
773 396 }
774 397
775 398 $context = $this->get_request_context( $data );
776 399
777 - $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 + }
778 404
779 - $result = $app->get_custom_code( $data, $context, $request_ids );
780 - $this->throw_on_error( $result );
781 -
782 405 return [
783 406 'text' => $result['text'],
784 407 'response_id' => $result['responseId'],
785 408 'usage' => $result['usage'],
@@ -790,17 +413,17 @@
790 413 $this->verify_permissions( $data['editor_post_id'] );
791 414
792 415 $app = $this->get_ai_app();
793 416
794 - if ( empty( $data['payload']['prompt'] ) ) {
417 + if ( empty( $data['prompt'] ) ) {
795 418 throw new \Exception( 'Missing prompt' );
796 419 }
797 420
798 - if ( empty( $data['payload']['html_markup'] ) ) {
421 + if ( empty( $data['html_markup'] ) ) {
799 422 $data['html_markup'] = '';
800 423 }
801 424
802 - if ( empty( $data['payload']['element_id'] ) ) {
425 + if ( empty( $data['element_id'] ) ) {
803 426 throw new \Exception( 'Missing element_id' );
804 427 }
805 428
806 429 if ( ! $app->is_connected() ) {
@@ -807,12 +430,13 @@
807 430 throw new \Exception( 'not_connected' );
808 431 }
809 432
810 433 $context = $this->get_request_context( $data );
811 - $request_ids = $this->get_request_ids( $data['payload'] );
812 434
813 - $result = $app->get_custom_css( $data, $context, $request_ids );
814 - $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 + }
815 439
816 440 return [
817 441 'text' => $result['text'],
818 442 'response_id' => $result['responseId'],
@@ -846,11 +470,11 @@
846 470 return [];
847 471 }
848 472
849 473 public function ajax_ai_get_text_to_image( $data ) {
850 - $this->verify_upload_permissions( $data );
474 + $this->verify_permissions( $data['editor_post_id'] );
851 475
852 - if ( empty( $data['payload']['prompt'] ) ) {
476 + if ( empty( $data['prompt'] ) ) {
853 477 throw new \Exception( 'Missing prompt' );
854 478 }
855 479
856 480 $app = $this->get_ai_app();
@@ -859,13 +483,14 @@
859 483 throw new \Exception( 'not_connected' );
860 484 }
861 485
862 486 $context = $this->get_request_context( $data );
863 - $request_ids = $this->get_request_ids( $data['payload'] );
864 487
865 - $result = $app->get_text_to_image( $data, $context, $request_ids );
488 + $result = $app->get_text_to_image( $data['prompt'], $data['promptSettings'], $context );
866 489
867 - $this->throw_on_error( $result );
490 + if ( is_wp_error( $result ) ) {
491 + throw new \Exception( $result->get_error_message() );
492 + }
868 493
869 494 return [
870 495 'images' => $result['images'],
871 496 'response_id' => $result['responseId'],
@@ -873,17 +498,21 @@
873 498 ];
874 499 }
875 500
876 501 public function ajax_ai_get_image_to_image( $data ) {
877 - $this->verify_upload_permissions( $data );
502 + $this->verify_permissions( $data['editor_post_id'] );
878 503
879 504 $app = $this->get_ai_app();
880 505
881 - 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'] ) ) {
882 511 throw new \Exception( 'Missing Image' );
883 512 }
884 513
885 - if ( empty( $data['payload']['settings'] ) ) {
514 + if ( empty( $data['promptSettings'] ) ) {
886 515 throw new \Exception( 'Missing prompt settings' );
887 516 }
888 517
889 518 if ( ! $app->is_connected() ) {
@@ -890,17 +519,18 @@
890 519 throw new \Exception( 'not_connected' );
891 520 }
892 521
893 522 $context = $this->get_request_context( $data );
894 - $request_ids = $this->get_request_ids( $data['payload'] );
895 523
896 524 $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 );
525 + 'prompt' => $data['prompt'],
526 + 'promptSettings' => $data['promptSettings'],
527 + 'attachment_id' => $data['image']['id'],
528 + ], $context );
901 529
902 - $this->throw_on_error( $result );
530 + if ( is_wp_error( $result ) ) {
531 + throw new \Exception( $result->get_error_message() );
532 + }
903 533
904 534 return [
905 535 'images' => $result['images'],
906 536 'response_id' => $result['responseId'],
@@ -908,17 +538,17 @@
908 538 ];
909 539 }
910 540
911 541 public function ajax_ai_get_image_to_image_upscale( $data ) {
912 - $this->verify_upload_permissions( $data );
542 + $this->verify_permissions( $data['editor_post_id'] );
913 543
914 544 $app = $this->get_ai_app();
915 545
916 - if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) {
546 + if ( empty( $data['image'] ) || empty( $data['image']['id'] ) ) {
917 547 throw new \Exception( 'Missing Image' );
918 548 }
919 549
920 - if ( empty( $data['payload']['promptSettings'] ) ) {
550 + if ( empty( $data['promptSettings'] ) ) {
921 551 throw new \Exception( 'Missing prompt settings' );
922 552 }
923 553
924 554 if ( ! $app->is_connected() ) {
@@ -925,16 +555,17 @@
925 555 throw new \Exception( 'not_connected' );
926 556 }
927 557
928 558 $context = $this->get_request_context( $data );
929 - $request_ids = $this->get_request_ids( $data['payload'] );
930 559
931 560 $result = $app->get_image_to_image_upscale( [
932 - 'promptSettings' => $data['payload']['promptSettings'],
933 - 'attachment_id' => $data['payload']['image']['id'],
934 - ], $context, $request_ids );
561 + 'promptSettings' => $data['promptSettings'],
562 + 'attachment_id' => $data['image']['id'],
563 + ], $context );
935 564
936 - $this->throw_on_error( $result );
565 + if ( is_wp_error( $result ) ) {
566 + throw new \Exception( $result->get_error_message() );
567 + }
937 568
938 569 return [
939 570 'images' => $result['images'],
940 571 'response_id' => $result['responseId'],
@@ -942,17 +573,17 @@
942 573 ];
943 574 }
944 575
945 576 public function ajax_ai_get_image_to_image_replace_background( $data ) {
946 - $this->verify_upload_permissions( $data );
577 + $this->verify_permissions( $data['editor_post_id'] );
947 578
948 579 $app = $this->get_ai_app();
949 580
950 - if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) {
581 + if ( empty( $data['image'] ) || empty( $data['image']['id'] ) ) {
951 582 throw new \Exception( 'Missing Image' );
952 583 }
953 584
954 - if ( empty( $data['payload']['prompt'] ) ) {
585 + if ( empty( $data['prompt'] ) ) {
955 586 throw new \Exception( 'Prompt Missing' );
956 587 }
957 588
958 589 if ( ! $app->is_connected() ) {
@@ -959,16 +590,17 @@
959 590 throw new \Exception( 'not_connected' );
960 591 }
961 592
962 593 $context = $this->get_request_context( $data );
963 - $request_ids = $this->get_request_ids( $data['payload'] );
964 594
965 595 $result = $app->get_image_to_image_replace_background( [
966 - 'attachment_id' => $data['payload']['image']['id'],
967 - 'prompt' => $data['payload']['prompt'],
968 - ], $context, $request_ids );
596 + 'attachment_id' => $data['image']['id'],
597 + 'prompt' => $data['prompt'],
598 + ], $context );
969 599
970 - $this->throw_on_error( $result );
600 + if ( is_wp_error( $result ) ) {
601 + throw new \Exception( $result->get_error_message() );
602 + }
971 603
972 604 return [
973 605 'images' => $result['images'],
974 606 'response_id' => $result['responseId'],
@@ -976,13 +608,13 @@
976 608 ];
977 609 }
978 610
979 611 public function ajax_ai_get_image_to_image_remove_background( $data ) {
980 - $this->verify_upload_permissions( $data );
612 + $this->verify_permissions( $data['editor_post_id'] );
981 613
982 614 $app = $this->get_ai_app();
983 615
984 - if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) {
616 + if ( empty( $data['image'] ) || empty( $data['image']['id'] ) ) {
985 617 throw new \Exception( 'Missing Image' );
986 618 }
987 619
988 620 if ( ! $app->is_connected() ) {
@@ -989,14 +621,16 @@
989 621 throw new \Exception( 'not_connected' );
990 622 }
991 623
992 624 $context = $this->get_request_context( $data );
993 - $request_ids = $this->get_request_ids( $data['payload'] );
625 +
994 626 $result = $app->get_image_to_image_remove_background( [
995 - 'attachment_id' => $data['payload']['image']['id'],
996 - ], $context, $request_ids );
627 + 'attachment_id' => $data['image']['id'],
628 + ], $context );
997 629
998 - $this->throw_on_error( $result );
630 + if ( is_wp_error( $result ) ) {
631 + throw new \Exception( $result->get_error_message() );
632 + }
999 633
1000 634 return [
1001 635 'images' => $result['images'],
1002 636 'response_id' => $result['responseId'],
@@ -1004,75 +638,44 @@
1004 638 ];
1005 639 }
1006 640
1007 641 public function ajax_ai_get_image_to_image_mask( $data ) {
1008 - $this->verify_upload_permissions( $data );
642 + $this->verify_permissions( $data['editor_post_id'] );
1009 643
1010 644 $app = $this->get_ai_app();
1011 645
1012 - if ( empty( $data['payload']['prompt'] ) ) {
646 + if ( empty( $data['prompt'] ) ) {
1013 647 throw new \Exception( 'Missing prompt' );
1014 648 }
1015 649
1016 - if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) {
650 + if ( empty( $data['image'] ) || empty( $data['image']['id'] ) ) {
1017 651 throw new \Exception( 'Missing Image' );
1018 652 }
1019 653
1020 - if ( empty( $data['payload']['settings'] ) ) {
654 + if ( empty( $data['promptSettings'] ) ) {
1021 655 throw new \Exception( 'Missing prompt settings' );
1022 656 }
1023 657
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 658 if ( ! $app->is_connected() ) {
1059 659 throw new \Exception( 'not_connected' );
1060 660 }
1061 661
1062 - if ( empty( $data['payload']['mask'] ) ) {
662 + if ( empty( $data['mask'] ) ) {
1063 663 throw new \Exception( 'Missing Mask' );
1064 664 }
1065 665
1066 666 $context = $this->get_request_context( $data );
1067 - $request_ids = $this->get_request_ids( $data['payload'] );
1068 667
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 );
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 );
1073 674
1074 - $this->throw_on_error( $result );
675 + if ( is_wp_error( $result ) ) {
676 + throw new \Exception( $result->get_error_message() );
677 + }
1075 678
1076 679 return [
1077 680 'images' => $result['images'],
1078 681 'response_id' => $result['responseId'],
@@ -1078,32 +681,35 @@
1078 681 'response_id' => $result['responseId'],
1079 682 'usage' => $result['usage'],
1080 683 ];
1081 684 }
1082 -
1083 685 public function ajax_ai_get_image_to_image_outpainting( $data ) {
1084 - $this->verify_upload_permissions( $data );
686 + $this->verify_permissions( $data['editor_post_id'] );
1085 687
1086 688 $app = $this->get_ai_app();
1087 689
690 + if ( empty( $data['prompt'] ) ) {
691 + throw new \Exception( 'Missing prompt' );
692 + }
693 +
1088 694 if ( ! $app->is_connected() ) {
1089 695 throw new \Exception( 'not_connected' );
1090 696 }
1091 697
1092 - if ( empty( $data['payload']['mask'] ) ) {
698 + if ( empty( $data['mask'] ) ) {
1093 699 throw new \Exception( 'Missing Expended Image' );
1094 700 }
1095 701
1096 702 $context = $this->get_request_context( $data );
1097 - $request_ids = $this->get_request_ids( $data['payload'] );
703 +
1098 704 $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 );
705 + 'prompt' => $data['prompt'],
706 + 'mask' => $data['mask'],
707 + ], $context );
1104 708
1105 - $this->throw_on_error( $result );
709 + if ( is_wp_error( $result ) ) {
710 + throw new \Exception( $result->get_error_message() );
711 + }
1106 712
1107 713 return [
1108 714 'images' => $result['images'],
1109 715 'response_id' => $result['responseId'],
@@ -1111,10 +717,8 @@
1111 717 ];
1112 718 }
1113 719
1114 720 public function ajax_ai_upload_image( $data ) {
1115 - $this->verify_upload_permissions( $data );
1116 -
1117 721 if ( empty( $data['image'] ) ) {
1118 722 throw new \Exception( 'Missing image data' );
1119 723 }
1120 724
@@ -1126,14 +730,14 @@
1126 730
1127 731 $image_data = $this->upload_image( $image['image_url'], $data['prompt'], $data['editor_post_id'] );
1128 732
1129 733 if ( is_wp_error( $image_data ) ) {
1130 - throw new \Exception( esc_html( $image_data->get_error_message() ) );
734 + throw new \Exception( $image_data->get_error_message() );
1131 735 }
1132 736
1133 737 if ( ! empty( $image['use_gallery_image'] ) && ! empty( $image['id'] ) ) {
1134 - $app = $this->get_ai_app();
1135 - $app->set_used_gallery_image( $image['id'] );
738 + $app = $this->get_ai_app();
739 + $app->set_used_gallery_image( $image['id'] );
1136 740 }
1137 741
1138 742 return [
1139 743 'image' => array_merge( $image_data, $data ),
@@ -1154,9 +758,9 @@
1154 758 }
1155 759
1156 760 $result = $app->generate_layout(
1157 761 $data,
1158 - $this->prepare_generate_layout_context( $data )
762 + $this->prepare_generate_layout_context()
1159 763 );
1160 764
1161 765 if ( is_wp_error( $result ) ) {
1162 766 $message = $result->get_error_message();
@@ -1162,12 +766,11 @@
1162 766 $message = $result->get_error_message();
1163 767
1164 768 if ( is_array( $message ) ) {
1165 769 $message = implode( ', ', $message );
1166 - throw new \Exception( esc_html( $message ) );
1167 770 }
1168 771
1169 - $this->throw_on_error( $result );
772 + throw new \Exception( $message );
1170 773 }
1171 774
1172 775 $elements = $result['text']['elements'] ?? [];
1173 776 $base_template_id = $result['baseTemplateId'] ?? null;
@@ -1227,12 +830,14 @@
1227 830
1228 831 $result = $app->get_layout_prompt_enhanced(
1229 832 $data['prompt'],
1230 833 $data['enhance_type'],
1231 - $this->prepare_generate_layout_context( $data )
834 + $this->prepare_generate_layout_context()
1232 835 );
1233 836
1234 - $this->throw_on_error( $result );
837 + if ( is_wp_error( $result ) ) {
838 + throw new \Exception( $result->get_error_message() );
839 + }
1235 840
1236 841 return [
1237 842 'text' => $result['text'] ?? $data['prompt'],
1238 843 'response_id' => $result['responseId'] ?? '',
@@ -1239,14 +844,13 @@
1239 844 'usage' => $result['usage'] ?? '',
1240 845 ];
1241 846 }
1242 847
1243 - private function prepare_generate_layout_context( $data ) {
1244 - $request_context = $this->get_request_context( $data );
848 + private function prepare_generate_layout_context() {
1245 849 $kit = Plugin::$instance->kits_manager->get_active_kit();
1246 850
1247 851 if ( ! $kit ) {
1248 - return $request_context;
852 + return [];
1249 853 }
1250 854
1251 855 $kits_data = Collection::make( $kit->get_data()['settings'] ?? [] );
1252 856
@@ -1299,14 +903,14 @@
1299 903 ],
1300 904 ];
1301 905 } );
1302 906
1303 - $request_context['globals'] = [
1304 - 'colors' => $colors->all(),
1305 - 'typography' => $typography->all(),
907 + return [
908 + 'globals' => [
909 + 'colors' => $colors->all(),
910 + 'typography' => $typography->all(),
911 + ],
1306 912 ];
1307 -
1308 - return $request_context;
1309 913 }
1310 914
1311 915 private function upload_image( $image_url, $image_title, $parent_post_id = 0 ) {
1312 916 if ( ! current_user_can( 'upload_files' ) ) {
@@ -1312,24 +916,10 @@
1312 916 if ( ! current_user_can( 'upload_files' ) ) {
1313 917 throw new \Exception( 'Not Allowed to Upload images' );
1314 918 }
1315 919
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 920 $attachment_id = media_sideload_image( $image_url, $parent_post_id, $image_title, 'id' );
1327 921
1328 - if ( is_wp_error( $attachment_id ) ) {
1329 - return new \WP_Error( 'upload_error', $attachment_id->get_error_message() );
1330 - }
1331 -
1332 922 if ( ! empty( $attachment_id['error'] ) ) {
1333 923 return new \WP_Error( 'upload_error', $attachment_id['error'] );
1334 924 }
1335 925
@@ -1334,10 +924,10 @@
1334 924 }
1335 925
1336 926 return [
1337 927 'id' => $attachment_id,
1338 - 'url' => esc_url( wp_get_attachment_image_url( $attachment_id, 'full' ) ),
1339 - 'alt' => esc_attr( $image_title ),
928 + 'url' => wp_get_attachment_image_url( $attachment_id, 'full' ),
929 + 'alt' => $image_title,
1340 930 'source' => 'library',
1341 931 ];
1342 932 }
1343 933
@@ -1361,9 +951,9 @@
1361 951
1362 952 $result = $app->get_history_by_type( $type, $page, $limit, $context );
1363 953
1364 954 if ( is_wp_error( $result ) ) {
1365 - throw new \Exception( esc_html( $result->get_error_message() ) );
955 + throw new \Exception( $result->get_error_message() );
1366 956 }
1367 957
1368 958 return $result;
1369 959 }
@@ -1383,9 +973,9 @@
1383 973
1384 974 $result = $app->delete_history_item( $data['id'], $context );
1385 975
1386 976 if ( is_wp_error( $result ) ) {
1387 - throw new \Exception( esc_html( $result->get_error_message() ) );
977 + throw new \Exception( $result->get_error_message() );
1388 978 }
1389 979
1390 980 return [];
1391 981 }
@@ -1405,193 +995,10 @@
1405 995
1406 996 $result = $app->toggle_favorite_history_item( $data['id'], $context );
1407 997
1408 998 if ( is_wp_error( $result ) ) {
1409 - throw new \Exception( esc_html( $result->get_error_message() ) );
999 + throw new \Exception( $result->get_error_message() );
1410 1000 }
1411 1001
1412 1002 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 1003 }
1597 1004 }