Plugin Directory

Changeset 3464259


Ignore:
Timestamp:
02/18/2026 11:22:04 AM (6 weeks ago)
Author:
previewai
Message:

Release 1.2.1 – Add feedback form

Location:
preview-ai
Files:
6 edited
26 copied

Legend:

Unmodified
Added
Removed
  • preview-ai/tags/1.2.1/admin/class-preview-ai-admin.php

    r3455295 r3464259  
    225225
    226226        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">&times;</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();
    227340    }
    228341
     
    308421            'previewAiAdmin',
    309422            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(
    317432                    'error'        => __( 'An error occurred.', 'preview-ai' ),
    318433                    'apiPending'   => __( '(API integration pending)', 'preview-ai' ),
  • preview-ai/tags/1.2.1/admin/css/preview-ai-admin.css

    r3455295 r3464259  
    869869    padding: 10px 16px !important;
    870870}
     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  
    332332        }
    333333
     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
    334415    });
    335416
  • preview-ai/tags/1.2.1/includes/class-preview-ai.php

    r3455839 r3464259  
    239239        $this->loader->add_action( 'wp_ajax_preview_ai_reverify_compatibility', $plugin_admin, 'handle_reverify_compatibility' );
    240240        $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' );
    241245
    242246        // Action Scheduler hook for background catalog processing.
  • preview-ai/tags/1.2.1/preview-ai.php

    r3460856 r3464259  
    77 *
    88 * @wordpress-plugin
    9  * Plugin Name:       Preview AI – Virtual Try-On for WooCommerce
     9 * Plugin Name:       Virtual Try-On for WooCommerce – Preview AI
    1010 * Plugin URI:        https://previewai.app/
    1111 * 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.0
     12 * Version:           1.2.1
    1313 * Author:            Preview AI
    1414 * Author URI:        https://profiles.wordpress.org/previewai/
    1515 * License:           GPL-2.0+
    1616 * License URI:       http://www.gnu.org/licenses/gpl-2.0.txt
     17 * Requires Plugins:  woocommerce
    1718 * Text Domain:       preview-ai
    1819 * Domain Path:       /languages
     
    2728 * Current plugin version.
    2829 */
    29 define( 'PREVIEW_AI_VERSION', '1.2.0' );
     30define( 'PREVIEW_AI_VERSION', '1.2.1' );
    3031define( 'PREVIEW_AI_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
    3132
  • 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 ===
    22Contributors: previewai
    33Donate link: https://previewai.app/
     
    88WC requires at least: 8.0
    99WC tested up to: 10.5.1
    10 Stable tag: 1.2.0
     10Stable tag: 1.2.1
    1111License: GPLv2 or later
    1212License URI: http://www.gnu.org/licenses/gpl-2.0.html
     
    160160== Changelog ==
    161161
     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
    162167= 1.2.0 =
    163168– Added optional Advanced Analytics (opt-in): link try-on usage to purchases for accurate ROI measurement.
     
    183188
    184189= 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"
    186191
    187192= 1.0.0 =
     
    193198== Upgrade Notice ==
    194199
     200= 1.2.1 =
     201Plugin renamed, WooCommerce declared as required dependency, and added deactivation feedback survey.
     202
    195203= 1.2.0 =
    196204Adds 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  
    225225
    226226        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">&times;</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();
    227340    }
    228341
     
    308421            'previewAiAdmin',
    309422            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(
    317432                    'error'        => __( 'An error occurred.', 'preview-ai' ),
    318433                    'apiPending'   => __( '(API integration pending)', 'preview-ai' ),
  • preview-ai/trunk/admin/css/preview-ai-admin.css

    r3455295 r3464259  
    869869    padding: 10px 16px !important;
    870870}
     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  
    332332        }
    333333
     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
    334415    });
    335416
  • preview-ai/trunk/includes/class-preview-ai.php

    r3455839 r3464259  
    239239        $this->loader->add_action( 'wp_ajax_preview_ai_reverify_compatibility', $plugin_admin, 'handle_reverify_compatibility' );
    240240        $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' );
    241245
    242246        // Action Scheduler hook for background catalog processing.
  • preview-ai/trunk/preview-ai.php

    r3460856 r3464259  
    77 *
    88 * @wordpress-plugin
    9  * Plugin Name:       Preview AI – Virtual Try-On for WooCommerce
     9 * Plugin Name:       Virtual Try-On for WooCommerce – Preview AI
    1010 * Plugin URI:        https://previewai.app/
    1111 * 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.0
     12 * Version:           1.2.1
    1313 * Author:            Preview AI
    1414 * Author URI:        https://profiles.wordpress.org/previewai/
    1515 * License:           GPL-2.0+
    1616 * License URI:       http://www.gnu.org/licenses/gpl-2.0.txt
     17 * Requires Plugins:  woocommerce
    1718 * Text Domain:       preview-ai
    1819 * Domain Path:       /languages
     
    2728 * Current plugin version.
    2829 */
    29 define( 'PREVIEW_AI_VERSION', '1.2.0' );
     30define( 'PREVIEW_AI_VERSION', '1.2.1' );
    3031define( 'PREVIEW_AI_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
    3132
  • preview-ai/trunk/readme.txt

    r3460856 r3464259  
    1 === Preview AI – Virtual Try-On for WooCommerce ===
     1=== Virtual Try-On for WooCommerce – Preview AI ===
    22Contributors: previewai
    33Donate link: https://previewai.app/
     
    88WC requires at least: 8.0
    99WC tested up to: 10.5.1
    10 Stable tag: 1.2.0
     10Stable tag: 1.2.1
    1111License: GPLv2 or later
    1212License URI: http://www.gnu.org/licenses/gpl-2.0.html
     
    160160== Changelog ==
    161161
     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
    162167= 1.2.0 =
    163168– Added optional Advanced Analytics (opt-in): link try-on usage to purchases for accurate ROI measurement.
     
    183188
    184189= 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"
    186191
    187192= 1.0.0 =
     
    193198== Upgrade Notice ==
    194199
     200= 1.2.1 =
     201Plugin renamed, WooCommerce declared as required dependency, and added deactivation feedback survey.
     202
    195203= 1.2.0 =
    196204Adds end-to-end conversion attribution: see exactly how virtual try-on impacts your sales.
Note: See TracChangeset for help on using the changeset viewer.