Changeset 3464259
- Timestamp:
- 02/18/2026 11:22:04 AM (6 weeks ago)
- Location:
- preview-ai
- Files:
-
- 6 edited
- 26 copied
-
tags/1.2.1 (copied) (copied from preview-ai/trunk)
-
tags/1.2.1/admin (copied) (copied from preview-ai/trunk/admin)
-
tags/1.2.1/admin/class-preview-ai-admin-catalog.php (copied) (copied from preview-ai/trunk/admin/class-preview-ai-admin-catalog.php)
-
tags/1.2.1/admin/class-preview-ai-admin-onboarding.php (copied) (copied from preview-ai/trunk/admin/class-preview-ai-admin-onboarding.php)
-
tags/1.2.1/admin/class-preview-ai-admin-product.php (copied) (copied from preview-ai/trunk/admin/class-preview-ai-admin-product.php)
-
tags/1.2.1/admin/class-preview-ai-admin-settings.php (copied) (copied from preview-ai/trunk/admin/class-preview-ai-admin-settings.php)
-
tags/1.2.1/admin/class-preview-ai-admin.php (copied) (copied from preview-ai/trunk/admin/class-preview-ai-admin.php) (2 diffs)
-
tags/1.2.1/admin/css/preview-ai-admin.css (copied) (copied from preview-ai/trunk/admin/css/preview-ai-admin.css) (1 diff)
-
tags/1.2.1/admin/js/preview-ai-admin.js (copied) (copied from preview-ai/trunk/admin/js/preview-ai-admin.js) (1 diff)
-
tags/1.2.1/admin/partials/preview-ai-admin-display.php (copied) (copied from preview-ai/trunk/admin/partials/preview-ai-admin-display.php)
-
tags/1.2.1/includes (copied) (copied from preview-ai/trunk/includes)
-
tags/1.2.1/includes/class-preview-ai-ajax.php (copied) (copied from preview-ai/trunk/includes/class-preview-ai-ajax.php)
-
tags/1.2.1/includes/class-preview-ai-api.php (copied) (copied from preview-ai/trunk/includes/class-preview-ai-api.php)
-
tags/1.2.1/includes/class-preview-ai-tracking.php (copied) (copied from preview-ai/trunk/includes/class-preview-ai-tracking.php)
-
tags/1.2.1/includes/class-preview-ai.php (copied) (copied from preview-ai/trunk/includes/class-preview-ai.php) (1 diff)
-
tags/1.2.1/index.php (copied) (copied from preview-ai/trunk/index.php)
-
tags/1.2.1/languages (copied) (copied from preview-ai/trunk/languages)
-
tags/1.2.1/languages/preview-ai-es_ES.po (copied) (copied from preview-ai/trunk/languages/preview-ai-es_ES.po)
-
tags/1.2.1/languages/preview-ai.pot (copied) (copied from preview-ai/trunk/languages/preview-ai.pot)
-
tags/1.2.1/preview-ai.php (copied) (copied from preview-ai/trunk/preview-ai.php) (2 diffs)
-
tags/1.2.1/public (copied) (copied from preview-ai/trunk/public)
-
tags/1.2.1/public/class-preview-ai-public.php (copied) (copied from preview-ai/trunk/public/class-preview-ai-public.php)
-
tags/1.2.1/public/js/preview-ai-api.js (copied) (copied from preview-ai/trunk/public/js/preview-ai-api.js)
-
tags/1.2.1/public/js/preview-ai-storage.js (copied) (copied from preview-ai/trunk/public/js/preview-ai-storage.js)
-
tags/1.2.1/readme.txt (copied) (copied from preview-ai/trunk/readme.txt) (5 diffs)
-
tags/1.2.1/uninstall.php (copied) (copied from preview-ai/trunk/uninstall.php)
-
trunk/admin/class-preview-ai-admin.php (modified) (2 diffs)
-
trunk/admin/css/preview-ai-admin.css (modified) (1 diff)
-
trunk/admin/js/preview-ai-admin.js (modified) (1 diff)
-
trunk/includes/class-preview-ai.php (modified) (1 diff)
-
trunk/preview-ai.php (modified) (2 diffs)
-
trunk/readme.txt (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
-
preview-ai/tags/1.2.1/admin/class-preview-ai-admin.php
r3455295 r3464259 225 225 226 226 include plugin_dir_path( __FILE__ ) . 'partials/preview-ai-admin-display.php'; 227 } 228 229 /** 230 * Render the deactivation feedback modal on the plugins page. 231 */ 232 public function render_deactivation_modal() { 233 $screen = get_current_screen(); 234 if ( ! $screen || 'plugins' !== $screen->id ) { 235 return; 236 } 237 ?> 238 <div id="preview-ai-deactivation-modal" class="preview-ai-deactivation-overlay" style="display:none;"> 239 <div class="preview-ai-deactivation-modal"> 240 <button type="button" class="preview-ai-deactivation-close" id="preview-ai-deactivation-close">×</button> 241 <div class="preview-ai-deactivation-header"> 242 <div class="preview-ai-deactivation-icon"> 243 <svg width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg> 244 </div> 245 <h3><?php esc_html_e( 'Quick feedback before you go', 'preview-ai' ); ?></h3> 246 <p><?php esc_html_e( 'We\'d love to know why you\'re deactivating so we can improve.', 'preview-ai' ); ?></p> 247 </div> 248 <form id="preview-ai-deactivation-form"> 249 <ul class="preview-ai-deactivation-reasons"> 250 <li> 251 <label> 252 <input type="radio" name="preview_ai_deactivation_reason" value="too_complex"> 253 <span><?php esc_html_e( 'Too complex to set up or use', 'preview-ai' ); ?></span> 254 </label> 255 </li> 256 <li> 257 <label> 258 <input type="radio" name="preview_ai_deactivation_reason" value="not_working"> 259 <span><?php esc_html_e( 'Doesn\'t work as expected', 'preview-ai' ); ?></span> 260 </label> 261 </li> 262 <li> 263 <label> 264 <input type="radio" name="preview_ai_deactivation_reason" value="not_compatible"> 265 <span><?php esc_html_e( 'Not compatible with my store/theme', 'preview-ai' ); ?></span> 266 </label> 267 </li> 268 <li> 269 <label> 270 <input type="radio" name="preview_ai_deactivation_reason" value="too_expensive"> 271 <span><?php esc_html_e( 'Too expensive', 'preview-ai' ); ?></span> 272 </label> 273 </li> 274 <li> 275 <label> 276 <input type="radio" name="preview_ai_deactivation_reason" value="just_testing"> 277 <span><?php esc_html_e( 'Just testing, not ready yet', 'preview-ai' ); ?></span> 278 </label> 279 </li> 280 <li> 281 <label> 282 <input type="radio" name="preview_ai_deactivation_reason" value="found_alternative"> 283 <span><?php esc_html_e( 'Found a better alternative', 'preview-ai' ); ?></span> 284 </label> 285 </li> 286 <li> 287 <label> 288 <input type="radio" name="preview_ai_deactivation_reason" value="ai_quality"> 289 <span><?php esc_html_e( 'AI-generated images aren\'t good enough', 'preview-ai' ); ?></span> 290 </label> 291 </li> 292 <li> 293 <label> 294 <input type="radio" name="preview_ai_deactivation_reason" value="other"> 295 <span><?php esc_html_e( 'Other', 'preview-ai' ); ?></span> 296 </label> 297 </li> 298 </ul> 299 <textarea id="preview-ai-deactivation-details" class="preview-ai-deactivation-details" rows="3" placeholder="<?php esc_attr_e( 'Any additional details? (optional)', 'preview-ai' ); ?>" style="display:none;"></textarea> 300 <div class="preview-ai-deactivation-actions"> 301 <button type="button" class="button" id="preview-ai-deactivation-skip"> 302 <?php esc_html_e( 'Skip & Deactivate', 'preview-ai' ); ?> 303 </button> 304 <button type="submit" class="button button-primary" id="preview-ai-deactivation-submit" disabled> 305 <?php esc_html_e( 'Submit & Deactivate', 'preview-ai' ); ?> 306 </button> 307 </div> 308 </form> 309 </div> 310 </div> 311 <?php 312 } 313 314 /** 315 * Handle deactivation feedback AJAX request. 316 */ 317 public function handle_deactivation_feedback() { 318 check_ajax_referer( 'preview_ai_deactivation_feedback', 'nonce' ); 319 320 if ( ! current_user_can( 'activate_plugins' ) ) { 321 wp_send_json_error( array( 'message' => __( 'Unauthorized.', 'preview-ai' ) ) ); 322 } 323 324 $reason = isset( $_POST['reason'] ) ? sanitize_text_field( wp_unslash( $_POST['reason'] ) ) : ''; 325 $details = isset( $_POST['details'] ) ? sanitize_textarea_field( wp_unslash( $_POST['details'] ) ) : ''; 326 327 if ( empty( $reason ) ) { 328 wp_send_json_error( array( 'message' => __( 'No reason provided.', 'preview-ai' ) ) ); 329 } 330 331 $api = new PREVIEW_AI_Api(); 332 $api->request( 'feedback/deactivation', array( 333 'reason' => $reason, 334 'details' => $details, 335 'plugin_version' => PREVIEW_AI_VERSION, 336 'site_url' => home_url(), 337 ), 5 ); 338 339 wp_send_json_success(); 227 340 } 228 341 … … 308 421 'previewAiAdmin', 309 422 array( 310 'ajaxUrl' => admin_url( 'admin-ajax.php' ), 311 'nonce' => wp_create_nonce( 'preview_ai_learn_catalog' ), 312 'verifyNonce' => wp_create_nonce( 'preview_ai_verify_api_key' ), 313 'dismissNonce' => wp_create_nonce( 'preview_ai_dismiss_notice' ), 314 'registerNonce' => wp_create_nonce( 'preview_ai_register_site' ), 315 'toggleProductNonce' => wp_create_nonce( 'preview_ai_toggle_product' ), 316 'i18n' => array( 423 'ajaxUrl' => admin_url( 'admin-ajax.php' ), 424 'nonce' => wp_create_nonce( 'preview_ai_learn_catalog' ), 425 'verifyNonce' => wp_create_nonce( 'preview_ai_verify_api_key' ), 426 'dismissNonce' => wp_create_nonce( 'preview_ai_dismiss_notice' ), 427 'registerNonce' => wp_create_nonce( 'preview_ai_register_site' ), 428 'toggleProductNonce' => wp_create_nonce( 'preview_ai_toggle_product' ), 429 'deactivationNonce' => wp_create_nonce( 'preview_ai_deactivation_feedback' ), 430 'pluginSlug' => 'preview-ai', 431 'i18n' => array( 317 432 'error' => __( 'An error occurred.', 'preview-ai' ), 318 433 'apiPending' => __( '(API integration pending)', 'preview-ai' ), -
preview-ai/tags/1.2.1/admin/css/preview-ai-admin.css
r3455295 r3464259 869 869 padding: 10px 16px !important; 870 870 } 871 872 /* ================================ 873 Deactivation Feedback Modal 874 ================================ */ 875 876 .preview-ai-deactivation-overlay { 877 position: fixed; 878 inset: 0; 879 background: rgba(0, 0, 0, 0.6); 880 z-index: 100050; 881 display: flex; 882 align-items: center; 883 justify-content: center; 884 animation: previewAiFadeIn 0.2s ease; 885 } 886 887 @keyframes previewAiFadeIn { 888 from { opacity: 0; } 889 to { opacity: 1; } 890 } 891 892 @keyframes previewAiSlideUp { 893 from { opacity: 0; transform: translateY(20px); } 894 to { opacity: 1; transform: translateY(0); } 895 } 896 897 .preview-ai-deactivation-modal { 898 background: #fff; 899 border-radius: 12px; 900 padding: 32px; 901 width: 480px; 902 max-width: 90vw; 903 max-height: 85vh; 904 overflow-y: auto; 905 position: relative; 906 box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); 907 animation: previewAiSlideUp 0.25s ease; 908 } 909 910 .preview-ai-deactivation-close { 911 position: absolute; 912 top: 12px; 913 right: 12px; 914 background: none; 915 border: none; 916 font-size: 24px; 917 line-height: 1; 918 cursor: pointer; 919 color: #8c8f94; 920 padding: 4px 8px; 921 border-radius: 4px; 922 transition: all 0.15s; 923 } 924 925 .preview-ai-deactivation-close:hover { 926 background: #f0f0f1; 927 color: #1d2327; 928 } 929 930 .preview-ai-deactivation-header { 931 text-align: center; 932 margin-bottom: 24px; 933 } 934 935 .preview-ai-deactivation-icon { 936 display: inline-flex; 937 align-items: center; 938 justify-content: center; 939 width: 48px; 940 height: 48px; 941 background: linear-gradient(135deg, #6366f1, #8b5cf6); 942 border-radius: 12px; 943 margin-bottom: 12px; 944 color: #fff; 945 } 946 947 .preview-ai-deactivation-header h3 { 948 margin: 0 0 6px; 949 font-size: 18px; 950 font-weight: 600; 951 color: #1d2327; 952 } 953 954 .preview-ai-deactivation-header p { 955 margin: 0; 956 color: #646970; 957 font-size: 13px; 958 } 959 960 .preview-ai-deactivation-reasons { 961 list-style: none; 962 margin: 0; 963 padding: 0; 964 } 965 966 .preview-ai-deactivation-reasons li { 967 margin: 0; 968 padding: 0; 969 } 970 971 .preview-ai-deactivation-reasons label { 972 display: flex; 973 align-items: center; 974 gap: 10px; 975 padding: 10px 12px; 976 margin-bottom: 4px; 977 border-radius: 8px; 978 cursor: pointer; 979 transition: background 0.15s; 980 font-size: 13px; 981 color: #1d2327; 982 } 983 984 .preview-ai-deactivation-reasons label:hover { 985 background: #f6f7f7; 986 } 987 988 .preview-ai-deactivation-reasons input[type="radio"] { 989 margin: 0; 990 flex-shrink: 0; 991 } 992 993 .preview-ai-deactivation-reasons input[type="radio"]:checked + span { 994 font-weight: 500; 995 color: #4C82F7; 996 } 997 998 .preview-ai-deactivation-details { 999 width: 100%; 1000 margin-top: 12px; 1001 padding: 10px 12px; 1002 border: 1px solid #c3c4c7; 1003 border-radius: 6px; 1004 font-size: 13px; 1005 resize: vertical; 1006 transition: border-color 0.15s; 1007 box-sizing: border-box; 1008 } 1009 1010 .preview-ai-deactivation-details:focus { 1011 border-color: #4C82F7; 1012 outline: none; 1013 box-shadow: 0 0 0 1px #4C82F7; 1014 } 1015 1016 .preview-ai-deactivation-actions { 1017 display: flex; 1018 justify-content: space-between; 1019 align-items: center; 1020 margin-top: 20px; 1021 padding-top: 16px; 1022 border-top: 1px solid #f0f0f1; 1023 } 1024 1025 #preview-ai-deactivation-skip { 1026 color: #646970; 1027 border-color: #c3c4c7; 1028 } 1029 1030 #preview-ai-deactivation-skip:hover { 1031 color: #1d2327; 1032 border-color: #8c8f94; 1033 } 1034 1035 #preview-ai-deactivation-submit { 1036 background: #4C82F7; 1037 border-color: #4C82F7; 1038 box-shadow: none; 1039 text-shadow: none; 1040 } 1041 1042 #preview-ai-deactivation-submit:hover:not(:disabled) { 1043 background: #3a6fd9; 1044 border-color: #3a6fd9; 1045 } 1046 1047 #preview-ai-deactivation-submit:disabled { 1048 opacity: 0.5; 1049 cursor: not-allowed; 1050 } -
preview-ai/tags/1.2.1/admin/js/preview-ai-admin.js
r3455295 r3464259 332 332 } 333 333 334 // ================================ 335 // Deactivation Feedback Modal 336 // ================================ 337 338 var $deactivateLink = $( '#the-list [data-slug="' + ( previewAiAdmin.pluginSlug || 'preview-ai' ) + '"] .deactivate a' ); 339 340 if ( $deactivateLink.length ) { 341 var deactivateUrl = $deactivateLink.attr( 'href' ); 342 var $modal = $( '#preview-ai-deactivation-modal' ); 343 var $form = $( '#preview-ai-deactivation-form' ); 344 var $details = $( '#preview-ai-deactivation-details' ); 345 var $submitBtn = $( '#preview-ai-deactivation-submit' ); 346 347 $deactivateLink.on( 'click', function( e ) { 348 e.preventDefault(); 349 $modal.fadeIn( 200 ); 350 } ); 351 352 // Close modal. 353 $( '#preview-ai-deactivation-close' ).on( 'click', function() { 354 $modal.fadeOut( 150 ); 355 } ); 356 357 // Close on overlay click. 358 $modal.on( 'click', function( e ) { 359 if ( $( e.target ).is( $modal ) ) { 360 $modal.fadeOut( 150 ); 361 } 362 } ); 363 364 // Close on Esc key. 365 $( document ).on( 'keydown', function( e ) { 366 if ( 27 === e.keyCode && $modal.is( ':visible' ) ) { 367 $modal.fadeOut( 150 ); 368 } 369 } ); 370 371 // Show/hide details textarea based on selection. 372 $form.on( 'change', 'input[name="preview_ai_deactivation_reason"]', function() { 373 $submitBtn.prop( 'disabled', false ); 374 var val = $( this ).val(); 375 if ( 'other' === val || 'not_working' === val || 'not_compatible' === val ) { 376 $details.slideDown( 150 ); 377 } else { 378 $details.slideUp( 150 ); 379 } 380 } ); 381 382 // Skip & Deactivate. 383 $( '#preview-ai-deactivation-skip' ).on( 'click', function() { 384 window.location.href = deactivateUrl; 385 } ); 386 387 // Submit & Deactivate. 388 $form.on( 'submit', function( e ) { 389 e.preventDefault(); 390 var reason = $form.find( 'input[name="preview_ai_deactivation_reason"]:checked' ).val(); 391 392 if ( ! reason ) { 393 window.location.href = deactivateUrl; 394 return; 395 } 396 397 $submitBtn.prop( 'disabled', true ).text( previewAiAdmin.i18n.deactivating || 'Deactivating...' ); 398 399 $.ajax( { 400 url: previewAiAdmin.ajaxUrl, 401 type: 'POST', 402 data: { 403 action: 'preview_ai_deactivation_feedback', 404 nonce: previewAiAdmin.deactivationNonce, 405 reason: reason, 406 details: $details.val() || '' 407 }, 408 complete: function() { 409 window.location.href = deactivateUrl; 410 } 411 } ); 412 } ); 413 } 414 334 415 }); 335 416 -
preview-ai/tags/1.2.1/includes/class-preview-ai.php
r3455839 r3464259 239 239 $this->loader->add_action( 'wp_ajax_preview_ai_reverify_compatibility', $plugin_admin, 'handle_reverify_compatibility' ); 240 240 $this->loader->add_action( 'wp_ajax_preview_ai_toggle_product', $plugin_admin, 'handle_toggle_product' ); 241 242 // Deactivation feedback modal. 243 $this->loader->add_action( 'admin_footer', $plugin_admin, 'render_deactivation_modal' ); 244 $this->loader->add_action( 'wp_ajax_preview_ai_deactivation_feedback', $plugin_admin, 'handle_deactivation_feedback' ); 241 245 242 246 // Action Scheduler hook for background catalog processing. -
preview-ai/tags/1.2.1/preview-ai.php
r3460856 r3464259 7 7 * 8 8 * @wordpress-plugin 9 * Plugin Name: Preview AI – Virtual Try-On for WooCommerce9 * Plugin Name: Virtual Try-On for WooCommerce – Preview AI 10 10 * Plugin URI: https://previewai.app/ 11 11 * Description: Preview AI is a plugin that allows your customers to preview your products in real-time using AI image generation. 12 * Version: 1.2. 012 * Version: 1.2.1 13 13 * Author: Preview AI 14 14 * Author URI: https://profiles.wordpress.org/previewai/ 15 15 * License: GPL-2.0+ 16 16 * License URI: http://www.gnu.org/licenses/gpl-2.0.txt 17 * Requires Plugins: woocommerce 17 18 * Text Domain: preview-ai 18 19 * Domain Path: /languages … … 27 28 * Current plugin version. 28 29 */ 29 define( 'PREVIEW_AI_VERSION', '1.2. 0' );30 define( 'PREVIEW_AI_VERSION', '1.2.1' ); 30 31 define( 'PREVIEW_AI_PLUGIN_BASENAME', plugin_basename( __FILE__ ) ); 31 32 -
preview-ai/tags/1.2.1/readme.txt
r3460856 r3464259 1 === Preview AI – Virtual Try-On for WooCommerce===1 === Virtual Try-On for WooCommerce – Preview AI === 2 2 Contributors: previewai 3 3 Donate link: https://previewai.app/ … … 8 8 WC requires at least: 8.0 9 9 WC tested up to: 10.5.1 10 Stable tag: 1.2. 010 Stable tag: 1.2.1 11 11 License: GPLv2 or later 12 12 License URI: http://www.gnu.org/licenses/gpl-2.0.html … … 160 160 == Changelog == 161 161 162 = 1.2.1 = 163 – Renamed plugin to "Virtual Try-On for WooCommerce – Preview AI" 164 – Added WooCommerce as a required plugin dependency (Requires Plugins header) 165 – Added optional deactivation feedback survey to help us improve the plugin 166 162 167 = 1.2.0 = 163 168 – Added optional Advanced Analytics (opt-in): link try-on usage to purchases for accurate ROI measurement. … … 183 188 184 189 = 1.0.1 = 185 – Updated plugin name to " Preview AI – Virtual Try-On for WooCommerce"190 – Updated plugin name to "Virtual Try-On for WooCommerce – Preview AI" 186 191 187 192 = 1.0.0 = … … 193 198 == Upgrade Notice == 194 199 200 = 1.2.1 = 201 Plugin renamed, WooCommerce declared as required dependency, and added deactivation feedback survey. 202 195 203 = 1.2.0 = 196 204 Adds end-to-end conversion attribution: see exactly how virtual try-on impacts your sales. -
preview-ai/trunk/admin/class-preview-ai-admin.php
r3455295 r3464259 225 225 226 226 include plugin_dir_path( __FILE__ ) . 'partials/preview-ai-admin-display.php'; 227 } 228 229 /** 230 * Render the deactivation feedback modal on the plugins page. 231 */ 232 public function render_deactivation_modal() { 233 $screen = get_current_screen(); 234 if ( ! $screen || 'plugins' !== $screen->id ) { 235 return; 236 } 237 ?> 238 <div id="preview-ai-deactivation-modal" class="preview-ai-deactivation-overlay" style="display:none;"> 239 <div class="preview-ai-deactivation-modal"> 240 <button type="button" class="preview-ai-deactivation-close" id="preview-ai-deactivation-close">×</button> 241 <div class="preview-ai-deactivation-header"> 242 <div class="preview-ai-deactivation-icon"> 243 <svg width="24" height="24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg> 244 </div> 245 <h3><?php esc_html_e( 'Quick feedback before you go', 'preview-ai' ); ?></h3> 246 <p><?php esc_html_e( 'We\'d love to know why you\'re deactivating so we can improve.', 'preview-ai' ); ?></p> 247 </div> 248 <form id="preview-ai-deactivation-form"> 249 <ul class="preview-ai-deactivation-reasons"> 250 <li> 251 <label> 252 <input type="radio" name="preview_ai_deactivation_reason" value="too_complex"> 253 <span><?php esc_html_e( 'Too complex to set up or use', 'preview-ai' ); ?></span> 254 </label> 255 </li> 256 <li> 257 <label> 258 <input type="radio" name="preview_ai_deactivation_reason" value="not_working"> 259 <span><?php esc_html_e( 'Doesn\'t work as expected', 'preview-ai' ); ?></span> 260 </label> 261 </li> 262 <li> 263 <label> 264 <input type="radio" name="preview_ai_deactivation_reason" value="not_compatible"> 265 <span><?php esc_html_e( 'Not compatible with my store/theme', 'preview-ai' ); ?></span> 266 </label> 267 </li> 268 <li> 269 <label> 270 <input type="radio" name="preview_ai_deactivation_reason" value="too_expensive"> 271 <span><?php esc_html_e( 'Too expensive', 'preview-ai' ); ?></span> 272 </label> 273 </li> 274 <li> 275 <label> 276 <input type="radio" name="preview_ai_deactivation_reason" value="just_testing"> 277 <span><?php esc_html_e( 'Just testing, not ready yet', 'preview-ai' ); ?></span> 278 </label> 279 </li> 280 <li> 281 <label> 282 <input type="radio" name="preview_ai_deactivation_reason" value="found_alternative"> 283 <span><?php esc_html_e( 'Found a better alternative', 'preview-ai' ); ?></span> 284 </label> 285 </li> 286 <li> 287 <label> 288 <input type="radio" name="preview_ai_deactivation_reason" value="ai_quality"> 289 <span><?php esc_html_e( 'AI-generated images aren\'t good enough', 'preview-ai' ); ?></span> 290 </label> 291 </li> 292 <li> 293 <label> 294 <input type="radio" name="preview_ai_deactivation_reason" value="other"> 295 <span><?php esc_html_e( 'Other', 'preview-ai' ); ?></span> 296 </label> 297 </li> 298 </ul> 299 <textarea id="preview-ai-deactivation-details" class="preview-ai-deactivation-details" rows="3" placeholder="<?php esc_attr_e( 'Any additional details? (optional)', 'preview-ai' ); ?>" style="display:none;"></textarea> 300 <div class="preview-ai-deactivation-actions"> 301 <button type="button" class="button" id="preview-ai-deactivation-skip"> 302 <?php esc_html_e( 'Skip & Deactivate', 'preview-ai' ); ?> 303 </button> 304 <button type="submit" class="button button-primary" id="preview-ai-deactivation-submit" disabled> 305 <?php esc_html_e( 'Submit & Deactivate', 'preview-ai' ); ?> 306 </button> 307 </div> 308 </form> 309 </div> 310 </div> 311 <?php 312 } 313 314 /** 315 * Handle deactivation feedback AJAX request. 316 */ 317 public function handle_deactivation_feedback() { 318 check_ajax_referer( 'preview_ai_deactivation_feedback', 'nonce' ); 319 320 if ( ! current_user_can( 'activate_plugins' ) ) { 321 wp_send_json_error( array( 'message' => __( 'Unauthorized.', 'preview-ai' ) ) ); 322 } 323 324 $reason = isset( $_POST['reason'] ) ? sanitize_text_field( wp_unslash( $_POST['reason'] ) ) : ''; 325 $details = isset( $_POST['details'] ) ? sanitize_textarea_field( wp_unslash( $_POST['details'] ) ) : ''; 326 327 if ( empty( $reason ) ) { 328 wp_send_json_error( array( 'message' => __( 'No reason provided.', 'preview-ai' ) ) ); 329 } 330 331 $api = new PREVIEW_AI_Api(); 332 $api->request( 'feedback/deactivation', array( 333 'reason' => $reason, 334 'details' => $details, 335 'plugin_version' => PREVIEW_AI_VERSION, 336 'site_url' => home_url(), 337 ), 5 ); 338 339 wp_send_json_success(); 227 340 } 228 341 … … 308 421 'previewAiAdmin', 309 422 array( 310 'ajaxUrl' => admin_url( 'admin-ajax.php' ), 311 'nonce' => wp_create_nonce( 'preview_ai_learn_catalog' ), 312 'verifyNonce' => wp_create_nonce( 'preview_ai_verify_api_key' ), 313 'dismissNonce' => wp_create_nonce( 'preview_ai_dismiss_notice' ), 314 'registerNonce' => wp_create_nonce( 'preview_ai_register_site' ), 315 'toggleProductNonce' => wp_create_nonce( 'preview_ai_toggle_product' ), 316 'i18n' => array( 423 'ajaxUrl' => admin_url( 'admin-ajax.php' ), 424 'nonce' => wp_create_nonce( 'preview_ai_learn_catalog' ), 425 'verifyNonce' => wp_create_nonce( 'preview_ai_verify_api_key' ), 426 'dismissNonce' => wp_create_nonce( 'preview_ai_dismiss_notice' ), 427 'registerNonce' => wp_create_nonce( 'preview_ai_register_site' ), 428 'toggleProductNonce' => wp_create_nonce( 'preview_ai_toggle_product' ), 429 'deactivationNonce' => wp_create_nonce( 'preview_ai_deactivation_feedback' ), 430 'pluginSlug' => 'preview-ai', 431 'i18n' => array( 317 432 'error' => __( 'An error occurred.', 'preview-ai' ), 318 433 'apiPending' => __( '(API integration pending)', 'preview-ai' ), -
preview-ai/trunk/admin/css/preview-ai-admin.css
r3455295 r3464259 869 869 padding: 10px 16px !important; 870 870 } 871 872 /* ================================ 873 Deactivation Feedback Modal 874 ================================ */ 875 876 .preview-ai-deactivation-overlay { 877 position: fixed; 878 inset: 0; 879 background: rgba(0, 0, 0, 0.6); 880 z-index: 100050; 881 display: flex; 882 align-items: center; 883 justify-content: center; 884 animation: previewAiFadeIn 0.2s ease; 885 } 886 887 @keyframes previewAiFadeIn { 888 from { opacity: 0; } 889 to { opacity: 1; } 890 } 891 892 @keyframes previewAiSlideUp { 893 from { opacity: 0; transform: translateY(20px); } 894 to { opacity: 1; transform: translateY(0); } 895 } 896 897 .preview-ai-deactivation-modal { 898 background: #fff; 899 border-radius: 12px; 900 padding: 32px; 901 width: 480px; 902 max-width: 90vw; 903 max-height: 85vh; 904 overflow-y: auto; 905 position: relative; 906 box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); 907 animation: previewAiSlideUp 0.25s ease; 908 } 909 910 .preview-ai-deactivation-close { 911 position: absolute; 912 top: 12px; 913 right: 12px; 914 background: none; 915 border: none; 916 font-size: 24px; 917 line-height: 1; 918 cursor: pointer; 919 color: #8c8f94; 920 padding: 4px 8px; 921 border-radius: 4px; 922 transition: all 0.15s; 923 } 924 925 .preview-ai-deactivation-close:hover { 926 background: #f0f0f1; 927 color: #1d2327; 928 } 929 930 .preview-ai-deactivation-header { 931 text-align: center; 932 margin-bottom: 24px; 933 } 934 935 .preview-ai-deactivation-icon { 936 display: inline-flex; 937 align-items: center; 938 justify-content: center; 939 width: 48px; 940 height: 48px; 941 background: linear-gradient(135deg, #6366f1, #8b5cf6); 942 border-radius: 12px; 943 margin-bottom: 12px; 944 color: #fff; 945 } 946 947 .preview-ai-deactivation-header h3 { 948 margin: 0 0 6px; 949 font-size: 18px; 950 font-weight: 600; 951 color: #1d2327; 952 } 953 954 .preview-ai-deactivation-header p { 955 margin: 0; 956 color: #646970; 957 font-size: 13px; 958 } 959 960 .preview-ai-deactivation-reasons { 961 list-style: none; 962 margin: 0; 963 padding: 0; 964 } 965 966 .preview-ai-deactivation-reasons li { 967 margin: 0; 968 padding: 0; 969 } 970 971 .preview-ai-deactivation-reasons label { 972 display: flex; 973 align-items: center; 974 gap: 10px; 975 padding: 10px 12px; 976 margin-bottom: 4px; 977 border-radius: 8px; 978 cursor: pointer; 979 transition: background 0.15s; 980 font-size: 13px; 981 color: #1d2327; 982 } 983 984 .preview-ai-deactivation-reasons label:hover { 985 background: #f6f7f7; 986 } 987 988 .preview-ai-deactivation-reasons input[type="radio"] { 989 margin: 0; 990 flex-shrink: 0; 991 } 992 993 .preview-ai-deactivation-reasons input[type="radio"]:checked + span { 994 font-weight: 500; 995 color: #4C82F7; 996 } 997 998 .preview-ai-deactivation-details { 999 width: 100%; 1000 margin-top: 12px; 1001 padding: 10px 12px; 1002 border: 1px solid #c3c4c7; 1003 border-radius: 6px; 1004 font-size: 13px; 1005 resize: vertical; 1006 transition: border-color 0.15s; 1007 box-sizing: border-box; 1008 } 1009 1010 .preview-ai-deactivation-details:focus { 1011 border-color: #4C82F7; 1012 outline: none; 1013 box-shadow: 0 0 0 1px #4C82F7; 1014 } 1015 1016 .preview-ai-deactivation-actions { 1017 display: flex; 1018 justify-content: space-between; 1019 align-items: center; 1020 margin-top: 20px; 1021 padding-top: 16px; 1022 border-top: 1px solid #f0f0f1; 1023 } 1024 1025 #preview-ai-deactivation-skip { 1026 color: #646970; 1027 border-color: #c3c4c7; 1028 } 1029 1030 #preview-ai-deactivation-skip:hover { 1031 color: #1d2327; 1032 border-color: #8c8f94; 1033 } 1034 1035 #preview-ai-deactivation-submit { 1036 background: #4C82F7; 1037 border-color: #4C82F7; 1038 box-shadow: none; 1039 text-shadow: none; 1040 } 1041 1042 #preview-ai-deactivation-submit:hover:not(:disabled) { 1043 background: #3a6fd9; 1044 border-color: #3a6fd9; 1045 } 1046 1047 #preview-ai-deactivation-submit:disabled { 1048 opacity: 0.5; 1049 cursor: not-allowed; 1050 } -
preview-ai/trunk/admin/js/preview-ai-admin.js
r3455295 r3464259 332 332 } 333 333 334 // ================================ 335 // Deactivation Feedback Modal 336 // ================================ 337 338 var $deactivateLink = $( '#the-list [data-slug="' + ( previewAiAdmin.pluginSlug || 'preview-ai' ) + '"] .deactivate a' ); 339 340 if ( $deactivateLink.length ) { 341 var deactivateUrl = $deactivateLink.attr( 'href' ); 342 var $modal = $( '#preview-ai-deactivation-modal' ); 343 var $form = $( '#preview-ai-deactivation-form' ); 344 var $details = $( '#preview-ai-deactivation-details' ); 345 var $submitBtn = $( '#preview-ai-deactivation-submit' ); 346 347 $deactivateLink.on( 'click', function( e ) { 348 e.preventDefault(); 349 $modal.fadeIn( 200 ); 350 } ); 351 352 // Close modal. 353 $( '#preview-ai-deactivation-close' ).on( 'click', function() { 354 $modal.fadeOut( 150 ); 355 } ); 356 357 // Close on overlay click. 358 $modal.on( 'click', function( e ) { 359 if ( $( e.target ).is( $modal ) ) { 360 $modal.fadeOut( 150 ); 361 } 362 } ); 363 364 // Close on Esc key. 365 $( document ).on( 'keydown', function( e ) { 366 if ( 27 === e.keyCode && $modal.is( ':visible' ) ) { 367 $modal.fadeOut( 150 ); 368 } 369 } ); 370 371 // Show/hide details textarea based on selection. 372 $form.on( 'change', 'input[name="preview_ai_deactivation_reason"]', function() { 373 $submitBtn.prop( 'disabled', false ); 374 var val = $( this ).val(); 375 if ( 'other' === val || 'not_working' === val || 'not_compatible' === val ) { 376 $details.slideDown( 150 ); 377 } else { 378 $details.slideUp( 150 ); 379 } 380 } ); 381 382 // Skip & Deactivate. 383 $( '#preview-ai-deactivation-skip' ).on( 'click', function() { 384 window.location.href = deactivateUrl; 385 } ); 386 387 // Submit & Deactivate. 388 $form.on( 'submit', function( e ) { 389 e.preventDefault(); 390 var reason = $form.find( 'input[name="preview_ai_deactivation_reason"]:checked' ).val(); 391 392 if ( ! reason ) { 393 window.location.href = deactivateUrl; 394 return; 395 } 396 397 $submitBtn.prop( 'disabled', true ).text( previewAiAdmin.i18n.deactivating || 'Deactivating...' ); 398 399 $.ajax( { 400 url: previewAiAdmin.ajaxUrl, 401 type: 'POST', 402 data: { 403 action: 'preview_ai_deactivation_feedback', 404 nonce: previewAiAdmin.deactivationNonce, 405 reason: reason, 406 details: $details.val() || '' 407 }, 408 complete: function() { 409 window.location.href = deactivateUrl; 410 } 411 } ); 412 } ); 413 } 414 334 415 }); 335 416 -
preview-ai/trunk/includes/class-preview-ai.php
r3455839 r3464259 239 239 $this->loader->add_action( 'wp_ajax_preview_ai_reverify_compatibility', $plugin_admin, 'handle_reverify_compatibility' ); 240 240 $this->loader->add_action( 'wp_ajax_preview_ai_toggle_product', $plugin_admin, 'handle_toggle_product' ); 241 242 // Deactivation feedback modal. 243 $this->loader->add_action( 'admin_footer', $plugin_admin, 'render_deactivation_modal' ); 244 $this->loader->add_action( 'wp_ajax_preview_ai_deactivation_feedback', $plugin_admin, 'handle_deactivation_feedback' ); 241 245 242 246 // Action Scheduler hook for background catalog processing. -
preview-ai/trunk/preview-ai.php
r3460856 r3464259 7 7 * 8 8 * @wordpress-plugin 9 * Plugin Name: Preview AI – Virtual Try-On for WooCommerce9 * Plugin Name: Virtual Try-On for WooCommerce – Preview AI 10 10 * Plugin URI: https://previewai.app/ 11 11 * Description: Preview AI is a plugin that allows your customers to preview your products in real-time using AI image generation. 12 * Version: 1.2. 012 * Version: 1.2.1 13 13 * Author: Preview AI 14 14 * Author URI: https://profiles.wordpress.org/previewai/ 15 15 * License: GPL-2.0+ 16 16 * License URI: http://www.gnu.org/licenses/gpl-2.0.txt 17 * Requires Plugins: woocommerce 17 18 * Text Domain: preview-ai 18 19 * Domain Path: /languages … … 27 28 * Current plugin version. 28 29 */ 29 define( 'PREVIEW_AI_VERSION', '1.2. 0' );30 define( 'PREVIEW_AI_VERSION', '1.2.1' ); 30 31 define( 'PREVIEW_AI_PLUGIN_BASENAME', plugin_basename( __FILE__ ) ); 31 32 -
preview-ai/trunk/readme.txt
r3460856 r3464259 1 === Preview AI – Virtual Try-On for WooCommerce===1 === Virtual Try-On for WooCommerce – Preview AI === 2 2 Contributors: previewai 3 3 Donate link: https://previewai.app/ … … 8 8 WC requires at least: 8.0 9 9 WC tested up to: 10.5.1 10 Stable tag: 1.2. 010 Stable tag: 1.2.1 11 11 License: GPLv2 or later 12 12 License URI: http://www.gnu.org/licenses/gpl-2.0.html … … 160 160 == Changelog == 161 161 162 = 1.2.1 = 163 – Renamed plugin to "Virtual Try-On for WooCommerce – Preview AI" 164 – Added WooCommerce as a required plugin dependency (Requires Plugins header) 165 – Added optional deactivation feedback survey to help us improve the plugin 166 162 167 = 1.2.0 = 163 168 – Added optional Advanced Analytics (opt-in): link try-on usage to purchases for accurate ROI measurement. … … 183 188 184 189 = 1.0.1 = 185 – Updated plugin name to " Preview AI – Virtual Try-On for WooCommerce"190 – Updated plugin name to "Virtual Try-On for WooCommerce – Preview AI" 186 191 187 192 = 1.0.0 = … … 193 198 == Upgrade Notice == 194 199 200 = 1.2.1 = 201 Plugin renamed, WooCommerce declared as required dependency, and added deactivation feedback survey. 202 195 203 = 1.2.0 = 196 204 Adds end-to-end conversion attribution: see exactly how virtual try-on impacts your sales.
Note: See TracChangeset
for help on using the changeset viewer.