PluginProbe
Elementor Website Builder – more than just a page builder / 3.19.0-beta1
Elementor Website Builder – more than just a page builder v3.19.0-beta1
4.3.3 4.3.2 4.3.1 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 All 456 releases
← All changes | modules/ai/module.php +165 -780 4.3.0-beta2 → 3.19.0-beta1 View file →
@@ -1,16 +1,14 @@
1 1 <?php
2 2 namespace Elementor\Modules\Ai;
3 3
4 -use Elementor\Controls_Manager;
5 4 use Elementor\Core\Base\Module as BaseModule;
6 5 use Elementor\Core\Common\Modules\Connect\Module as ConnectModule;
7 -use Elementor\Element_Base;
8 -use Elementor\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 -use Elementor\Utils;
13 11
14 12 if ( ! defined( 'ABSPATH' ) ) {
15 13 exit; // Exit if accessed directly.
16 14 }
@@ -27,10 +25,11 @@
27 25 self::HISTORY_TYPE_CODE,
28 26 self::HISTORY_TYPE_IMAGE,
29 27 self::HISTORY_TYPE_BLOCK,
30 28 ];
31 - const MIN_PAGES_FOR_CREATE_WITH_AI_BANNER = 10;
32 29
30 + const LAYOUT_EXPERIMENT = 'ai-layout';
31 +
33 32 public function get_name() {
34 33 return 'ai';
35 34 }
36 35
@@ -36,21 +35,10 @@
36 35
37 36 public function __construct() {
38 37 parent::__construct();
39 38
40 - ( new SitePlannerConnect\Module() );
39 + $this->register_layout_experiment();
41 40
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 41 add_action( 'elementor/connect/apps/register', function ( ConnectModule $connect_module ) {
54 42 $connect_module->register_app( 'ai', Ai::get_class_name() );
55 43 } );
56 44
@@ -57,12 +45,9 @@
57 45 add_action( 'elementor/ajax/register_actions', function( $ajax ) {
58 46 $handlers = [
59 47 'ai_get_user_information' => [ $this, 'ajax_ai_get_user_information' ],
60 48 'ai_get_remote_config' => [ $this, 'ajax_ai_get_remote_config' ],
61 - 'ai_get_remote_frontend_config' => [ $this, 'ajax_ai_get_remote_frontend_config' ],
62 49 '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 50 'ai_get_edit_text' => [ $this, 'ajax_ai_get_edit_text' ],
66 51 'ai_get_custom_code' => [ $this, 'ajax_ai_get_custom_code' ],
67 52 'ai_get_custom_css' => [ $this, 'ajax_ai_get_custom_css' ],
68 53 'ai_set_get_started' => [ $this, 'ajax_ai_set_get_started' ],
@@ -70,9 +55,8 @@
70 55 'ai_get_image_prompt_enhancer' => [ $this, 'ajax_ai_get_image_prompt_enhancer' ],
71 56 'ai_get_text_to_image' => [ $this, 'ajax_ai_get_text_to_image' ],
72 57 'ai_get_image_to_image' => [ $this, 'ajax_ai_get_image_to_image' ],
73 58 '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 59 'ai_get_image_to_image_outpainting' => [ $this, 'ajax_ai_get_image_to_image_outpainting' ],
76 60 'ai_get_image_to_image_upscale' => [ $this, 'ajax_ai_get_image_to_image_upscale' ],
77 61 'ai_get_image_to_image_remove_background' => [ $this, 'ajax_ai_get_image_to_image_remove_background' ],
78 62 'ai_get_image_to_image_replace_background' => [ $this, 'ajax_ai_get_image_to_image_replace_background' ],
@@ -81,11 +65,8 @@
81 65 'ai_get_layout_prompt_enhancer' => [ $this, 'ajax_ai_get_layout_prompt_enhancer' ],
82 66 'ai_get_history' => [ $this, 'ajax_ai_get_history' ],
83 67 'ai_delete_history_item' => [ $this, 'ajax_ai_delete_history_item' ],
84 68 '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 69 ];
89 70
90 71 foreach ( $handlers as $tag => $callback ) {
91 72 $ajax->register_ajax_action( $tag, $callback );
@@ -93,9 +74,12 @@
93 74 } );
94 75
95 76 add_action( 'elementor/editor/before_enqueue_scripts', function() {
96 77 $this->enqueue_main_script();
97 - $this->enqueue_layout_script();
78 +
79 + if ( $this->is_layout_active() ) {
80 + $this->enqueue_layout_script();
81 + }
98 82 } );
99 83
100 84 add_action( 'elementor/editor/after_enqueue_styles', function() {
101 85 wp_enqueue_style(
@@ -106,351 +90,40 @@
106 90 );
107 91 } );
108 92
109 93 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 - );
94 + if ( $this->is_layout_active() ) {
95 + wp_enqueue_style(
96 + 'elementor-ai-layout-preview',
97 + $this->get_css_assets_url( 'modules/ai/layout-preview' ),
98 + [],
99 + ELEMENTOR_VERSION
100 + );
101 + }
116 102 } );
117 103
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' ] );
104 + add_filter( 'elementor/document/save/data', function ( $data ) {
105 + if ( $this->is_layout_active() ) {
106 + return $this->remove_temporary_containers( $data );
127 107 }
128 - }
129 108
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 );
109 + return $data;
163 110 } );
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 111 }
170 112
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'],
113 + private function register_layout_experiment() {
114 + Plugin::$instance->experiments->add_feature( [
115 + 'name' => static::LAYOUT_EXPERIMENT,
116 + 'title' => esc_html__( 'Build with AI', 'elementor' ),
117 + 'description' => esc_html__( 'Tap into the potential of AI to easily create and customize containers to your specifications, right within Elementor. This feature comes packed with handy AI tools, including generation, variations, and URL references.', 'elementor' ),
118 + 'default' => Experiments_Manager::STATE_ACTIVE,
119 + 'release_status' => Experiments_Manager::RELEASE_STATUS_BETA,
120 + 'dependencies' => [
121 + 'container',
212 122 ],
213 123 ] );
214 124 }
215 125
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 126 private function enqueue_main_script() {
454 127 wp_enqueue_script(
455 128 'elementor-ai',
456 129 $this->get_js_assets_url( 'ai' ),
@@ -474,8 +147,13 @@
474 147 'is_get_started' => User::get_introduction_meta( 'ai_get_started' ),
475 148 'connect_url' => $this->get_ai_connect_url(),
476 149 ];
477 150
151 + if ( $this->get_ai_app()->is_connected() ) {
152 + // Use a cached version, don't call the API on every editor load.
153 + $config['usage'] = $this->get_ai_app()->get_cached_usage();
154 + }
155 +
478 156 wp_localize_script(
479 157 'elementor-ai',
480 158 'ElementorAiConfig',
481 159 $config
@@ -505,10 +183,14 @@
505 183
506 184 wp_set_script_translations( 'elementor-ai-layout', 'elementor' );
507 185 }
508 186
187 + private function is_layout_active() {
188 + return Plugin::$instance->experiments->is_feature_active( self::LAYOUT_EXPERIMENT );
189 + }
190 +
509 191 private function remove_temporary_containers( $data ) {
510 - if ( empty( $data['elements'] ) || ! is_array( $data['elements'] ) ) {
192 + if ( empty( $data['elements'] ) ) {
511 193 return $data;
512 194 }
513 195
514 196 // If for some reason the document has been saved during an AI Layout session,
@@ -566,25 +248,8 @@
566 248
567 249 return $app->get_remote_config();
568 250 }
569 251
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 252 private function verify_permissions( $editor_post_id ) {
588 253 $document = Plugin::$instance->documents->get( $editor_post_id );
589 254
590 255 if ( ! $document ) {
@@ -590,19 +255,15 @@
590 255 if ( ! $document ) {
591 256 throw new \Exception( 'Document not found' );
592 257 }
593 258
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' );
259 + if ( ! $document->is_built_with_elementor() || ! $document->is_editable_by_current_user() ) {
260 + throw new \Exception( 'Access denied' );
600 261 }
601 262 }
602 263
603 264 public function ajax_ai_get_image_prompt_enhancer( $data ) {
604 - $this->verify_upload_permissions( $data );
265 + $this->verify_permissions( $data['editor_post_id'] );
605 266
606 267 $app = $this->get_ai_app();
607 268
608 269 if ( empty( $data['prompt'] ) ) {
@@ -611,12 +272,13 @@
611 272
612 273 if ( ! $app->is_connected() ) {
613 274 throw new \Exception( 'not_connected' );
614 275 }
615 - $request_ids = $this->get_request_ids( $data['payload'] );
616 276
617 - $result = $app->get_image_prompt_enhanced( $data['prompt'], [], $request_ids );
618 - $this->throw_on_error( $result );
277 + $result = $app->get_image_prompt_enhanced( $data['prompt'] );
278 + if ( is_wp_error( $result ) ) {
279 + throw new \Exception( $result->get_error_message() );
280 + }
619 281
620 282 return [
621 283 'text' => $result['text'],
622 284 'response_id' => $result['responseId'],
@@ -628,9 +290,9 @@
628 290 $this->verify_permissions( $data['editor_post_id'] );
629 291
630 292 $app = $this->get_ai_app();
631 293
632 - if ( empty( $data['payload']['prompt'] ) ) {
294 + if ( empty( $data['prompt'] ) ) {
633 295 throw new \Exception( 'Missing prompt' );
634 296 }
635 297
636 298 if ( ! $app->is_connected() ) {
@@ -638,39 +300,13 @@
638 300 }
639 301
640 302 $context = $this->get_request_context( $data );
641 303
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' );
304 + $result = $app->get_completion_text( $data['prompt'], $context );
305 + if ( is_wp_error( $result ) ) {
306 + throw new \Exception( $result->get_error_message() );
660 307 }
661 308
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 309 return [
674 310 'text' => $result['text'],
675 311 'response_id' => $result['responseId'],
676 312 'usage' => $result['usage'],
@@ -676,36 +312,9 @@
676 312 'usage' => $result['usage'],
677 313 ];
678 314 }
679 315
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 {
316 + private function get_ai_app() : Ai {
708 317 return Plugin::$instance->common->get_component( 'connect' )->get_app( 'ai' );
709 318 }
710 319
711 320 private function get_request_context( $data ) {
@@ -715,26 +324,18 @@
715 324
716 325 return $data['context'];
717 326 }
718 327
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 328 public function ajax_ai_get_edit_text( $data ) {
728 329 $this->verify_permissions( $data['editor_post_id'] );
729 330
730 331 $app = $this->get_ai_app();
731 332
732 - if ( empty( $data['payload']['input'] ) ) {
333 + if ( empty( $data['input'] ) ) {
733 334 throw new \Exception( 'Missing input' );
734 335 }
735 336
736 - if ( empty( $data['payload']['instruction'] ) ) {
337 + if ( empty( $data['instruction'] ) ) {
737 338 throw new \Exception( 'Missing instruction' );
738 339 }
739 340
740 341 if ( ! $app->is_connected() ) {
@@ -742,13 +343,13 @@
742 343 }
743 344
744 345 $context = $this->get_request_context( $data );
745 346
746 - $request_ids = $this->get_request_ids( $data['payload'] );
347 + $result = $app->get_edit_text( $data['input'], $data['instruction'], $context );
348 + if ( is_wp_error( $result ) ) {
349 + throw new \Exception( $result->get_error_message() );
350 + }
747 351
748 - $result = $app->get_edit_text( $data, $context, $request_ids );
749 - $this->throw_on_error( $result );
750 -
751 352 return [
752 353 'text' => $result['text'],
753 354 'response_id' => $result['responseId'],
754 355 'usage' => $result['usage'],
@@ -757,13 +358,13 @@
757 358
758 359 public function ajax_ai_get_custom_code( $data ) {
759 360 $app = $this->get_ai_app();
760 361
761 - if ( empty( $data['payload']['prompt'] ) ) {
362 + if ( empty( $data['prompt'] ) ) {
762 363 throw new \Exception( 'Missing prompt' );
763 364 }
764 365
765 - if ( empty( $data['payload']['language'] ) ) {
366 + if ( empty( $data['language'] ) ) {
766 367 throw new \Exception( 'Missing language' );
767 368 }
768 369
769 370 if ( ! $app->is_connected() ) {
@@ -771,13 +372,13 @@
771 372 }
772 373
773 374 $context = $this->get_request_context( $data );
774 375
775 - $request_ids = $this->get_request_ids( $data['payload'] );
376 + $result = $app->get_custom_code( $data['prompt'], $data['language'], $context );
377 + if ( is_wp_error( $result ) ) {
378 + throw new \Exception( $result->get_error_message() );
379 + }
776 380
777 - $result = $app->get_custom_code( $data, $context, $request_ids );
778 - $this->throw_on_error( $result );
779 -
780 381 return [
781 382 'text' => $result['text'],
782 383 'response_id' => $result['responseId'],
783 384 'usage' => $result['usage'],
@@ -788,17 +389,17 @@
788 389 $this->verify_permissions( $data['editor_post_id'] );
789 390
790 391 $app = $this->get_ai_app();
791 392
792 - if ( empty( $data['payload']['prompt'] ) ) {
393 + if ( empty( $data['prompt'] ) ) {
793 394 throw new \Exception( 'Missing prompt' );
794 395 }
795 396
796 - if ( empty( $data['payload']['html_markup'] ) ) {
397 + if ( empty( $data['html_markup'] ) ) {
797 398 $data['html_markup'] = '';
798 399 }
799 400
800 - if ( empty( $data['payload']['element_id'] ) ) {
401 + if ( empty( $data['element_id'] ) ) {
801 402 throw new \Exception( 'Missing element_id' );
802 403 }
803 404
804 405 if ( ! $app->is_connected() ) {
@@ -805,12 +406,13 @@
805 406 throw new \Exception( 'not_connected' );
806 407 }
807 408
808 409 $context = $this->get_request_context( $data );
809 - $request_ids = $this->get_request_ids( $data['payload'] );
810 410
811 - $result = $app->get_custom_css( $data, $context, $request_ids );
812 - $this->throw_on_error( $result );
411 + $result = $app->get_custom_css( $data['prompt'], $data['html_markup'], $data['element_id'], $context );
412 + if ( is_wp_error( $result ) ) {
413 + throw new \Exception( $result->get_error_message() );
414 + }
813 415
814 416 return [
815 417 'text' => $result['text'],
816 418 'response_id' => $result['responseId'],
@@ -844,11 +446,11 @@
844 446 return [];
845 447 }
846 448
847 449 public function ajax_ai_get_text_to_image( $data ) {
848 - $this->verify_upload_permissions( $data );
450 + $this->verify_permissions( $data['editor_post_id'] );
849 451
850 - if ( empty( $data['payload']['prompt'] ) ) {
452 + if ( empty( $data['prompt'] ) ) {
851 453 throw new \Exception( 'Missing prompt' );
852 454 }
853 455
854 456 $app = $this->get_ai_app();
@@ -857,13 +459,14 @@
857 459 throw new \Exception( 'not_connected' );
858 460 }
859 461
860 462 $context = $this->get_request_context( $data );
861 - $request_ids = $this->get_request_ids( $data['payload'] );
862 463
863 - $result = $app->get_text_to_image( $data, $context, $request_ids );
464 + $result = $app->get_text_to_image( $data['prompt'], $data['promptSettings'], $context );
864 465
865 - $this->throw_on_error( $result );
466 + if ( is_wp_error( $result ) ) {
467 + throw new \Exception( $result->get_error_message() );
468 + }
866 469
867 470 return [
868 471 'images' => $result['images'],
869 472 'response_id' => $result['responseId'],
@@ -871,17 +474,21 @@
871 474 ];
872 475 }
873 476
874 477 public function ajax_ai_get_image_to_image( $data ) {
875 - $this->verify_upload_permissions( $data );
478 + $this->verify_permissions( $data['editor_post_id'] );
876 479
877 480 $app = $this->get_ai_app();
878 481
879 - if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) {
482 + if ( empty( $data['prompt'] ) ) {
483 + throw new \Exception( 'Missing prompt' );
484 + }
485 +
486 + if ( empty( $data['image'] ) || empty( $data['image']['id'] ) ) {
880 487 throw new \Exception( 'Missing Image' );
881 488 }
882 489
883 - if ( empty( $data['payload']['settings'] ) ) {
490 + if ( empty( $data['promptSettings'] ) ) {
884 491 throw new \Exception( 'Missing prompt settings' );
885 492 }
886 493
887 494 if ( ! $app->is_connected() ) {
@@ -888,17 +495,18 @@
888 495 throw new \Exception( 'not_connected' );
889 496 }
890 497
891 498 $context = $this->get_request_context( $data );
892 - $request_ids = $this->get_request_ids( $data['payload'] );
893 499
894 500 $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 );
501 + 'prompt' => $data['prompt'],
502 + 'promptSettings' => $data['promptSettings'],
503 + 'attachment_id' => $data['image']['id'],
504 + ], $context );
899 505
900 - $this->throw_on_error( $result );
506 + if ( is_wp_error( $result ) ) {
507 + throw new \Exception( $result->get_error_message() );
508 + }
901 509
902 510 return [
903 511 'images' => $result['images'],
904 512 'response_id' => $result['responseId'],
@@ -906,17 +514,17 @@
906 514 ];
907 515 }
908 516
909 517 public function ajax_ai_get_image_to_image_upscale( $data ) {
910 - $this->verify_upload_permissions( $data );
518 + $this->verify_permissions( $data['editor_post_id'] );
911 519
912 520 $app = $this->get_ai_app();
913 521
914 - if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) {
522 + if ( empty( $data['image'] ) || empty( $data['image']['id'] ) ) {
915 523 throw new \Exception( 'Missing Image' );
916 524 }
917 525
918 - if ( empty( $data['payload']['promptSettings'] ) ) {
526 + if ( empty( $data['promptSettings'] ) ) {
919 527 throw new \Exception( 'Missing prompt settings' );
920 528 }
921 529
922 530 if ( ! $app->is_connected() ) {
@@ -923,16 +531,17 @@
923 531 throw new \Exception( 'not_connected' );
924 532 }
925 533
926 534 $context = $this->get_request_context( $data );
927 - $request_ids = $this->get_request_ids( $data['payload'] );
928 535
929 536 $result = $app->get_image_to_image_upscale( [
930 - 'promptSettings' => $data['payload']['promptSettings'],
931 - 'attachment_id' => $data['payload']['image']['id'],
932 - ], $context, $request_ids );
537 + 'promptSettings' => $data['promptSettings'],
538 + 'attachment_id' => $data['image']['id'],
539 + ], $context );
933 540
934 - $this->throw_on_error( $result );
541 + if ( is_wp_error( $result ) ) {
542 + throw new \Exception( $result->get_error_message() );
543 + }
935 544
936 545 return [
937 546 'images' => $result['images'],
938 547 'response_id' => $result['responseId'],
@@ -940,17 +549,17 @@
940 549 ];
941 550 }
942 551
943 552 public function ajax_ai_get_image_to_image_replace_background( $data ) {
944 - $this->verify_upload_permissions( $data );
553 + $this->verify_permissions( $data['editor_post_id'] );
945 554
946 555 $app = $this->get_ai_app();
947 556
948 - if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) {
557 + if ( empty( $data['image'] ) || empty( $data['image']['id'] ) ) {
949 558 throw new \Exception( 'Missing Image' );
950 559 }
951 560
952 - if ( empty( $data['payload']['prompt'] ) ) {
561 + if ( empty( $data['prompt'] ) ) {
953 562 throw new \Exception( 'Prompt Missing' );
954 563 }
955 564
956 565 if ( ! $app->is_connected() ) {
@@ -957,16 +566,17 @@
957 566 throw new \Exception( 'not_connected' );
958 567 }
959 568
960 569 $context = $this->get_request_context( $data );
961 - $request_ids = $this->get_request_ids( $data['payload'] );
962 570
963 571 $result = $app->get_image_to_image_replace_background( [
964 - 'attachment_id' => $data['payload']['image']['id'],
965 - 'prompt' => $data['payload']['prompt'],
966 - ], $context, $request_ids );
572 + 'attachment_id' => $data['image']['id'],
573 + 'prompt' => $data['prompt'],
574 + ], $context );
967 575
968 - $this->throw_on_error( $result );
576 + if ( is_wp_error( $result ) ) {
577 + throw new \Exception( $result->get_error_message() );
578 + }
969 579
970 580 return [
971 581 'images' => $result['images'],
972 582 'response_id' => $result['responseId'],
@@ -974,13 +584,13 @@
974 584 ];
975 585 }
976 586
977 587 public function ajax_ai_get_image_to_image_remove_background( $data ) {
978 - $this->verify_upload_permissions( $data );
588 + $this->verify_permissions( $data['editor_post_id'] );
979 589
980 590 $app = $this->get_ai_app();
981 591
982 - if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) {
592 + if ( empty( $data['image'] ) || empty( $data['image']['id'] ) ) {
983 593 throw new \Exception( 'Missing Image' );
984 594 }
985 595
986 596 if ( ! $app->is_connected() ) {
@@ -987,14 +597,16 @@
987 597 throw new \Exception( 'not_connected' );
988 598 }
989 599
990 600 $context = $this->get_request_context( $data );
991 - $request_ids = $this->get_request_ids( $data['payload'] );
601 +
992 602 $result = $app->get_image_to_image_remove_background( [
993 - 'attachment_id' => $data['payload']['image']['id'],
994 - ], $context, $request_ids );
603 + 'attachment_id' => $data['image']['id'],
604 + ], $context );
995 605
996 - $this->throw_on_error( $result );
606 + if ( is_wp_error( $result ) ) {
607 + throw new \Exception( $result->get_error_message() );
608 + }
997 609
998 610 return [
999 611 'images' => $result['images'],
1000 612 'response_id' => $result['responseId'],
@@ -1002,75 +614,44 @@
1002 614 ];
1003 615 }
1004 616
1005 617 public function ajax_ai_get_image_to_image_mask( $data ) {
1006 - $this->verify_upload_permissions( $data );
618 + $this->verify_permissions( $data['editor_post_id'] );
1007 619
1008 620 $app = $this->get_ai_app();
1009 621
1010 - if ( empty( $data['payload']['prompt'] ) ) {
622 + if ( empty( $data['prompt'] ) ) {
1011 623 throw new \Exception( 'Missing prompt' );
1012 624 }
1013 625
1014 - if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) {
626 + if ( empty( $data['image'] ) || empty( $data['image']['id'] ) ) {
1015 627 throw new \Exception( 'Missing Image' );
1016 628 }
1017 629
1018 - if ( empty( $data['payload']['settings'] ) ) {
630 + if ( empty( $data['promptSettings'] ) ) {
1019 631 throw new \Exception( 'Missing prompt settings' );
1020 632 }
1021 633
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 634 if ( ! $app->is_connected() ) {
1057 635 throw new \Exception( 'not_connected' );
1058 636 }
1059 637
1060 - if ( empty( $data['payload']['mask'] ) ) {
638 + if ( empty( $data['mask'] ) ) {
1061 639 throw new \Exception( 'Missing Mask' );
1062 640 }
1063 641
1064 642 $context = $this->get_request_context( $data );
1065 - $request_ids = $this->get_request_ids( $data['payload'] );
1066 643
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 );
644 + $result = $app->get_image_to_image_mask( [
645 + 'prompt' => $data['prompt'],
646 + 'promptSettings' => $data['promptSettings'],
647 + 'attachment_id' => $data['image']['id'],
648 + 'mask' => $data['mask'],
649 + ], $context );
1071 650
1072 - $this->throw_on_error( $result );
651 + if ( is_wp_error( $result ) ) {
652 + throw new \Exception( $result->get_error_message() );
653 + }
1073 654
1074 655 return [
1075 656 'images' => $result['images'],
1076 657 'response_id' => $result['responseId'],
@@ -1076,32 +657,35 @@
1076 657 'response_id' => $result['responseId'],
1077 658 'usage' => $result['usage'],
1078 659 ];
1079 660 }
1080 -
1081 661 public function ajax_ai_get_image_to_image_outpainting( $data ) {
1082 - $this->verify_upload_permissions( $data );
662 + $this->verify_permissions( $data['editor_post_id'] );
1083 663
1084 664 $app = $this->get_ai_app();
1085 665
666 + if ( empty( $data['prompt'] ) ) {
667 + throw new \Exception( 'Missing prompt' );
668 + }
669 +
1086 670 if ( ! $app->is_connected() ) {
1087 671 throw new \Exception( 'not_connected' );
1088 672 }
1089 673
1090 - if ( empty( $data['payload']['mask'] ) ) {
674 + if ( empty( $data['mask'] ) ) {
1091 675 throw new \Exception( 'Missing Expended Image' );
1092 676 }
1093 677
1094 678 $context = $this->get_request_context( $data );
1095 - $request_ids = $this->get_request_ids( $data['payload'] );
679 +
1096 680 $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 );
681 + 'prompt' => $data['prompt'],
682 + 'mask' => $data['mask'],
683 + ], $context );
1102 684
1103 - $this->throw_on_error( $result );
685 + if ( is_wp_error( $result ) ) {
686 + throw new \Exception( $result->get_error_message() );
687 + }
1104 688
1105 689 return [
1106 690 'images' => $result['images'],
1107 691 'response_id' => $result['responseId'],
@@ -1109,10 +693,8 @@
1109 693 ];
1110 694 }
1111 695
1112 696 public function ajax_ai_upload_image( $data ) {
1113 - $this->verify_upload_permissions( $data );
1114 -
1115 697 if ( empty( $data['image'] ) ) {
1116 698 throw new \Exception( 'Missing image data' );
1117 699 }
1118 700
@@ -1124,14 +706,14 @@
1124 706
1125 707 $image_data = $this->upload_image( $image['image_url'], $data['prompt'], $data['editor_post_id'] );
1126 708
1127 709 if ( is_wp_error( $image_data ) ) {
1128 - throw new \Exception( esc_html( $image_data->get_error_message() ) );
710 + throw new \Exception( $image_data->get_error_message() );
1129 711 }
1130 712
1131 713 if ( ! empty( $image['use_gallery_image'] ) && ! empty( $image['id'] ) ) {
1132 - $app = $this->get_ai_app();
1133 - $app->set_used_gallery_image( $image['id'] );
714 + $app = $this->get_ai_app();
715 + $app->set_used_gallery_image( $image['id'] );
1134 716 }
1135 717
1136 718 return [
1137 719 'image' => array_merge( $image_data, $data ),
@@ -1152,9 +734,9 @@
1152 734 }
1153 735
1154 736 $result = $app->generate_layout(
1155 737 $data,
1156 - $this->prepare_generate_layout_context( $data )
738 + $this->prepare_generate_layout_context()
1157 739 );
1158 740
1159 741 if ( is_wp_error( $result ) ) {
1160 742 $message = $result->get_error_message();
@@ -1160,12 +742,11 @@
1160 742 $message = $result->get_error_message();
1161 743
1162 744 if ( is_array( $message ) ) {
1163 745 $message = implode( ', ', $message );
1164 - throw new \Exception( esc_html( $message ) );
1165 746 }
1166 747
1167 - $this->throw_on_error( $result );
748 + throw new \Exception( $message );
1168 749 }
1169 750
1170 751 $elements = $result['text']['elements'] ?? [];
1171 752 $base_template_id = $result['baseTemplateId'] ?? null;
@@ -1225,12 +806,14 @@
1225 806
1226 807 $result = $app->get_layout_prompt_enhanced(
1227 808 $data['prompt'],
1228 809 $data['enhance_type'],
1229 - $this->prepare_generate_layout_context( $data )
810 + $this->prepare_generate_layout_context()
1230 811 );
1231 812
1232 - $this->throw_on_error( $result );
813 + if ( is_wp_error( $result ) ) {
814 + throw new \Exception( $result->get_error_message() );
815 + }
1233 816
1234 817 return [
1235 818 'text' => $result['text'] ?? $data['prompt'],
1236 819 'response_id' => $result['responseId'] ?? '',
@@ -1237,14 +820,13 @@
1237 820 'usage' => $result['usage'] ?? '',
1238 821 ];
1239 822 }
1240 823
1241 - private function prepare_generate_layout_context( $data ) {
1242 - $request_context = $this->get_request_context( $data );
824 + private function prepare_generate_layout_context() {
1243 825 $kit = Plugin::$instance->kits_manager->get_active_kit();
1244 826
1245 827 if ( ! $kit ) {
1246 - return $request_context;
828 + return [];
1247 829 }
1248 830
1249 831 $kits_data = Collection::make( $kit->get_data()['settings'] ?? [] );
1250 832
@@ -1297,14 +879,14 @@
1297 879 ],
1298 880 ];
1299 881 } );
1300 882
1301 - $request_context['globals'] = [
1302 - 'colors' => $colors->all(),
1303 - 'typography' => $typography->all(),
883 + return [
884 + 'globals' => [
885 + 'colors' => $colors->all(),
886 + 'typography' => $typography->all(),
887 + ],
1304 888 ];
1305 -
1306 - return $request_context;
1307 889 }
1308 890
1309 891 private function upload_image( $image_url, $image_title, $parent_post_id = 0 ) {
1310 892 if ( ! current_user_can( 'upload_files' ) ) {
@@ -1310,24 +892,10 @@
1310 892 if ( ! current_user_can( 'upload_files' ) ) {
1311 893 throw new \Exception( 'Not Allowed to Upload images' );
1312 894 }
1313 895
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 896 $attachment_id = media_sideload_image( $image_url, $parent_post_id, $image_title, 'id' );
1325 897
1326 - if ( is_wp_error( $attachment_id ) ) {
1327 - return new \WP_Error( 'upload_error', $attachment_id->get_error_message() );
1328 - }
1329 -
1330 898 if ( ! empty( $attachment_id['error'] ) ) {
1331 899 return new \WP_Error( 'upload_error', $attachment_id['error'] );
1332 900 }
1333 901
@@ -1332,10 +900,10 @@
1332 900 }
1333 901
1334 902 return [
1335 903 'id' => $attachment_id,
1336 - 'url' => esc_url( wp_get_attachment_image_url( $attachment_id, 'full' ) ),
1337 - 'alt' => esc_attr( $image_title ),
904 + 'url' => wp_get_attachment_image_url( $attachment_id, 'full' ),
905 + 'alt' => $image_title,
1338 906 'source' => 'library',
1339 907 ];
1340 908 }
1341 909
@@ -1359,9 +927,9 @@
1359 927
1360 928 $result = $app->get_history_by_type( $type, $page, $limit, $context );
1361 929
1362 930 if ( is_wp_error( $result ) ) {
1363 - throw new \Exception( esc_html( $result->get_error_message() ) );
931 + throw new \Exception( $result->get_error_message() );
1364 932 }
1365 933
1366 934 return $result;
1367 935 }
@@ -1381,9 +949,9 @@
1381 949
1382 950 $result = $app->delete_history_item( $data['id'], $context );
1383 951
1384 952 if ( is_wp_error( $result ) ) {
1385 - throw new \Exception( esc_html( $result->get_error_message() ) );
953 + throw new \Exception( $result->get_error_message() );
1386 954 }
1387 955
1388 956 return [];
1389 957 }
@@ -1403,193 +971,10 @@
1403 971
1404 972 $result = $app->toggle_favorite_history_item( $data['id'], $context );
1405 973
1406 974 if ( is_wp_error( $result ) ) {
1407 - throw new \Exception( esc_html( $result->get_error_message() ) );
975 + throw new \Exception( $result->get_error_message() );
1408 976 }
1409 977
1410 978 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 979 }
1595 980 }