?MZ? ?? ? @ ? o !?L!This program cannot be run in DOS mode.
$ 3B#?#?#???A#?T??#?騴??#??'??#???t#??T??#?????#???e#?#??{#?sT??#?s???#?Rich#? PE d? ??g e " * o ? @ P ? `? P ? ?? ` # @ t P @ D .text 1 o `.rdata j+ D , ? @ @.data PS @ .pdata # ` $ ? @ @.fptable ? @ .rsrc ?? ? ? @ @.reloc t @ ?
/**
* Front to the WordPress application. This file doesn't do anything, but loads
site-planner-connect/view.php 0000644 00000020270 15156145315 0012266 0 ustar 00
%title%
%description%
%cta%
site-planner-connect/module.php 0000644 00000003425 15156145315 0012604 0 ustar 00 get_route() && is_user_logged_in() ) {
$user = wp_get_current_user();
$response->data['user_login'] = $user->user_login;
}
return $response;
}, 10, 3 );
}
public function on_rest_init(): void {
( new Wp_Rest_Api() )->register();
}
public function register_menu_page() {
add_submenu_page(
self::HIDDEN_PAGE_SLUG,
'App Password Generator',
'App Password',
'manage_options',
'e-site-planner-password-generator',
[ $this, 'render_menu_page' ]
);
}
public function render_menu_page() {
ob_start();
require_once __DIR__ . '/view.php';
$content = ob_get_clean();
$vars = [
'%app_name%' => self::NOT_TRANSLATED_APP_NAME,
'%safe_origin%' => esc_url( self::PLANNER_ORIGIN ),
'%domain%' => isset( $_SERVER['HTTP_HOST'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_HOST'] ) ) : '',
'%title%' => esc_html__( 'Connect to Site Planner', 'elementor' ),
'%description%' => esc_html__( 'To connect your site to Site Planner, you need to generate an app password.', 'elementor' ),
'%cta%' => esc_html__( 'Approve & Connect', 'elementor' ),
];
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo strtr( $content, $vars );
}
}
site-planner-connect/wp-rest-api.php 0000644 00000001353 15156145315 0013465 0 ustar 00 \WP_REST_Server::READABLE,
'permission_callback' => function () {
return current_user_can( 'manage_options' );
},
'callback' => function () {
try {
wp_send_json_success( [
'site_planner_connect' => true,
] );
} catch ( \Exception $e ) {
wp_send_json_error( [
'message' => $e->getMessage(),
] );
}
},
],
] );
}
}
feature-intro/product-image-unification-intro.php 0000644 00000004202 15156145315 0016244 0 ustar 00 post_type ) || 'product' !== $screen->post_type ) {
return;
}
wp_enqueue_script( 'wp-pointer' );
wp_enqueue_style( 'wp-pointer' );
$pointer_content = '' . esc_html__( 'New! Unify pack-shots with Elementor AI', 'elementor' ) . ' ';
$pointer_content .= '' . esc_html__( 'Now you can process images in bulk and standardized the background and ratio - no manual editing required!', 'elementor' ) . '
';
$pointer_content .= sprintf(
'%s
',
esc_js( 'https://go.elementor.com/wp-dash-unify-images-learn-more/' ),
esc_html__( 'Learn more', 'elementor' )
);
?>
add_personal_options_settings( $user );
} );
add_action( 'personal_options_update', function ( $user_id ) {
$this->update_personal_options_settings( $user_id );
} );
add_action( 'edit_user_profile_update', function ( $user_id ) {
$this->update_personal_options_settings( $user_id );
} );
}
/**
* Determine if AI features are enabled for a user.
*
* @param int $user_id - User ID.
*
* @return bool
*/
public static function is_ai_enabled( $user_id ) {
return (bool) User::get_user_option_with_default( static::ENABLE_AI, $user_id, true );
}
/**
* Add settings to the "Personal Options".
*
* @param \WP_User $user - User object.
*
* @return void
*/
protected function add_personal_options_settings( \WP_User $user ) {
if ( ! $this->has_permissions_to_edit_user( $user->ID ) ) {
return;
}
$ai_value = User::get_user_option_with_default( static::ENABLE_AI, $user->ID, '1' );
?>
/>
has_permissions_to_edit_user( $user_id ) ) {
return;
}
$ai_value = empty( $_POST[ static::ENABLE_AI ] ) ? '0' : '1';
update_user_option( $user_id, static::ENABLE_AI, sanitize_text_field( $ai_value ) );
}
/**
* Determine if the current user has permission to view/change preferences of a user.
*
* @param int $user_id
*
* @return bool
*/
protected function has_permissions_to_edit_user( $user_id ) {
return current_user_can( 'edit_user', $user_id );
}
}
connect/ai.php 0000644 00000054450 15156145315 0007315 0 ustar 00 ai_request(
'POST',
'status/check',
[
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
]
);
}
public function get_remote_config() {
return $this->ai_request(
'GET',
'remote-config/config',
[
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
]
);
}
public function get_remote_frontend_config( $data ) {
return $this->ai_request(
'POST',
'remote-config/frontend-config',
[
'client_name' => $data['payload']['client_name'],
'client_version' => $data['payload']['client_version'],
'client_session_id' => $data['payload']['client_session_id'],
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
],
false,
'',
'json'
);
}
/**
* @param array $event_data {
* @type string $name
* @type array $data
* @type array $client {
* @type string $name
* @type string $version
* @type string $session_id
* }
* }
*/
public function send_event( array $event_data ): void {
$this->ai_request(
'POST',
'client-events/events',
[
'payload' => $event_data,
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
],
false,
'',
'json'
);
}
/**
* Get file upload get_file_payload
*
* @param $filename
* @param $file_type
* @param $file_path
* @param $boundary
*
* @return string
*/
private function get_file_payload( $filename, $file_type, $file_path, $boundary ) {
$name = $filename ?? basename( $file_path );
$mine_type = 'image' === $file_type ? image_type_to_mime_type( exif_imagetype( $file_path ) ) : $file_type;
$payload = '';
// Upload the file
$payload .= '--' . $boundary;
$payload .= "\r\n";
$payload .= 'Content-Disposition: form-data; name="' . esc_attr( $name ) . '"; filename="' . esc_attr( $name ) . '"' . "\r\n";
$payload .= 'Content-Type: ' . $mine_type . "\r\n";
$payload .= "\r\n";
$payload .= file_get_contents( $file_path );
$payload .= "\r\n";
return $payload;
}
private function get_upload_request_body( $body, $file, $boundary, $file_name = '' ) {
$payload = '';
// add all body fields as standard POST fields:
foreach ( $body as $name => $value ) {
$payload .= '--' . $boundary;
$payload .= "\r\n";
$payload .= 'Content-Disposition: form-data; name="' . esc_attr( $name ) . '"' . "\r\n\r\n";
$payload .= $value;
$payload .= "\r\n";
}
if ( is_array( $file ) ) {
foreach ( $file as $key => $file_data ) {
$payload .= $this->get_file_payload( $file_data['name'], $file_data['type'], $file_data['path'], $boundary );
}
} else {
$image_mime = image_type_to_mime_type( exif_imagetype( $file ) );
// @todo: add validation for supported image types
if ( empty( $file_name ) ) {
$file_name = basename( $file );
}
$payload .= $this->get_file_payload( $file_name, $image_mime, $file, $boundary );
}
$payload .= '--' . $boundary . '--';
return $payload;
}
private function ai_request( $method, $endpoint, $body, $file = false, $file_name = '', $format = 'default' ) {
$headers = [
'x-elementor-ai-version' => '2',
];
if ( $file ) {
$boundary = wp_generate_password( 24, false );
$body = $this->get_upload_request_body( $body, $file, $boundary, $file_name );
// add content type header
$headers['Content-Type'] = 'multipart/form-data; boundary=' . $boundary;
} elseif ( 'json' === $format ) {
$headers['Content-Type'] = 'application/json';
$body = wp_json_encode( $body );
}
return $this->http_request(
$method,
$endpoint,
[
'timeout' => 100,
'headers' => $headers,
'body' => $body,
],
[
'return_type' => static::HTTP_RETURN_TYPE_ARRAY,
'with_error_data' => true,
]
);
}
public function set_get_started() {
return $this->ai_request(
'POST',
'status/get-started',
[
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
]
);
}
public function set_status_feedback( $response_id ) {
return $this->ai_request(
'POST',
'status/feedback/' . $response_id,
[
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
]
);
}
public function set_used_gallery_image( $image_id ) {
return $this->ai_request(
'POST',
'status/used-gallery-image/' . $image_id,
[
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
]
);
}
public function get_completion_text( $prompt, $context, $request_ids ) {
return $this->ai_request(
'POST',
'text/completion',
[
'prompt' => $prompt,
'context' => wp_json_encode( $context ),
'ids' => $request_ids,
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
],
false,
'',
'json'
);
}
public function get_excerpt( $prompt, $context, $request_ids ) {
$excerpt_length = apply_filters( 'excerpt_length', 55 );
return $this->ai_request(
'POST',
'text/get-excerpt',
[
'content' => $prompt,
'maxLength' => $excerpt_length,
'context' => wp_json_encode( $context ),
'ids' => $request_ids,
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
],
false,
'',
'json'
);
}
/**
* Get Image Prompt Enhanced get_image_prompt_enhanced
*
* @param $prompt
*
* @return mixed|\WP_Error
*/
public function get_image_prompt_enhanced( $prompt, $context, $request_ids ) {
return $this->ai_request(
'POST',
'text/enhance-image-prompt',
[
'prompt' => $prompt,
'context' => wp_json_encode( $context ),
'ids' => $request_ids,
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
]
);
}
public function get_edit_text( $data, $context, $request_ids ) {
return $this->ai_request(
'POST',
'text/edit',
[
'input' => $data['payload']['input'],
'instruction' => $data['payload']['instruction'],
'context' => wp_json_encode( $context ),
'ids' => $request_ids,
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
],
false,
'',
'json'
);
}
public function get_custom_code( $data, $context, $request_ids ) {
return $this->ai_request(
'POST',
'text/custom-code',
[
'prompt' => $data['payload']['prompt'],
'language' => $data['payload']['language'],
'context' => wp_json_encode( $context ),
'ids' => $request_ids,
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
],
false,
'',
'json'
);
}
public function get_custom_css( $data, $context, $request_ids ) {
return $this->ai_request(
'POST',
'text/custom-css',
[
'prompt' => $data['payload']['prompt'],
'html_markup' => $data['payload']['html_markup'],
'element_id' => $data['payload']['element_id'],
'context' => wp_json_encode( $context ),
'ids' => $request_ids,
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
],
false,
'',
'json'
);
}
/**
* Get text to image get_text_to_image
*
* @param $prompt
* @param $prompt_settings
*
* @return mixed|\WP_Error
*/
public function get_text_to_image( $data, $context, $request_ids ) {
return $this->ai_request(
'POST',
'image/text-to-image',
[
self::PROMPT => $data['payload']['prompt'],
self::IMAGE_TYPE => $data['payload']['settings'][ self::IMAGE_TYPE ] . '/' . $data['payload']['settings'][ self::STYLE_PRESET ],
self::ASPECT_RATIO => $data['payload']['settings'][ self::ASPECT_RATIO ],
'context' => wp_json_encode( $context ),
'ids' => $request_ids,
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
],
false,
'',
'json'
);
}
/**
* Get_Featured_Image get_featured_image
*
* @param $data
* @param $context
* @param $request_ids
* @return mixed|\WP_Error
*/
public function get_featured_image( $data, $context, $request_ids ) {
return $this->ai_request(
'POST',
'image/text-to-image/featured-image',
[
self::PROMPT => $data['payload']['prompt'],
self::IMAGE_TYPE => $data['payload']['settings'][ self::IMAGE_TYPE ] . '/' . $data['payload']['settings'][ self::STYLE_PRESET ],
self::ASPECT_RATIO => $data['payload']['settings'][ self::ASPECT_RATIO ],
'context' => wp_json_encode( $context ),
'ids' => $request_ids,
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
],
false,
'',
'json'
);
}
/**
* Get Image To Image get_image_to_image
*
* @param $image_data
* @param $context
* @param $request_ids
* @return mixed|\WP_Error
* @throws \Exception If image file not found.
*/
public function get_image_to_image( $image_data, $context, $request_ids ) {
$image_file = get_attached_file( $image_data['attachment_id'] );
if ( ! $image_file ) {
throw new \Exception( 'Image file not found' );
}
$result = $this->ai_request(
'POST',
'image/image-to-image',
[
self::PROMPT => $image_data[ self::PROMPT ],
self::IMAGE_TYPE => $image_data['promptSettings'][ self::IMAGE_TYPE ] . '/' . $image_data['promptSettings'][ self::STYLE_PRESET ],
self::IMAGE_STRENGTH => $image_data['promptSettings'][ self::IMAGE_STRENGTH ],
self::ASPECT_RATIO => $image_data['promptSettings'][ self::ASPECT_RATIO ],
'context' => wp_json_encode( $context ),
'ids' => $request_ids,
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
],
$image_file,
'image'
);
return $result;
}
private function resizeImageIfNeeded( $original_url ) {
try {
$max_file_size = 4194304;
$current_size = filesize( $original_url );
if ( $current_size <= $max_file_size ) {
return $original_url;
}
$image_editor = wp_get_image_editor( $original_url );
if ( is_wp_error( $image_editor ) ) {
return $original_url;
}
$dimensions = $image_editor->get_size();
$original_width = $dimensions['width'];
$original_height = $dimensions['height'];
$scaling_factor = sqrt( $max_file_size / $current_size );
$new_width = (int) ( $original_width * $scaling_factor );
$new_height = (int) ( $original_height * $scaling_factor );
$image_editor->resize( $new_width, $new_height, true );
$file_extension = pathinfo( $original_url, PATHINFO_EXTENSION );
$temp_image = tempnam( sys_get_temp_dir(), 'resized_' ) . '.' . $file_extension;
$image_editor->save( $temp_image );
return $temp_image;
} catch ( \Exception $e ) {
return $original_url;
}
}
public function get_unify_product_images( $image_data, $context, $request_ids ) {
$image_file = get_attached_file( $image_data['attachment_id'] );
if ( ! $image_file ) {
throw new \Exception( 'Image file not found' );
}
$final_path = $this->resizeImageIfNeeded( $image_file );
$result = $this->ai_request(
'POST',
'image/image-to-image/unify-product-images',
[
'aspectRatio' => $image_data['promptSettings'][ self::ASPECT_RATIO ],
'backgroundColor' => $image_data['promptSettings'][ self::IMAGE_BACKGROUND_COLOR ],
'featureIdentifier' => $image_data['featureIdentifier'],
'context' => wp_json_encode( $context ),
'ids' => $request_ids,
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
],
$final_path,
'image'
);
if ( $image_file !== $final_path ) {
unlink( $final_path );
}
return $result;
}
/**
* Get Image To Image Upscale get_image_to_image_upscale
*
* @param $image_data
* @param $context
* @param $request_ids
* @return mixed|\WP_Error
* @throws \Exception If image file not found.
*/
public function get_image_to_image_upscale( $image_data, $context, $request_ids ) {
$image_file = get_attached_file( $image_data['attachment_id'] );
if ( ! $image_file ) {
throw new \Exception( 'Image file not found' );
}
$result = $this->ai_request(
'POST',
'image/image-to-image/upscale',
[
self::IMAGE_RESOLUTION => $image_data['promptSettings']['upscale_to'],
'context' => wp_json_encode( $context ),
'ids' => $request_ids,
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
],
$image_file,
'image'
);
return $result;
}
/**
* Get Image To Image Remove Background get_image_to_image_remove_background
*
* @param $image_data
* @param $context
* @param $request_ids
* @return mixed|\WP_Error
* @throws \Exception If image file not found.
*/
public function get_image_to_image_remove_background( $image_data, $context, $request_ids ) {
$image_file = get_attached_file( $image_data['attachment_id'] );
if ( ! $image_file ) {
throw new \Exception( 'Image file not found' );
}
$result = $this->ai_request(
'POST',
'image/image-to-image/remove-background',
[
'context' => wp_json_encode( $context ),
'ids' => $request_ids,
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
],
$image_file,
'image'
);
return $result;
}
/**
* Get Image To Image Remove Text get_image_to_image_remove_text
*
* @param $image_data
* @param $context
* @param $request_ids
* @return mixed|\WP_Error
* @throws \Exception If image file not found.
*/
public function get_image_to_image_replace_background( $image_data, $context, $request_ids ) {
$image_file = get_attached_file( $image_data['attachment_id'] );
if ( ! $image_file ) {
throw new \Exception( 'Image file not found' );
}
$result = $this->ai_request(
'POST',
'image/image-to-image/replace-background',
[
self::PROMPT => $image_data[ self::PROMPT ],
'context' => wp_json_encode( $context ),
'ids' => $request_ids,
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
],
$image_file,
'image'
);
return $result;
}
/**
* Store Temp File store_temp_file
* used to store a temp file for the AI request and deletes it once the request is done
*
* @param $file_content
* @param $file_ext
*
* @return string
*/
private function store_temp_file( $file_content, $file_ext = '' ) {
$temp_file = str_replace( '.tmp', '', wp_tempnam() . $file_ext );
file_put_contents( $temp_file, $file_content );
// make sure the temp file is deleted on shutdown
register_shutdown_function( function () use ( $temp_file ) {
if ( file_exists( $temp_file ) ) {
unlink( $temp_file );
}
} );
return $temp_file;
}
/**
* Get Image To Image Out Painting get_image_to_image_out_painting
*
* @param $image_data
* @param $context
* @param $request_ids
* @return mixed|\WP_Error
* @throws \Exception If image file not found.
*/
public function get_image_to_image_out_painting( $image_data, $context, $request_ids ) {
$img_content = str_replace( ' ', '+', $image_data['mask'] );
$img_content = substr( $img_content, strpos( $img_content, ',' ) + 1 );
$img_content = base64_decode( $img_content );
$mask_file = $this->store_temp_file( $img_content, '.png' );
if ( ! $mask_file ) {
throw new \Exception( 'Expended Image file not found' );
}
$result = $this->ai_request(
'POST',
'image/image-to-image/outpainting',
[
'context' => wp_json_encode( $context ),
'ids' => $request_ids,
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
'size' => wp_json_encode( $image_data['size'] ),
'position' => wp_json_encode( $image_data['position'] ),
'image_base64' => $image_data['image_base64'],
$image_data['image'],
],
[
[
'name' => 'image',
'type' => 'image',
'path' => $mask_file,
],
]
);
return $result;
}
/**
* Get Image To Image Mask get_image_to_image_mask
*
* @param $image_data
* @param $context
* @param $request_ids
* @return mixed|\WP_Error
* @throws \Exception If image file not found.
*/
public function get_image_to_image_mask( $image_data, $context, $request_ids ) {
$image_file = get_attached_file( $image_data['attachment_id'] );
$mask_file = $this->store_temp_file( $image_data['mask'], '.svg' );
if ( ! $image_file ) {
throw new \Exception( 'Image file not found' );
}
if ( ! $mask_file ) {
throw new \Exception( 'Mask file not found' );
}
$result = $this->ai_request(
'POST',
'image/image-to-image/inpainting',
[
self::PROMPT => $image_data[ self::PROMPT ],
'context' => wp_json_encode( $context ),
'ids' => $request_ids,
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
'image_base64' => $image_data['image_base64'],
],
[
[
'name' => 'image',
'type' => 'image',
'path' => $image_file,
],
[
'name' => 'mask_image',
'type' => 'image/svg+xml',
'path' => $mask_file,
],
]
);
return $result;
}
public function get_image_to_image_mask_cleanup( $image_data, $context, $request_ids ) {
$image_file = get_attached_file( $image_data['attachment_id'] );
$mask_file = $this->store_temp_file( $image_data['mask'], '.svg' );
if ( ! $image_file ) {
throw new \Exception( 'Image file not found' );
}
if ( ! $mask_file ) {
throw new \Exception( 'Mask file not found' );
}
$result = $this->ai_request(
'POST',
'image/image-to-image/cleanup',
[
self::PROMPT => $image_data[ self::PROMPT ],
'context' => wp_json_encode( $context ),
'ids' => $request_ids,
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
'image_base64' => $image_data['image_base64'],
],
[
[
'name' => 'image',
'type' => 'image',
'path' => $image_file,
],
[
'name' => 'mask_image',
'type' => 'image/svg+xml',
'path' => $mask_file,
],
]
);
return $result;
}
public function generate_layout( $data, $context ) {
$endpoint = 'generate/layout';
$body = [
'prompt' => $data['prompt'],
'variationType' => (int) $data['variationType'],
'ids' => $data['ids'],
];
if ( ! empty( $data['prevGeneratedIds'] ) ) {
$body['generatedBaseTemplatesIds'] = $data['prevGeneratedIds'];
}
if ( ! empty( $data['attachments'] ) ) {
$attachment = $data['attachments'][0];
switch ( $attachment['type'] ) {
case 'json':
$endpoint = 'generate/generate-json-variation';
$body['json'] = [
'type' => 'elementor',
'elements' => [ $attachment['content'] ],
'label' => $attachment['label'],
'source' => $attachment['source'],
];
break;
case 'url':
$endpoint = 'generate/html-to-elementor';
$html = wp_json_encode( $attachment['content'] );
$body['html'] = $html;
$body['htmlFetchedUrl'] = $attachment['label'];
break;
}
}
$context['currentContext'] = $data['currentContext'];
$context['features'] = [
'supportedFeatures' => [ 'Taxonomy' ],
];
if ( ElementorUtils::has_pro() ) {
$context['features']['subscriptions'] = [ 'Pro' ];
}
if ( Plugin::instance()->experiments->get_active_features()['nested-elements'] ) {
$context['features']['supportedFeatures'][] = 'Nested';
}
if ( Plugin::instance()->experiments->get_active_features()['mega-menu'] ) {
$context['features']['supportedFeatures'][] = 'MegaMenu';
}
if ( class_exists( 'WC' ) ) {
$context['features']['supportedFeatures'][] = 'WooCommerce';
}
$metadata = [
'context' => $context,
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
'config' => [
'generate' => [
'all' => true,
],
],
];
$body = array_merge( $body, $metadata );
// Temp hack for platforms that filters the http_request_args, and it breaks JSON requests.
remove_all_filters( 'http_request_args' );
return $this->ai_request(
'POST',
$endpoint,
$body,
false,
'',
'json'
);
}
public function get_layout_prompt_enhanced( $prompt, $enhance_type, $context ) {
return $this->ai_request(
'POST',
'generate/enhance-prompt',
[
'prompt' => $prompt,
'enhance_type' => $enhance_type,
'context' => wp_json_encode( $context ),
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
],
false,
'',
'json'
);
}
public function get_history_by_type( $type, $page, $limit, $context = [] ) {
$endpoint = Module::HISTORY_TYPE_ALL === $type
? 'history'
: add_query_arg( [
'page' => $page,
'limit' => $limit,
], "history/{$type}" );
return $this->ai_request(
'POST',
$endpoint,
[
'context' => wp_json_encode( $context ),
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
]
);
}
public function delete_history_item( $id, $context = [] ) {
return $this->ai_request(
'DELETE', 'history/' . $id,
[
'context' => wp_json_encode( $context ),
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
]
);
}
public function toggle_favorite_history_item( $id, $context = [] ) {
return $this->ai_request(
'POST', sprintf( 'history/%s/favorite', $id ),
[
'context' => wp_json_encode( $context ),
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
]
);
}
public function get_animation( $data, $context, $request_ids ) {
return $this->ai_request(
'POST',
'text/get-motion-effect',
[
'prompt' => $data['payload']['prompt'],
'motionEffectType' => $data['payload']['motionEffectType'],
'context' => wp_json_encode( $context ),
'ids' => $request_ids,
'api_version' => ELEMENTOR_VERSION,
'site_lang' => get_bloginfo( 'language' ),
],
false,
'',
'json'
);
}
protected function init() {}
}
module.php 0000644 00000126770 15156145315 0006565 0 ustar 00 register();
add_action( 'elementor/import-export/import-kit/runner/after-run', [ $this, 'handle_kit_install' ] );
}
if ( ! $this->is_ai_enabled() ) {
return;
}
add_filter( 'elementor/core/admin/homescreen', [ $this, 'add_create_with_ai_banner_to_homescreen' ] );
add_action( 'elementor/connect/apps/register', function ( ConnectModule $connect_module ) {
$connect_module->register_app( 'ai', Ai::get_class_name() );
} );
add_action( 'elementor/ajax/register_actions', function( $ajax ) {
$handlers = [
'ai_get_user_information' => [ $this, 'ajax_ai_get_user_information' ],
'ai_get_remote_config' => [ $this, 'ajax_ai_get_remote_config' ],
'ai_get_remote_frontend_config' => [ $this, 'ajax_ai_get_remote_frontend_config' ],
'ai_get_completion_text' => [ $this, 'ajax_ai_get_completion_text' ],
'ai_get_excerpt' => [ $this, 'ajax_ai_get_excerpt' ],
'ai_get_featured_image' => [ $this, 'ajax_ai_get_featured_image' ],
'ai_get_edit_text' => [ $this, 'ajax_ai_get_edit_text' ],
'ai_get_custom_code' => [ $this, 'ajax_ai_get_custom_code' ],
'ai_get_custom_css' => [ $this, 'ajax_ai_get_custom_css' ],
'ai_set_get_started' => [ $this, 'ajax_ai_set_get_started' ],
'ai_set_status_feedback' => [ $this, 'ajax_ai_set_status_feedback' ],
'ai_get_image_prompt_enhancer' => [ $this, 'ajax_ai_get_image_prompt_enhancer' ],
'ai_get_text_to_image' => [ $this, 'ajax_ai_get_text_to_image' ],
'ai_get_image_to_image' => [ $this, 'ajax_ai_get_image_to_image' ],
'ai_get_image_to_image_mask' => [ $this, 'ajax_ai_get_image_to_image_mask' ],
'ai_get_image_to_image_mask_cleanup' => [ $this, 'ajax_ai_get_image_to_image_mask_cleanup' ],
'ai_get_image_to_image_outpainting' => [ $this, 'ajax_ai_get_image_to_image_outpainting' ],
'ai_get_image_to_image_upscale' => [ $this, 'ajax_ai_get_image_to_image_upscale' ],
'ai_get_image_to_image_remove_background' => [ $this, 'ajax_ai_get_image_to_image_remove_background' ],
'ai_get_image_to_image_replace_background' => [ $this, 'ajax_ai_get_image_to_image_replace_background' ],
'ai_upload_image' => [ $this, 'ajax_ai_upload_image' ],
'ai_generate_layout' => [ $this, 'ajax_ai_generate_layout' ],
'ai_get_layout_prompt_enhancer' => [ $this, 'ajax_ai_get_layout_prompt_enhancer' ],
'ai_get_history' => [ $this, 'ajax_ai_get_history' ],
'ai_delete_history_item' => [ $this, 'ajax_ai_delete_history_item' ],
'ai_toggle_favorite_history_item' => [ $this, 'ajax_ai_toggle_favorite_history_item' ],
'ai_get_product_image_unification' => [ $this, 'ajax_ai_get_product_image_unification' ],
'ai_get_animation' => [ $this, 'ajax_ai_get_animation' ],
'ai_get_image_to_image_isolate_objects' => [ $this, 'ajax_ai_get_product_image_unification' ],
];
foreach ( $handlers as $tag => $callback ) {
$ajax->register_ajax_action( $tag, $callback );
}
} );
add_action( 'elementor/editor/before_enqueue_scripts', function() {
$this->enqueue_main_script();
$this->enqueue_layout_script();
} );
add_action( 'elementor/editor/after_enqueue_styles', function() {
wp_enqueue_style(
'elementor-ai-editor',
$this->get_css_assets_url( 'modules/ai/editor' ),
[],
ELEMENTOR_VERSION
);
} );
add_action( 'elementor/preview/enqueue_styles', function() {
wp_enqueue_style(
'elementor-ai-layout-preview',
$this->get_css_assets_url( 'modules/ai/layout-preview' ),
[],
ELEMENTOR_VERSION
);
} );
if ( is_admin() ) {
add_action( 'wp_enqueue_media', [ $this, 'enqueue_ai_media_library' ] );
add_action( 'admin_head', [ $this, 'enqueue_ai_media_library_upload_screen' ] );
if ( current_user_can( 'edit_products' ) || current_user_can( 'publish_products' ) ) {
add_action( 'admin_init', [ $this, 'enqueue_ai_products_page_scripts' ] );
add_action( 'current_screen', [ $this, 'enqueue_ai_single_product_page_scripts' ] );
add_action( 'wp_ajax_elementor-ai-get-product-images', [ $this, 'get_product_images_ajax' ] );
add_action( 'wp_ajax_elementor-ai-set-product-images', [ $this, 'set_product_images_ajax' ] );
Product_Image_Unification_Intro::add_hooks();
}
}
add_action( 'enqueue_block_editor_assets', function() {
wp_enqueue_script( 'elementor-ai-gutenberg',
$this->get_js_assets_url( 'ai-gutenberg' ),
[
'jquery',
'elementor-v2-ui',
'elementor-v2-icons',
'wp-blocks',
'wp-element',
'wp-editor',
'wp-data',
'wp-components',
'wp-compose',
'wp-i18n',
'wp-hooks',
'elementor-ai-media-library',
],
ELEMENTOR_VERSION, true );
wp_localize_script(
'elementor-ai-gutenberg',
'ElementorAiConfig',
[
'is_get_started' => User::get_introduction_meta( 'ai_get_started' ),
'connect_url' => $this->get_ai_connect_url(),
]
);
wp_set_script_translations( 'elementor-ai-gutenberg', 'elementor' );
});
add_filter( 'elementor/document/save/data', function ( $data ) {
return $this->remove_temporary_containers( $data );
} );
add_action( 'elementor/element/common/section_effects/after_section_start', [ $this, 'register_ai_motion_effect_control' ], 10, 1 );
add_action( 'elementor/element/container/section_effects/after_section_start', [ $this, 'register_ai_motion_effect_control' ], 10, 1 );
add_action( 'elementor/element/common/_section_transform/after_section_end', [ $this, 'register_ai_hover_effect_control' ], 10, 1 );
add_action( 'elementor/element/container/_section_transform/after_section_end', [ $this, 'register_ai_hover_effect_control' ], 10, 1 );
}
public function is_ai_enabled() {
if ( ! Plugin::$instance->experiments->is_feature_active( 'container' ) ) {
return false;
}
return Preferences::is_ai_enabled( get_current_user_id() );
}
public function handle_kit_install( $imported_data ) {
if ( ! $this->is_ai_enabled() ) {
return;
}
if ( ! isset( $imported_data['status'] ) || 'success' !== $imported_data['status'] ) {
return;
}
if ( ! isset( $imported_data['runner'] ) || 'site-settings' !== $imported_data['runner'] ) {
return;
}
if ( ! isset( $imported_data['configData']['lastImportedSession']['instance_data']['site_settings']['settings']['ai'] ) ) {
return;
}
$is_connected = $this->get_ai_app()->is_connected() && User::get_introduction_meta( 'ai_get_started' );
if ( ! $is_connected ) {
return;
}
$last_imported_session = $imported_data['configData']['lastImportedSession'];
$imported_ai_data = $last_imported_session['instance_data']['site_settings']['settings']['ai'];
$this->get_ai_app()->send_event( [
'name' => 'kit_installed',
'data' => $imported_ai_data,
'client' => [
'name' => 'elementor',
'version' => ELEMENTOR_VERSION,
'session_id' => $last_imported_session['session_id'],
],
] );
}
public function register_ai_hover_effect_control( Element_Base $element ) {
if ( ! $element->get_controls( 'ai_hover_animation' ) ) {
$element->add_control(
'ai_hover_animation',
[
'tabs_wrapper' => '_tabs_positioning',
'inner_tab' => '_tab_positioning_hover',
'label' => esc_html__( 'Animate With AI', 'elementor' ),
'type' => Controls_Manager::RAW_HTML,
'raw' => '
',
'render_type' => 'none',
'ai' => [
'active' => true,
'type' => 'hover_animation',
],
],
[
'position' => [
'of' => '_transform_rotate_popover_hover',
'type' => 'control',
'at' => 'before',
],
]
);
}
}
public function register_ai_motion_effect_control( $element ) {
if ( Utils::has_pro() && ! $element->get_controls( 'ai_animation' ) ) {
$element->add_control(
'ai_animation',
[
'label' => esc_html__( 'Animate With AI', 'elementor' ),
'type' => Controls_Manager::RAW_HTML,
'raw' => '
',
'render_type' => 'none',
'ai' => [
'active' => true,
'type' => 'animation',
],
]
);
}
}
private function get_current_screen() {
$is_wc = class_exists( 'WooCommerce' ) && post_type_exists( 'product' );
if ( ! $is_wc ) {
return 'other';
}
$is_products_page = isset( $_GET['post_type'] ) && 'product' === $_GET['post_type'];
if ( $is_products_page ) {
return 'wc-products';
}
$screen = get_current_screen();
$is_single_product_page = isset( $screen->post_type ) && ( 'product' === $screen->post_type && 'post' === $screen->base );
if ( $is_single_product_page ) {
return 'wc-single-product';
}
return 'other';
}
public function enqueue_ai_products_page_scripts() {
if ( 'wc-products' !== $this->get_current_screen() ) {
return;
}
$this->add_wc_scripts();
}
public function enqueue_ai_single_product_page_scripts() {
if ( 'wc-single-product' !== $this->get_current_screen() ) {
return;
}
$this->add_wc_scripts();
}
private function add_products_bulk_action( $bulk_actions ) {
$bulk_actions['elementor-ai-unify-product-images'] = __( 'Unify with Elementor AI', 'elementor' );
return $bulk_actions;
}
public function get_product_images_ajax() {
check_ajax_referer( 'elementor-ai-unify-product-images_nonce', 'nonce' );
$post_ids = isset( $_POST['post_ids'] ) ? array_map( 'intval', $_POST['post_ids'] ) : [];
$is_galley_only = isset( $_POST['is_galley_only'] ) && sanitize_text_field( wp_unslash( $_POST['is_galley_only'] ) );
$image_ids = [];
foreach ( $post_ids as $post_id ) {
if ( $is_galley_only ) {
$product = wc_get_product( $post_id );
$gallery_image_ids = $product->get_gallery_image_ids();
foreach ( $gallery_image_ids as $image_id ) {
$image_ids[] = [
'productId' => $post_id,
'id' => $image_id,
'image_url' => wp_get_attachment_url( $image_id ),
];
}
continue;
}
$image_id = get_post_thumbnail_id( $post_id );
if ( ! $image_id ) {
$product = wc_get_product( $post_id );
$gallery_image_ids = $product->get_gallery_image_ids();
if ( ! empty( $gallery_image_ids ) ) {
$image_id = $gallery_image_ids[0];
}
}
$image_ids[] = [
'productId' => $post_id,
'id' => $image_id ? $image_id : 'No Image',
'image_url' => $image_id ? wp_get_attachment_url( $image_id ) : 'No Image',
];
}
wp_send_json_success( [ 'product_images' => array_slice( $image_ids, 0, 10 ) ] );
wp_die();
}
private function get_attachment_id_by_url( $url ) {
$attachments = get_posts( [
'post_type' => 'attachment',
'meta_query' => [
[
'key' => '_wp_attached_file',
'value' => basename( $url ),
'compare' => 'LIKE',
],
],
'fields' => 'ids',
'numberposts' => 1,
] );
return ! empty( $attachments ) ? $attachments[0] : null;
}
public function set_product_images_ajax() {
check_ajax_referer( 'elementor-ai-unify-product-images_nonce', 'nonce' );
$product_id = isset( $_POST['productId'] ) ? sanitize_text_field( wp_unslash( $_POST['productId'] ) ) : '';
$image_url = isset( $_POST['image_url'] ) ? sanitize_text_field( wp_unslash( $_POST['image_url'] ) ) : '';
$image_to_add = isset( $_POST['image_to_add'] ) ? intval( wp_unslash( $_POST['image_to_add'] ) ) : null;
$image_to_remove = isset( $_POST['image_to_remove'] ) ? intval( wp_unslash( $_POST['image_to_remove'] ) ) : null;
$is_product_gallery = isset( $_POST['is_product_gallery'] ) && sanitize_text_field( wp_unslash( $_POST['is_product_gallery'] ) ) === 'true';
if ( ! $product_id || ! $image_url ) {
throw new \Exception( 'Product ID and Image URL are required' );
}
$product = wc_get_product( $product_id );
if ( ! $product ) {
throw new \Exception( 'Product not found' );
}
$attachment_id = $this->get_attachment_id_by_url( $image_url );
if ( is_wp_error( $attachment_id ) ) {
throw new \Exception( 'Image upload failed' );
}
if ( $is_product_gallery ) {
$this->update_product_gallery( $product, $image_to_remove, $image_to_add );
} else {
$product->set_image_id( $attachment_id );
$product->save();
}
wp_send_json_success( [
'message' => __( 'Image added successfully', 'elementor' ),
] );
}
public function enqueue_ai_media_library_upload_screen() {
$screen = get_current_screen();
if ( ! $screen || 'upload' !== $screen->id ) {
return;
}
$this->enqueue_ai_media_library();
}
public function enqueue_ai_media_library() {
wp_enqueue_script( 'elementor-ai-media-library',
$this->get_js_assets_url( 'ai-media-library' ),
[
'jquery',
'elementor-v2-ui',
'elementor-v2-icons',
'media-grid',
],
ELEMENTOR_VERSION,
true
);
wp_localize_script(
'elementor-ai-media-library',
'ElementorAiConfig',
[
'is_get_started' => User::get_introduction_meta( 'ai_get_started' ),
'connect_url' => $this->get_ai_connect_url(),
]
);
wp_set_script_translations( 'elementor-ai-media-library', 'elementor' );
}
private function enqueue_main_script() {
wp_enqueue_script(
'elementor-ai',
$this->get_js_assets_url( 'ai' ),
[
'react',
'react-dom',
'backbone-marionette',
'elementor-web-cli',
'wp-date',
'elementor-common',
'elementor-editor-modules',
'elementor-editor-document',
'elementor-v2-ui',
'elementor-v2-icons',
],
ELEMENTOR_VERSION,
true
);
$config = [
'is_get_started' => User::get_introduction_meta( 'ai_get_started' ),
'connect_url' => $this->get_ai_connect_url(),
];
wp_localize_script(
'elementor-ai',
'ElementorAiConfig',
$config
);
wp_set_script_translations( 'elementor-ai', 'elementor' );
}
private function enqueue_layout_script() {
wp_enqueue_script(
'elementor-ai-layout',
$this->get_js_assets_url( 'ai-layout' ),
[
'react',
'react-dom',
'backbone-marionette',
'elementor-common',
'elementor-web-cli',
'elementor-editor-modules',
'elementor-ai',
'elementor-v2-ui',
'elementor-v2-icons',
],
ELEMENTOR_VERSION,
true
);
wp_set_script_translations( 'elementor-ai-layout', 'elementor' );
}
private function remove_temporary_containers( $data ) {
if ( empty( $data['elements'] ) || ! is_array( $data['elements'] ) ) {
return $data;
}
// If for some reason the document has been saved during an AI Layout session,
// ensure that the temporary containers are removed from the data.
$data['elements'] = array_filter( $data['elements'], function( $element ) {
$is_preview_container = strpos( $element['id'], 'e-ai-preview-container' ) === 0;
$is_screenshot_container = strpos( $element['id'], 'e-ai-screenshot-container' ) === 0;
return ! $is_preview_container && ! $is_screenshot_container;
} );
return $data;
}
private function get_ai_connect_url() {
$app = $this->get_ai_app();
return $app->get_admin_url( 'authorize', [
'utm_source' => 'ai-popup',
'utm_campaign' => 'connect-account',
'utm_medium' => 'wp-dash',
'source' => 'generic',
] );
}
public function ajax_ai_get_user_information( $data ) {
$app = $this->get_ai_app();
if ( ! $app->is_connected() ) {
return [
'is_connected' => false,
'connect_url' => $this->get_ai_connect_url(),
];
}
$user_usage = wp_parse_args( $app->get_usage(), [
'hasAiSubscription' => false,
'usedQuota' => 0,
'quota' => 100,
] );
return [
'is_connected' => true,
'is_get_started' => User::get_introduction_meta( 'ai_get_started' ),
'usage' => $user_usage,
];
}
public function ajax_ai_get_remote_config() {
$app = $this->get_ai_app();
if ( ! $app->is_connected() ) {
return [];
}
return $app->get_remote_config();
}
public function ajax_ai_get_remote_frontend_config( $data ) {
$callback = function () use ( $data ) {
return $this->get_ai_app()->get_remote_frontend_config( $data );
};
return Utils::get_cached_callback( $callback, 'ai_remote_frontend_config-' . get_current_user_id(), HOUR_IN_SECONDS );
}
public function verify_upload_permissions( $data ) {
$referer = wp_get_referer();
if ( str_contains( $referer, 'wp-admin/upload.php' ) && current_user_can( 'upload_files' ) ) {
return;
}
$this->verify_permissions( $data['editor_post_id'] );
}
private function verify_permissions( $editor_post_id ) {
$document = Plugin::$instance->documents->get( $editor_post_id );
if ( ! $document ) {
throw new \Exception( 'Document not found' );
}
if ( $document->is_built_with_elementor() ) {
if ( ! $document->is_editable_by_current_user() ) {
throw new \Exception( 'Access denied' );
}
} elseif ( ! current_user_can( 'edit_post', $editor_post_id ) ) {
throw new \Exception( 'Access denied' );
}
}
public function ajax_ai_get_image_prompt_enhancer( $data ) {
$this->verify_upload_permissions( $data );
$app = $this->get_ai_app();
if ( empty( $data['prompt'] ) ) {
throw new \Exception( 'Missing prompt' );
}
if ( ! $app->is_connected() ) {
throw new \Exception( 'not_connected' );
}
$request_ids = $this->get_request_ids( $data['payload'] );
$result = $app->get_image_prompt_enhanced( $data['prompt'], [], $request_ids );
$this->throw_on_error( $result );
return [
'text' => $result['text'],
'response_id' => $result['responseId'],
'usage' => $result['usage'],
];
}
public function ajax_ai_get_completion_text( $data ) {
$this->verify_permissions( $data['editor_post_id'] );
$app = $this->get_ai_app();
if ( empty( $data['payload']['prompt'] ) ) {
throw new \Exception( 'Missing prompt' );
}
if ( ! $app->is_connected() ) {
throw new \Exception( 'not_connected' );
}
$context = $this->get_request_context( $data );
$request_ids = $this->get_request_ids( $data['payload'] );
$result = $app->get_completion_text( $data['payload']['prompt'], $context, $request_ids );
$this->throw_on_error( $result );
return [
'text' => $result['text'],
'response_id' => $result['responseId'],
'usage' => $result['usage'],
];
}
public function ajax_ai_get_excerpt( $data ): array {
$app = $this->get_ai_app();
if ( empty( $data['payload']['content'] ) ) {
throw new \Exception( 'Missing content' );
}
if ( ! $app->is_connected() ) {
throw new \Exception( 'Not connected' );
}
$context = $this->get_request_context( $data );
$request_ids = $this->get_request_ids( $data['payload'] );
$result = $app->get_excerpt( $data['payload']['content'], $context, $request_ids );
$this->throw_on_error( $result );
return [
'text' => $result['text'],
'response_id' => $result['responseId'],
'usage' => $result['usage'],
];
}
public function ajax_ai_get_featured_image( $data ): array {
$this->verify_upload_permissions( $data );
if ( empty( $data['payload']['prompt'] ) ) {
throw new \Exception( 'Missing prompt' );
}
$app = $this->get_ai_app();
if ( ! $app->is_connected() ) {
throw new \Exception( 'not_connected' );
}
$context = $this->get_request_context( $data );
$request_ids = $this->get_request_ids( $data['payload'] );
$result = $app->get_featured_image( $data, $context, $request_ids );
$this->throw_on_error( $result );
return [
'images' => $result['images'],
'response_id' => $result['responseId'],
'usage' => $result['usage'],
];
}
private function get_ai_app(): Ai {
return Plugin::$instance->common->get_component( 'connect' )->get_app( 'ai' );
}
private function get_request_context( $data ) {
if ( empty( $data['context'] ) ) {
return [];
}
return $data['context'];
}
private function get_request_ids( $data ) {
if ( empty( $data['requestIds'] ) ) {
return new \stdClass();
}
return $data['requestIds'];
}
public function ajax_ai_get_edit_text( $data ) {
$this->verify_permissions( $data['editor_post_id'] );
$app = $this->get_ai_app();
if ( empty( $data['payload']['input'] ) ) {
throw new \Exception( 'Missing input' );
}
if ( empty( $data['payload']['instruction'] ) ) {
throw new \Exception( 'Missing instruction' );
}
if ( ! $app->is_connected() ) {
throw new \Exception( 'not_connected' );
}
$context = $this->get_request_context( $data );
$request_ids = $this->get_request_ids( $data['payload'] );
$result = $app->get_edit_text( $data, $context, $request_ids );
$this->throw_on_error( $result );
return [
'text' => $result['text'],
'response_id' => $result['responseId'],
'usage' => $result['usage'],
];
}
public function ajax_ai_get_custom_code( $data ) {
$app = $this->get_ai_app();
if ( empty( $data['payload']['prompt'] ) ) {
throw new \Exception( 'Missing prompt' );
}
if ( empty( $data['payload']['language'] ) ) {
throw new \Exception( 'Missing language' );
}
if ( ! $app->is_connected() ) {
throw new \Exception( 'not_connected' );
}
$context = $this->get_request_context( $data );
$request_ids = $this->get_request_ids( $data['payload'] );
$result = $app->get_custom_code( $data, $context, $request_ids );
$this->throw_on_error( $result );
return [
'text' => $result['text'],
'response_id' => $result['responseId'],
'usage' => $result['usage'],
];
}
public function ajax_ai_get_custom_css( $data ) {
$this->verify_permissions( $data['editor_post_id'] );
$app = $this->get_ai_app();
if ( empty( $data['payload']['prompt'] ) ) {
throw new \Exception( 'Missing prompt' );
}
if ( empty( $data['payload']['html_markup'] ) ) {
$data['html_markup'] = '';
}
if ( empty( $data['payload']['element_id'] ) ) {
throw new \Exception( 'Missing element_id' );
}
if ( ! $app->is_connected() ) {
throw new \Exception( 'not_connected' );
}
$context = $this->get_request_context( $data );
$request_ids = $this->get_request_ids( $data['payload'] );
$result = $app->get_custom_css( $data, $context, $request_ids );
$this->throw_on_error( $result );
return [
'text' => $result['text'],
'response_id' => $result['responseId'],
'usage' => $result['usage'],
];
}
public function ajax_ai_set_get_started( $data ) {
$app = $this->get_ai_app();
User::set_introduction_viewed( [
'introductionKey' => 'ai_get_started',
] );
return $app->set_get_started();
}
public function ajax_ai_set_status_feedback( $data ) {
if ( empty( $data['response_id'] ) ) {
throw new \Exception( 'Missing response_id' );
}
$app = $this->get_ai_app();
if ( ! $app->is_connected() ) {
throw new \Exception( 'not_connected' );
}
$app->set_status_feedback( $data['response_id'] );
return [];
}
public function ajax_ai_get_text_to_image( $data ) {
$this->verify_upload_permissions( $data );
if ( empty( $data['payload']['prompt'] ) ) {
throw new \Exception( 'Missing prompt' );
}
$app = $this->get_ai_app();
if ( ! $app->is_connected() ) {
throw new \Exception( 'not_connected' );
}
$context = $this->get_request_context( $data );
$request_ids = $this->get_request_ids( $data['payload'] );
$result = $app->get_text_to_image( $data, $context, $request_ids );
$this->throw_on_error( $result );
return [
'images' => $result['images'],
'response_id' => $result['responseId'],
'usage' => $result['usage'],
];
}
public function ajax_ai_get_image_to_image( $data ) {
$this->verify_upload_permissions( $data );
$app = $this->get_ai_app();
if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) {
throw new \Exception( 'Missing Image' );
}
if ( empty( $data['payload']['settings'] ) ) {
throw new \Exception( 'Missing prompt settings' );
}
if ( ! $app->is_connected() ) {
throw new \Exception( 'not_connected' );
}
$context = $this->get_request_context( $data );
$request_ids = $this->get_request_ids( $data['payload'] );
$result = $app->get_image_to_image( [
'prompt' => $data['payload']['prompt'],
'promptSettings' => $data['payload']['settings'],
'attachment_id' => $data['payload']['image']['id'],
], $context, $request_ids );
$this->throw_on_error( $result );
return [
'images' => $result['images'],
'response_id' => $result['responseId'],
'usage' => $result['usage'],
];
}
public function ajax_ai_get_image_to_image_upscale( $data ) {
$this->verify_upload_permissions( $data );
$app = $this->get_ai_app();
if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) {
throw new \Exception( 'Missing Image' );
}
if ( empty( $data['payload']['promptSettings'] ) ) {
throw new \Exception( 'Missing prompt settings' );
}
if ( ! $app->is_connected() ) {
throw new \Exception( 'not_connected' );
}
$context = $this->get_request_context( $data );
$request_ids = $this->get_request_ids( $data['payload'] );
$result = $app->get_image_to_image_upscale( [
'promptSettings' => $data['payload']['promptSettings'],
'attachment_id' => $data['payload']['image']['id'],
], $context, $request_ids );
$this->throw_on_error( $result );
return [
'images' => $result['images'],
'response_id' => $result['responseId'],
'usage' => $result['usage'],
];
}
public function ajax_ai_get_image_to_image_replace_background( $data ) {
$this->verify_upload_permissions( $data );
$app = $this->get_ai_app();
if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) {
throw new \Exception( 'Missing Image' );
}
if ( empty( $data['payload']['prompt'] ) ) {
throw new \Exception( 'Prompt Missing' );
}
if ( ! $app->is_connected() ) {
throw new \Exception( 'not_connected' );
}
$context = $this->get_request_context( $data );
$request_ids = $this->get_request_ids( $data['payload'] );
$result = $app->get_image_to_image_replace_background( [
'attachment_id' => $data['payload']['image']['id'],
'prompt' => $data['payload']['prompt'],
], $context, $request_ids );
$this->throw_on_error( $result );
return [
'images' => $result['images'],
'response_id' => $result['responseId'],
'usage' => $result['usage'],
];
}
public function ajax_ai_get_image_to_image_remove_background( $data ) {
$this->verify_upload_permissions( $data );
$app = $this->get_ai_app();
if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) {
throw new \Exception( 'Missing Image' );
}
if ( ! $app->is_connected() ) {
throw new \Exception( 'not_connected' );
}
$context = $this->get_request_context( $data );
$request_ids = $this->get_request_ids( $data['payload'] );
$result = $app->get_image_to_image_remove_background( [
'attachment_id' => $data['payload']['image']['id'],
], $context, $request_ids );
$this->throw_on_error( $result );
return [
'images' => $result['images'],
'response_id' => $result['responseId'],
'usage' => $result['usage'],
];
}
public function ajax_ai_get_image_to_image_mask( $data ) {
$this->verify_upload_permissions( $data );
$app = $this->get_ai_app();
if ( empty( $data['payload']['prompt'] ) ) {
throw new \Exception( 'Missing prompt' );
}
if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) {
throw new \Exception( 'Missing Image' );
}
if ( empty( $data['payload']['settings'] ) ) {
throw new \Exception( 'Missing prompt settings' );
}
if ( empty( $data['payload']['mask'] ) ) {
throw new \Exception( 'Missing Mask' );
}
$context = $this->get_request_context( $data );
$request_ids = $this->get_request_ids( $data['payload'] );
$result = $app->get_image_to_image_mask( [
'prompt' => $data['payload']['prompt'],
'attachment_id' => $data['payload']['image']['id'],
'mask' => $data['payload']['mask'],
], $context, $request_ids );
$this->throw_on_error( $result );
return [
'images' => $result['images'],
'response_id' => $result['responseId'],
'usage' => $result['usage'],
];
}
public function ajax_ai_get_image_to_image_mask_cleanup( $data ) {
$this->verify_upload_permissions( $data );
$app = $this->get_ai_app();
if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) {
throw new \Exception( 'Missing Image' );
}
if ( empty( $data['payload']['settings'] ) ) {
throw new \Exception( 'Missing prompt settings' );
}
if ( ! $app->is_connected() ) {
throw new \Exception( 'not_connected' );
}
if ( empty( $data['payload']['mask'] ) ) {
throw new \Exception( 'Missing Mask' );
}
$context = $this->get_request_context( $data );
$request_ids = $this->get_request_ids( $data['payload'] );
$result = $app->get_image_to_image_mask_cleanup( [
'attachment_id' => $data['payload']['image']['id'],
'mask' => $data['payload']['mask'],
], $context, $request_ids );
$this->throw_on_error( $result );
return [
'images' => $result['images'],
'response_id' => $result['responseId'],
'usage' => $result['usage'],
];
}
public function ajax_ai_get_image_to_image_outpainting( $data ) {
$this->verify_upload_permissions( $data );
$app = $this->get_ai_app();
if ( ! $app->is_connected() ) {
throw new \Exception( 'not_connected' );
}
if ( empty( $data['payload']['mask'] ) ) {
throw new \Exception( 'Missing Expended Image' );
}
$context = $this->get_request_context( $data );
$request_ids = $this->get_request_ids( $data['payload'] );
$result = $app->get_image_to_image_out_painting( [
'size' => $data['payload']['size'],
'position' => $data['payload']['position'],
'mask' => $data['payload']['mask'],
'image_base64' => $data['payload']['image_base64'],
], $context, $request_ids );
$this->throw_on_error( $result );
return [
'images' => $result['images'],
'response_id' => $result['responseId'],
'usage' => $result['usage'],
];
}
public function ajax_ai_upload_image( $data ) {
if ( empty( $data['image'] ) ) {
throw new \Exception( 'Missing image data' );
}
$image = $data['image'];
if ( empty( $image['image_url'] ) ) {
throw new \Exception( 'Missing image_url' );
}
$image_data = $this->upload_image( $image['image_url'], $data['prompt'], $data['editor_post_id'] );
if ( is_wp_error( $image_data ) ) {
throw new \Exception( esc_html( $image_data->get_error_message() ) );
}
if ( ! empty( $image['use_gallery_image'] ) && ! empty( $image['id'] ) ) {
$app = $this->get_ai_app();
$app->set_used_gallery_image( $image['id'] );
}
return [
'image' => array_merge( $image_data, $data ),
];
}
public function ajax_ai_generate_layout( $data ) {
$this->verify_permissions( $data['editor_post_id'] );
$app = $this->get_ai_app();
if ( empty( $data['prompt'] ) && empty( $data['attachments'] ) ) {
throw new \Exception( 'Missing prompt / attachments' );
}
if ( ! $app->is_connected() ) {
throw new \Exception( 'not_connected' );
}
$result = $app->generate_layout(
$data,
$this->prepare_generate_layout_context( $data )
);
if ( is_wp_error( $result ) ) {
$message = $result->get_error_message();
if ( is_array( $message ) ) {
$message = implode( ', ', $message );
throw new \Exception( esc_html( $message ) );
}
$this->throw_on_error( $result );
}
$elements = $result['text']['elements'] ?? [];
$base_template_id = $result['baseTemplateId'] ?? null;
$template_type = $result['templateType'] ?? null;
if ( empty( $elements ) || ! is_array( $elements ) ) {
throw new \Exception( 'unknown_error' );
}
if ( 1 === count( $elements ) ) {
$template = $elements[0];
} else {
$template = [
'elType' => 'container',
'elements' => $elements,
'settings' => [
'content_width' => 'full',
'flex_gap' => [
'column' => '0',
'row' => '0',
'unit' => 'px',
],
'padding' => [
'unit' => 'px',
'top' => '0',
'right' => '0',
'bottom' => '0',
'left' => '0',
'isLinked' => true,
],
],
];
}
return [
'all' => [],
'text' => $template,
'response_id' => $result['responseId'],
'usage' => $result['usage'],
'base_template_id' => $base_template_id,
'template_type' => $template_type,
];
}
public function ajax_ai_get_layout_prompt_enhancer( $data ) {
$this->verify_permissions( $data['editor_post_id'] );
$app = $this->get_ai_app();
if ( empty( $data['prompt'] ) ) {
throw new \Exception( 'Missing prompt' );
}
if ( ! $app->is_connected() ) {
throw new \Exception( 'not_connected' );
}
$result = $app->get_layout_prompt_enhanced(
$data['prompt'],
$data['enhance_type'],
$this->prepare_generate_layout_context( $data )
);
$this->throw_on_error( $result );
return [
'text' => $result['text'] ?? $data['prompt'],
'response_id' => $result['responseId'] ?? '',
'usage' => $result['usage'] ?? '',
];
}
private function prepare_generate_layout_context( $data ) {
$request_context = $this->get_request_context( $data );
$kit = Plugin::$instance->kits_manager->get_active_kit();
if ( ! $kit ) {
return $request_context;
}
$kits_data = Collection::make( $kit->get_data()['settings'] ?? [] );
$colors = $kits_data
->filter( function ( $_, $key ) {
return in_array( $key, [ 'system_colors', 'custom_colors' ], true );
} )
->flatten()
->filter( function ( $val ) {
return ! empty( $val['_id'] );
} )
->map( function ( $val ) {
return [
'id' => $val['_id'],
'label' => $val['title'] ?? null,
'value' => $val['color'] ?? null,
];
} );
$typography = $kits_data
->filter( function ( $_, $key ) {
return in_array( $key, [ 'system_typography', 'custom_typography' ], true );
} )
->flatten()
->filter( function ( $val ) {
return ! empty( $val['_id'] );
} )
->map( function ( $val ) {
$font_size = null;
if ( isset(
$val['typography_font_size']['unit'],
$val['typography_font_size']['size']
) ) {
$prop = $val['typography_font_size'];
$font_size = 'custom' === $prop['unit']
? $prop['size']
: $prop['size'] . $prop['unit'];
}
return [
'id' => $val['_id'],
'label' => $val['title'] ?? null,
'value' => [
'family' => $val['typography_font_family'] ?? null,
'weight' => $val['typography_font_weight'] ?? null,
'style' => $val['typography_font_style'] ?? null,
'size' => $font_size,
],
];
} );
$request_context['globals'] = [
'colors' => $colors->all(),
'typography' => $typography->all(),
];
return $request_context;
}
private function upload_image( $image_url, $image_title, $parent_post_id = 0 ) {
if ( ! current_user_can( 'upload_files' ) ) {
throw new \Exception( 'Not Allowed to Upload images' );
}
$uploads_manager = new \Elementor\Core\Files\Uploads_Manager();
if ( $uploads_manager::are_unfiltered_uploads_enabled() ) {
Plugin::$instance->uploads_manager->set_elementor_upload_state( true );
add_filter( 'wp_handle_sideload_prefilter', [ Plugin::$instance->uploads_manager, 'handle_elementor_upload' ] );
add_filter( 'image_sideload_extensions', function( $extensions ) {
$extensions[] = 'svg';
return $extensions;
});
}
$attachment_id = media_sideload_image( $image_url, $parent_post_id, $image_title, 'id' );
if ( is_wp_error( $attachment_id ) ) {
return new \WP_Error( 'upload_error', $attachment_id->get_error_message() );
}
if ( ! empty( $attachment_id['error'] ) ) {
return new \WP_Error( 'upload_error', $attachment_id['error'] );
}
return [
'id' => $attachment_id,
'url' => esc_url( wp_get_attachment_image_url( $attachment_id, 'full' ) ),
'alt' => esc_attr( $image_title ),
'source' => 'library',
];
}
public function ajax_ai_get_history( $data ): array {
$type = $data['type'] ?? self::HISTORY_TYPE_ALL;
if ( ! in_array( $type, self::VALID_HISTORY_TYPES, true ) ) {
throw new \Exception( 'Invalid history type' );
}
$page = sanitize_text_field( $data['page'] ?? 1 );
$limit = sanitize_text_field( $data['limit'] ?? 10 );
$app = $this->get_ai_app();
if ( ! $app->is_connected() ) {
throw new \Exception( 'not_connected' );
}
$context = $this->get_request_context( $data );
$result = $app->get_history_by_type( $type, $page, $limit, $context );
if ( is_wp_error( $result ) ) {
throw new \Exception( esc_html( $result->get_error_message() ) );
}
return $result;
}
public function ajax_ai_delete_history_item( $data ): array {
if ( empty( $data['id'] ) || ! wp_is_uuid( $data['id'] ) ) {
throw new \Exception( 'Missing id parameter' );
}
$app = $this->get_ai_app();
if ( ! $app->is_connected() ) {
throw new \Exception( 'not_connected' );
}
$context = $this->get_request_context( $data );
$result = $app->delete_history_item( $data['id'], $context );
if ( is_wp_error( $result ) ) {
throw new \Exception( esc_html( $result->get_error_message() ) );
}
return [];
}
public function ajax_ai_toggle_favorite_history_item( $data ): array {
if ( empty( $data['id'] ) || ! wp_is_uuid( $data['id'] ) ) {
throw new \Exception( 'Missing id parameter' );
}
$app = $this->get_ai_app();
if ( ! $app->is_connected() ) {
throw new \Exception( 'not_connected' );
}
$context = $this->get_request_context( $data );
$result = $app->toggle_favorite_history_item( $data['id'], $context );
if ( is_wp_error( $result ) ) {
throw new \Exception( esc_html( $result->get_error_message() ) );
}
return [];
}
public function ajax_ai_get_product_image_unification( $data ): array {
if ( ! empty( $data['payload']['postId'] ) ) {
$data['editor_post_id'] = $data['payload']['postId'];
}
$this->verify_upload_permissions( $data );
$app = $this->get_ai_app();
if ( empty( $data['payload']['image'] ) || empty( $data['payload']['image']['id'] ) ) {
throw new \Exception( 'Missing Image' );
}
if ( empty( $data['payload']['settings'] ) ) {
throw new \Exception( 'Missing prompt settings' );
}
if ( ! $app->is_connected() ) {
throw new \Exception( 'not_connected' );
}
$context = $this->get_request_context( $data );
$request_ids = $this->get_request_ids( $data['payload'] );
$result = $app->get_unify_product_images( [
'promptSettings' => $data['payload']['settings'],
'attachment_id' => $data['payload']['image']['id'],
'featureIdentifier' => $data['payload']['featureIdentifier'] ?? '',
], $context, $request_ids );
$this->throw_on_error( $result );
return [
'images' => $result['images'],
'response_id' => $result['responseId'],
'usage' => $result['usage'],
];
}
public function ajax_ai_get_animation( $data ): array {
$this->verify_upload_permissions( $data );
$app = $this->get_ai_app();
if ( empty( $data['payload']['prompt'] ) ) {
throw new \Exception( 'Missing prompt' );
}
if ( empty( $data['payload']['motionEffectType'] ) ) {
throw new \Exception( 'Missing animation type' );
}
if ( ! $app->is_connected() ) {
throw new \Exception( 'not_connected' );
}
$context = $this->get_request_context( $data );
$request_ids = $this->get_request_ids( $data['payload'] );
$result = $app->get_animation( $data, $context, $request_ids );
$this->throw_on_error( $result );
return [
'text' => $result['text'],
'response_id' => $result['responseId'],
'usage' => $result['usage'],
];
}
/**
* @param mixed $result
*/
private function throw_on_error( $result ): void {
if ( is_wp_error( $result ) ) {
wp_send_json_error( [
'message' => esc_html( $result->get_error_message() ),
'extra_data' => $result->get_error_data(),
] );
}
}
/**
* @return void
*/
public function add_wc_scripts(): void {
wp_enqueue_script( 'elementor-ai-unify-product-images',
$this->get_js_assets_url( 'ai-unify-product-images' ),
[
'jquery',
'elementor-v2-ui',
'elementor-v2-icons',
'wp-components',
'elementor-common',
],
ELEMENTOR_VERSION,
true
);
wp_localize_script(
'elementor-ai-unify-product-images',
'UnifyProductImagesConfig',
[
'get_product_images_url' => admin_url( 'admin-ajax.php' ),
'set_product_images_url' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'elementor-ai-unify-product-images_nonce' ),
'placeholder' => ELEMENTOR_ASSETS_URL . 'images/app/ai/product-image-unification-example.gif?' . ELEMENTOR_VERSION,
'is_get_started' => User::get_introduction_meta( 'ai_get_started' ),
'connect_url' => $this->get_ai_connect_url(),
]
);
add_filter( 'bulk_actions-edit-product', function ( $data ) {
return $this->add_products_bulk_action( $data );
});
wp_set_script_translations( 'elementor-ai-unify-product-images', 'elementor' );
}
/**
* @param $product
* @param int|null $image_to_remove
* @param int|null $image_to_add
* @return void
*/
private function update_product_gallery( $product, ?int $image_to_remove, ?int $image_to_add ): void {
$gallery_image_ids = $product->get_gallery_image_ids();
$index = array_search( $image_to_remove, $gallery_image_ids, true );
if ( false !== $index ) {
unset( $gallery_image_ids[ $index ] );
}
if ( ! in_array( $image_to_add, $gallery_image_ids, true ) ) {
$gallery_image_ids[] = $image_to_add;
}
$product->set_gallery_image_ids( $gallery_image_ids );
$product->save();
}
private function should_display_create_with_ai_banner() {
$elementor_pages = new \WP_Query( [
'post_type' => 'page',
'post_status' => 'publish',
'fields' => 'ids',
'posts_per_page' => self::MIN_PAGES_FOR_CREATE_WITH_AI_BANNER + 1,
] );
if ( $elementor_pages->post_count > self::MIN_PAGES_FOR_CREATE_WITH_AI_BANNER ) {
return false;
}
if ( Utils::is_custom_kit_applied() ) {
return false;
}
return true;
}
private function get_create_with_ai_banner_data() {
return [
'title' => 'Create and launch your site faster with AI',
'description' => 'Share your vision with our AI Chat and watch as it becomes a brief, sitemap, and wireframes in minutes:',
'input_placeholder' => 'Start describing the site you want to create...',
'button_title' => 'Create with AI',
'button_cta_url' => 'http://planner.elementor.com/chat.html',
'background_image' => ELEMENTOR_ASSETS_URL . 'images/app/ai/ai-site-creator-homepage-bg.svg',
'utm_source' => 'editor-home',
'utm_medium' => 'wp-dash',
'utm_campaign' => 'generate-with-ai',
];
}
public function add_create_with_ai_banner_to_homescreen( $home_screen_data ) {
if ( $this->should_display_create_with_ai_banner() ) {
$home_screen_data['create_with_ai'] = $this->get_create_with_ai_banner_data();
} else {
$home_screen_data['create_with_ai'] = null;
}
return $home_screen_data;
}
}
editor.min.css 0000644 00000001113 15156237675 0007343 0 ustar 00 .e-ai-button{background:none;border:none;cursor:pointer;font-size:var(--control-title-size);transition:var(--e-a-transition-hover)}.e-ai-button:not(.e-active){color:var(--e-a-color-primary-bold)}.e-ai-button:hover{color:#e73cf6}.e-ai-promotion{font-size:var(--control-title-size)}.e-ai-promotion i{margin-inline-end:5px}.elementor-label-block .e-ai-button,.elementor-label-block .e-ai-promotion{margin-inline-start:auto}.e-ai-border-button{align-items:center;border:var(--e-a-border-bold);border-radius:var(--e-a-border-radius);display:flex;height:27px;justify-content:center;width:27px} layout-preview.min.css 0000644 00000010046 15156237675 0011056 0 ustar 00 [data-id^=e-ai-preview-container]{outline:2px solid var(--e-p-border-con);outline-offset:-2px}[data-id^=e-ai-screenshot-container],[data-id^=e-ai-screenshot-container] *{animation-duration:0s!important;animation-iteration-count:1!important;transition-duration:0s!important}.e-ai-preview-container--idle{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='80' height='80' fill='none' viewBox='0 0 80 80'%3E%3Cpath fill='%23BABFC5' fill-rule='evenodd' d='M60.834 10.833a2.5 2.5 0 0 1 2.5 2.5 4.167 4.167 0 0 0 4.167 4.167 2.5 2.5 0 0 1 0 5 4.167 4.167 0 0 0-4.167 4.166 2.5 2.5 0 1 1-5 0 4.167 4.167 0 0 0-4.167-4.166 2.5 2.5 0 0 1 0-5 4.167 4.167 0 0 0 4.167-4.167 2.5 2.5 0 0 1 2.5-2.5m0 8.792a9 9 0 0 1-.375.375 9 9 0 0 1 .375.375 10 10 0 0 1 .375-.375 10 10 0 0 1-.375-.375m-30-2.125a2.5 2.5 0 0 1 2.5 2.5 17.5 17.5 0 0 0 17.5 17.5 2.5 2.5 0 0 1 0 5 17.5 17.5 0 0 0-17.5 17.5 2.5 2.5 0 0 1-5 0 17.5 17.5 0 0 0-17.5-17.5 2.5 2.5 0 1 1 0-5 17.5 17.5 0 0 0 17.5-17.5 2.5 2.5 0 0 1 2.5-2.5m0 12.808A22.5 22.5 0 0 1 21.142 40a22.5 22.5 0 0 1 9.692 9.692A22.5 22.5 0 0 1 40.526 40a22.5 22.5 0 0 1-9.692-9.692m30 20.525a2.5 2.5 0 0 1 2.5 2.5 4.167 4.167 0 0 0 4.167 4.167 2.5 2.5 0 0 1 0 5 4.167 4.167 0 0 0-4.167 4.166 2.5 2.5 0 1 1-5 0 4.167 4.167 0 0 0-4.167-4.166 2.5 2.5 0 0 1 0-5 4.167 4.167 0 0 0 4.167-4.167 2.5 2.5 0 0 1 2.5-2.5m0 8.792a9 9 0 0 1-.375.375 9 9 0 0 1 .375.375 10 10 0 0 1 .375-.375 10 10 0 0 1-.375-.376' clip-rule='evenodd' opacity='.4'/%3E%3C/svg%3E");background-position:50%;background-repeat:no-repeat;background-size:80px auto;height:154px}.e-ai-preview-container--hidden,.e-ai-preview-container--idle>*{display:none!important}.e-ai-layout-button{position:relative}.e-ai-layout-button--sparkle{--animation-duration:1.5s;--opacity:.2;--size:6px;aspect-ratio:1;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='6' height='6' fill='none' viewBox='0 0 6 6'%3E%3Cpath fill='%230c0d0e' fill-rule='evenodd' d='M3 .25a.75.75 0 0 1 .693.463L4.16 1.84l1.127.467a.75.75 0 0 1 0 1.386L4.16 4.16l-.467 1.127a.75.75 0 0 1-1.386 0L1.84 4.16.713 3.693a.75.75 0 0 1 0-1.386L1.84 1.84 2.307.713A.75.75 0 0 1 3 .25' clip-rule='evenodd'/%3E%3C/svg%3E");background-size:cover;display:block;height:var(--size);opacity:0;position:absolute;z-index:99999}.e-ai-layout-button--sparkle:first-child,.e-ai-layout-button--sparkle:nth-child(2),.e-ai-layout-button--sparkle:nth-child(3){right:12px;top:12px}.e-ai-layout-button--sparkle:nth-child(4),.e-ai-layout-button--sparkle:nth-child(5),.e-ai-layout-button--sparkle:nth-child(6),.e-ai-layout-button--sparkle:nth-child(7){right:12px;top:22px}.e-ai-layout-button--sparkle:first-child{--opacity:.3;--size:4px;--animation-name:sparkle-1}.e-ai-layout-button--sparkle:nth-child(2){--opacity:.3;--size:4px;--animation-delay:.7s;--animation-name:sparkle-2}.e-ai-layout-button--sparkle:nth-child(3){--animation-delay:3.5s;--animation-name:sparkle-3}.e-ai-layout-button--sparkle:nth-child(4){--animation-delay:.5s;--animation-name:sparkle-4}.e-ai-layout-button--sparkle:nth-child(5){--animation-delay:1.5s;--animation-name:sparkle-5}.e-ai-layout-button--sparkle:nth-child(6){--animation-delay:2.5s;--animation-name:sparkle-6}.e-ai-layout-button--sparkle:nth-child(7){--opacity:.3;--animation-delay:.7s;--animation-name:sparkle-7}.e-ai-layout-button:hover .e-ai-layout-button--sparkle{--timing:cubic-bezier(0,1.18,.96,.75);animation:var(--animation-name) var(--animation-duration) var(--animation-delay,0s) var(--timing) infinite both,sparkle-opacity var(--animation-duration) var(--animation-delay,0s) var(--timing) infinite both}@keyframes sparkle-opacity{50%{opacity:var(--opacity)}to{opacity:0}}@keyframes sparkle-1{to{transform:translate(16px,-12px)}}@keyframes sparkle-2{to{transform:translate(16px,12px)}}@keyframes sparkle-3{to{transform:translate(12px,8px)}}@keyframes sparkle-4{to{transform:translate(16px,16px)}}@keyframes sparkle-5{to{transform:translate(12px,16px)}}@keyframes sparkle-6{to{transform:translate(-8px,-24px)}}@keyframes sparkle-7{to{transform:translate(-20px,16px)}} layout-preview.css 0000644 00000016407 15156237675 0010303 0 ustar 00 [data-id^=e-ai-preview-container] {
outline: 2px solid var(--e-p-border-con);
outline-offset: -2px;
}
[data-id^=e-ai-screenshot-container], [data-id^=e-ai-screenshot-container] * {
animation-duration: 0s !important;
animation-iteration-count: 1 !important;
transition-duration: 0s !important;
}
.e-ai-preview-container--idle {
height: 154px;
background-image: url("data:image/svg+xml,%3Csvg width='80' height='80' viewBox='0 0 80 80' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cg opacity='0.4'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M60.834 10.833C62.2147 10.833 63.334 11.9523 63.334 13.333C63.334 14.4381 63.773 15.4979 64.5544 16.2793C65.3358 17.0607 66.3956 17.4997 67.5007 17.4997C68.8814 17.4997 70.0007 18.619 70.0007 19.9997C70.0007 21.3804 68.8814 22.4997 67.5007 22.4997C66.3956 22.4997 65.3358 22.9387 64.5544 23.7201C63.773 24.5015 63.334 25.5613 63.334 26.6663C63.334 28.0471 62.2147 29.1663 60.834 29.1663C59.4533 29.1663 58.334 28.0471 58.334 26.6663C58.334 25.5613 57.895 24.5015 57.1136 23.7201C56.3322 22.9387 55.2724 22.4997 54.1673 22.4997C52.7866 22.4997 51.6673 21.3804 51.6673 19.9997C51.6673 18.619 52.7866 17.4997 54.1673 17.4997C55.2724 17.4997 56.3322 17.0607 57.1136 16.2793C57.895 15.4979 58.334 14.4381 58.334 13.333C58.334 11.9523 59.4533 10.833 60.834 10.833ZM60.834 19.6245C60.7734 19.6888 60.7118 19.7522 60.6491 19.8148C60.5865 19.8774 60.5231 19.9391 60.4588 19.9997C60.5231 20.0603 60.5865 20.1219 60.6491 20.1845C60.7118 20.2472 60.7734 20.3106 60.834 20.3748C60.8946 20.3106 60.9562 20.2472 61.0188 20.1845C61.0815 20.1219 61.1449 20.0603 61.2091 19.9997C61.1449 19.9391 61.0815 19.8774 61.0188 19.8148C60.9562 19.7522 60.8946 19.6888 60.834 19.6245ZM30.834 17.4997C32.2147 17.4997 33.334 18.619 33.334 19.9997C33.334 24.641 35.1777 29.0922 38.4596 32.374C41.7415 35.6559 46.1927 37.4997 50.834 37.4997C52.2147 37.4997 53.334 38.619 53.334 39.9997C53.334 41.3804 52.2147 42.4997 50.834 42.4997C46.1927 42.4997 41.7415 44.3434 38.4596 47.6253C35.1777 50.9072 33.334 55.3584 33.334 59.9997C33.334 61.3804 32.2147 62.4997 30.834 62.4997C29.4533 62.4997 28.334 61.3804 28.334 59.9997C28.334 55.3584 26.4902 50.9072 23.2084 47.6253C19.9265 44.3434 15.4753 42.4997 10.834 42.4997C9.45327 42.4997 8.33398 41.3804 8.33398 39.9997C8.33398 38.619 9.45327 37.4997 10.834 37.4997C15.4753 37.4997 19.9265 35.6559 23.2084 32.374C26.4902 29.0922 28.334 24.641 28.334 19.9997C28.334 18.619 29.4533 17.4997 30.834 17.4997ZM30.834 30.3075C29.778 32.3565 28.4041 34.2494 26.7439 35.9096C25.0837 37.5698 23.1908 38.9437 21.1418 39.9997C23.1908 41.0556 25.0837 42.4296 26.7439 44.0898C28.4041 45.75 29.778 47.6429 30.834 49.6919C31.8899 47.6429 33.2639 45.75 34.9241 44.0898C36.5843 42.4296 38.4772 41.0556 40.5262 39.9997C38.4772 38.9437 36.5843 37.5698 34.9241 35.9096C33.2639 34.2494 31.8899 32.3565 30.834 30.3075ZM60.834 50.833C62.2147 50.833 63.334 51.9523 63.334 53.333C63.334 54.4381 63.773 55.4979 64.5544 56.2793C65.3358 57.0607 66.3956 57.4997 67.5007 57.4997C68.8814 57.4997 70.0007 58.619 70.0007 59.9997C70.0007 61.3804 68.8814 62.4997 67.5007 62.4997C66.3956 62.4997 65.3358 62.9387 64.5544 63.7201C63.773 64.5015 63.334 65.5613 63.334 66.6663C63.334 68.0471 62.2147 69.1663 60.834 69.1663C59.4533 69.1663 58.334 68.0471 58.334 66.6663C58.334 65.5613 57.895 64.5015 57.1136 63.7201C56.3322 62.9387 55.2724 62.4997 54.1673 62.4997C52.7866 62.4997 51.6673 61.3804 51.6673 59.9997C51.6673 58.619 52.7866 57.4997 54.1673 57.4997C55.2724 57.4997 56.3322 57.0607 57.1136 56.2793C57.895 55.4979 58.334 54.4381 58.334 53.333C58.334 51.9523 59.4533 50.833 60.834 50.833ZM60.834 59.6245C60.7734 59.6888 60.7118 59.7522 60.6491 59.8148C60.5865 59.8774 60.5231 59.9391 60.4588 59.9997C60.5231 60.0603 60.5865 60.1219 60.6491 60.1845C60.7118 60.2472 60.7734 60.3106 60.834 60.3748C60.8946 60.3106 60.9562 60.2472 61.0188 60.1845C61.0815 60.1219 61.1449 60.0603 61.2091 59.9997C61.1449 59.9391 61.0815 59.8774 61.0188 59.8148C60.9562 59.7522 60.8946 59.6888 60.834 59.6245Z' fill='%23BABFC5'/%3E%3C/g%3E%3C/svg%3E");
background-position: center center;
background-repeat: no-repeat;
background-size: 80px auto;
}
.e-ai-preview-container--idle > * {
display: none !important;
}
.e-ai-preview-container--hidden {
display: none !important;
}
.e-ai-layout-button {
position: relative;
}
.e-ai-layout-button--sparkle {
--animation-duration: 1.5s;
--opacity: .2;
--size: 6px;
position: absolute;
z-index: 99999;
display: block;
height: var(--size);
aspect-ratio: 1;
background-image: url("data:image/svg+xml,%3Csvg width='6' height='6' viewBox='0 0 6 6' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M3 0.25C3.30335 0.25 3.57682 0.432732 3.69291 0.712987L4.15981 1.84019L5.28701 2.30709C5.56727 2.42318 5.75 2.69665 5.75 3C5.75 3.30335 5.56727 3.57682 5.28701 3.69291L4.15981 4.15981L3.69291 5.28701C3.57682 5.56727 3.30335 5.75 3 5.75C2.69665 5.75 2.42318 5.56727 2.30709 5.28701L1.84019 4.15981L0.712987 3.69291C0.432732 3.57682 0.25 3.30335 0.25 3C0.25 2.69665 0.432732 2.42318 0.712987 2.30709L1.84019 1.84019L2.30709 0.712987C2.42318 0.432732 2.69665 0.25 3 0.25Z' fill='%230c0d0e'/%3E%3C/svg%3E%0A");
background-size: cover;
opacity: 0;
}
.e-ai-layout-button--sparkle:nth-child(1), .e-ai-layout-button--sparkle:nth-child(2), .e-ai-layout-button--sparkle:nth-child(3) {
right: 12px;
top: 12px;
}
.e-ai-layout-button--sparkle:nth-child(4), .e-ai-layout-button--sparkle:nth-child(5), .e-ai-layout-button--sparkle:nth-child(6), .e-ai-layout-button--sparkle:nth-child(7) {
right: 12px;
top: 22px;
}
.e-ai-layout-button--sparkle:nth-child(1) {
--opacity: .3;
--size: 4px;
--animation-name: sparkle-1;
}
.e-ai-layout-button--sparkle:nth-child(2) {
--opacity: .3;
--size: 4px;
--animation-delay: .7s;
--animation-name: sparkle-2;
}
.e-ai-layout-button--sparkle:nth-child(3) {
--animation-delay: 3.5s;
--animation-name: sparkle-3;
}
.e-ai-layout-button--sparkle:nth-child(4) {
--animation-delay: .5s;
--animation-name: sparkle-4;
}
.e-ai-layout-button--sparkle:nth-child(5) {
--animation-delay: 1.5s;
--animation-name: sparkle-5;
}
.e-ai-layout-button--sparkle:nth-child(6) {
--animation-delay: 2.5s;
--animation-name: sparkle-6;
}
.e-ai-layout-button--sparkle:nth-child(7) {
--opacity: .3;
--animation-delay: .7s;
--animation-name: sparkle-7;
}
.e-ai-layout-button:hover .e-ai-layout-button--sparkle {
--timing: cubic-bezier( 0, 1.18, .96, .75 );
animation: var(--animation-name) var(--animation-duration) var(--animation-delay, 0s) var(--timing) infinite both, sparkle-opacity var(--animation-duration) var(--animation-delay, 0s) var(--timing) infinite both;
}
@keyframes sparkle-opacity {
50% {
opacity: var(--opacity);
}
100% {
opacity: 0;
}
}
@keyframes sparkle-1 {
100% {
transform: translate(16px, -12px);
}
}
@keyframes sparkle-2 {
100% {
transform: translate(16px, 12px);
}
}
@keyframes sparkle-3 {
100% {
transform: translate(12px, 8px);
}
}
@keyframes sparkle-4 {
100% {
transform: translate(16px, 16px);
}
}
@keyframes sparkle-5 {
100% {
transform: translate(12px, 16px);
}
}
@keyframes sparkle-6 {
100% {
transform: translate(-8px, -24px);
}
}
@keyframes sparkle-7 {
100% {
transform: translate(-20px, 16px);
}
}
/*# sourceMappingURL=layout-preview.css.map */ editor.css 0000644 00000001326 15156237675 0006567 0 ustar 00 .e-ai-button {
background: none;
border: none;
font-size: var(--control-title-size);
cursor: pointer;
transition: var(--e-a-transition-hover);
}
.e-ai-button:not(.e-active) {
color: var(--e-a-color-primary-bold);
}
.e-ai-button:hover {
color: #E73CF6;
}
.e-ai-promotion {
font-size: var(--control-title-size);
}
.e-ai-promotion i {
margin-inline-end: 5px;
}
.elementor-label-block .e-ai-promotion,
.elementor-label-block .e-ai-button {
margin-inline-start: auto;
}
.e-ai-border-button {
border-radius: var(--e-a-border-radius);
border: var(--e-a-border-bold);
display: flex;
align-items: center;
justify-content: center;
width: 27px;
height: 27px;
}
/*# sourceMappingURL=editor.css.map */ ai-site-creator-homepage-bg.svg 0000644 00000010032 15156251007 0012424 0 ustar 00
product-image-unification-example.gif 0000644 00000357001 15156251007 0013742 0 ustar 00 GIF89arr t1 =/ZY {hN,̭kQ
M'1u[Ĵ`<"1#Rb @{7 }!NETSCAPE2.0 !XMP DataXMP ~}|{zyxwvutsrqponmlkjihgfedcba`_^]\[ZYXWVUTSRQPONMLKJIHGFEDCBA@?>=<;:9876543210/.-,+*)('&%$#"!
! , rr `'dihlp,tmx|pH,Ȥrl:ШtJZجvzxL.zn|N~
H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@
JѣH*]ʴӧPJJիXjʵׯ`Ê hӪEl[2Ҿ
x[WܹpK
*(^̡1ŐCo[nk8qǠCXɕr3װc?p˙`صGЗm݉+_NmGMμuo:Nt
ë^8tҽ~}u guZwxѦ]Kf7!J]V`H (2w$v`a0G܈H`8~}uθQ'io+8LVW46cT*Yʭ%BfHdۓ衚p 睯x)ڕ砠A`&ʁ!hV?Vd馗槤>v>ZjEJF:>j<*h ,c뱸Z
Oʪ,[-NCֶ6{n++ &Ijn[믴;pN#c0+o6V|Pq[#?ʱ6,נ^˫\4r4#3VХsH
4)7Mt,;3ժ>\Wj3QM0lJkڟzp':63e
4iMjlwL}K6}Yy3g-sl?#8ʭᠫ2^zj^밓I0V+.L>[ |4,|5ƻX)+<