Plugin Directory

Changeset 3253459


Ignore:
Timestamp:
03/10/2025 03:56:02 PM (13 months ago)
Author:
limbobp
Message:

Update plugin to version 1.0.2

Location:
limbo/trunk
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • limbo/trunk/admin/export/js/limbo-export.js

    r3198812 r3253459  
    1616
    1717    function createProductElement(product) {
    18         const mainImage = product.images && product.images.length > 0
    19             ? product.images[0].thumbnail
    20             : limboExportData.placeholderImage;
     18        console.log('Product:', product.name);
     19        console.log('Image URLs:', product.images.map(img => img.full));
     20       
     21        let mainImage = limboExportData.placeholderImage;
     22        if (product.images && Array.isArray(product.images) && product.images.length > 0) {
     23            mainImage = product.images[0].thumbnail || product.images[0].full || limboExportData.placeholderImage;
     24        }
    2125
    2226        const attributesHtml = product.attributes.map(attr => `
     
    4145                     alt="${product.name}"
    4246                     class="product-thumbnail"
     47                     onerror="this.src='${limboExportData.placeholderImage}'"
    4348                >
    4449                <div class="product-info">
     
    227232            exportButton.textContent = limboExportData.strings.exporting;
    228233
     234            // Get the site URL
     235            const shopDomain = window.location.origin;
     236
    229237            const response = await fetch(limboExportData.ajaxurl, {
    230238                method: 'POST',
     
    236244                    security: limboExportData.nonce,
    237245                    productIds: Array.from(selectedProducts),
    238                     sellerId: JSON.parse(localStorage.getItem('limboUserData'))?.id
     246                    sellerId: JSON.parse(localStorage.getItem('limboUserData'))?.id,
     247                    shopDomain: shopDomain
    239248                })
    240249            });
     
    249258                throw new Error(limboExportData.strings.noProductsFormatted);
    250259            }
     260
     261            console.log('Formatted products for export:', data.data);
     262            data.data.forEach(product => {
     263                console.log(`Image URLs for product "${product.productName}":`, product.images);
     264            });
    251265
    252266            const backendResponse = await fetch(limboExportData.apiEndpoint, {
     
    258272                body: JSON.stringify({
    259273                    woocommerceProducts: data.data,
    260                     sellerId: JSON.parse(localStorage.getItem('limboUserData'))?.id
     274                    sellerId: JSON.parse(localStorage.getItem('limboUserData'))?.id,
     275                    shopDomain: shopDomain
    261276                })
    262277            });
  • limbo/trunk/admin/export/limbo-export-functions.php

    r3198812 r3253459  
    111111function limbo_get_product_images($product) {
    112112    $images = array();
    113     $image_ids = array_merge(
     113    $image_ids = array_filter(array_merge(
    114114        array($product->get_image_id()),
    115115        $product->get_gallery_image_ids()
    116     );
     116    ));
    117117
    118118    foreach ($image_ids as $image_id) {
    119119        if (!empty($image_id)) {
    120             $image_full = wp_get_attachment_image_src($image_id, 'full');
    121             $image_thumb = wp_get_attachment_image_src($image_id, 'thumbnail');
    122 
    123             if ($image_full && $image_thumb) {
     120            $file_path = get_attached_file($image_id);
     121           
     122            if ($file_path && file_exists($file_path)) {
     123                // Get image content and convert to base64
     124                $image_data = file_get_contents($file_path);
     125                $mime_type = mime_content_type($file_path);
     126                $base64 = base64_encode($image_data);
     127                $base64_url = "data:{$mime_type};base64,{$base64}";
     128               
    124129                $images[] = array(
    125130                    'id' => $image_id,
    126                     'full' => $image_full[0],
    127                     'thumbnail' => $image_thumb[0],
     131                    'full' => $base64_url,
     132                    'thumbnail' => $base64_url,
    128133                    'alt' => get_post_meta($image_id, '_wp_attachment_image_alt', true)
    129134                );
     
    131136        }
    132137    }
     138
     139    // If no images found, return array with placeholder
     140    if (empty($images)) {
     141        $images[] = array(
     142            'id' => 0,
     143            'full' => LIMBO_PLUGIN_URL . 'assets/images/placeholder.png',
     144            'thumbnail' => LIMBO_PLUGIN_URL . 'assets/images/placeholder.png',
     145            'alt' => __('Product image placeholder', 'limbo')
     146        );
     147    }
     148
    133149    return $images;
    134150}
     
    163179    $product_ids_raw = isset($_POST['productIds']) ? sanitize_text_field(wp_unslash($_POST['productIds'])) : '';
    164180    $seller_id_raw = isset($_POST['sellerId']) ? sanitize_text_field(wp_unslash($_POST['sellerId'])) : '';
     181    $shop_domain = isset($_POST['shopDomain']) ? esc_url_raw(wp_unslash($_POST['shopDomain'])) : '';
    165182
    166183    // Validate required data
    167     if (empty($product_ids_raw) || empty($seller_id_raw)) {
     184    if (empty($product_ids_raw) || empty($seller_id_raw) || empty($shop_domain)) {
    168185        wp_send_json_error(['message' => __('Missing required data', 'limbo')]);
    169186        return;
     
    191208            }, $images);
    192209
     210            // Get categories and ensure we have a default value
    193211            $categories = wp_get_post_terms($product_id, 'product_cat', ['fields' => 'names']);
    194             $category = !empty($categories) ? $categories[0] : '';
     212            $category = !empty($categories) ? $categories[0] : 'Uncategorized';
    195213
    196214            $attributes = limbo_get_product_attributes($product);
     
    208226
    209227            $formatted_products[] = [
     228                'id' => $product_id,
    210229                'productName' => sanitize_text_field($product->get_name()),
    211230                'description' => wp_kses_post($product->get_description() ?: $product->get_short_description()),
     
    213232                'sellerId' => $seller_id,
    214233                'quantity' => absint(50),
    215                 'images' => array_map('esc_url_raw', $image_urls),
     234                'images' => $image_urls,
    216235                'category' => sanitize_text_field($category),
    217236                'options' => $options,
  • limbo/trunk/admin/import/js/limbo-import.js

    r3198812 r3253459  
    166166
    167167        try {
    168             // Get the full product data for selected IDs
    169168            const selectedProductsData = allProducts.filter(product =>
    170169                selectedProducts.has(product._id)
    171170            );
     171
     172            console.log('Selected products data:', selectedProductsData);
     173            console.log('Selected products count:', selectedProductsData.length);
    172174
    173175            const response = await fetch(limboImportData.ajaxurl, {
     
    179181                    action: 'limbo_import_products',
    180182                    security: limboImportData.nonce,
    181                     products: JSON.stringify(selectedProductsData)
     183                    products: JSON.stringify(selectedProductsData),
     184                    shopDomain: window.location.origin
    182185                })
    183186            });
    184187
    185             const result = await response.json();
     188            const responseText = await response.text();
     189            console.log('Raw server response:', responseText);
     190
     191            let result;
     192            try {
     193                result = JSON.parse(responseText);
     194            } catch (e) {
     195                console.error('Failed to parse server response:', responseText);
     196                throw new Error('Server returned invalid JSON response');
     197            }
     198
     199            console.log('Parsed response:', result);
    186200
    187201            if (result.success) {
    188202                alert(`Successfully imported ${result.data.imported} products!`);
    189                 // Clear selections after successful import
     203                if (result.data.errors && result.data.errors.length > 0) {
     204                    console.warn('Import warnings:', result.data.errors);
     205                }
    190206                selectedProducts.clear();
    191207                updateSelectedCount();
    192                 // Optionally refresh the product list
    193208                displayProducts();
    194209            } else {
    195                 throw new Error(result.data.message || 'Import failed');
     210                throw new Error(result.data?.message || 'Import failed');
    196211            }
    197212        } catch (error) {
    198213            console.error('Import error:', error);
    199             alert('Error importing products. Please try again.');
     214            alert(`Error importing products: ${error.message}`);
    200215        } finally {
    201216            importButton.disabled = false;
  • limbo/trunk/admin/import/limbo-import-functions.php

    r3198812 r3253459  
    1818 */
    1919function limbo_handle_product_import() {
     20    // Increase memory limit for large imports using WordPress function
     21    wp_raise_memory_limit('admin');
     22   
    2023    try {
    21         check_ajax_referer('limbo-import-nonce', 'security');
     24        // Verify nonce first
     25        if (!check_ajax_referer('limbo-import-nonce', 'security', false)) {
     26            wp_send_json_error([
     27                'message' => 'Security check failed',
     28                'code' => 'security_error'
     29            ]);
     30            return;
     31        }
    2232
    2333        if (!current_user_can('manage_woocommerce')) {
    24             wp_send_json_error(['message' => esc_html__('Permission denied', 'limbo')]);
     34            wp_send_json_error([
     35                'message' => 'Permission denied',
     36                'code' => 'permission_error'
     37            ]);
    2538            return;
    2639        }
    2740
    28         // Validate and sanitize input
     41        // Validate input
    2942        if (!isset($_POST['products'])) {
    30             wp_send_json_error(['message' => esc_html__('No products data received', 'limbo')]);
     43            wp_send_json_error([
     44                'message' => 'No products data received',
     45                'code' => 'no_data'
     46            ]);
    3147            return;
    3248        }
    3349
     50        // Get and decode products data with proper sanitization
    3451        $products_raw = sanitize_text_field(wp_unslash($_POST['products']));
    35 
    36         if (!is_string($products_raw)) {
    37             wp_send_json_error(['message' => esc_html__('Invalid products data format', 'limbo')]);
     52        $products = json_decode($products_raw, true);
     53
     54        // JSON decode error check
     55        if (json_last_error() !== JSON_ERROR_NONE) {
     56            wp_send_json_error([
     57                'message' => 'Invalid JSON data: ' . json_last_error_msg(),
     58                'code' => 'json_error'
     59            ]);
    3860            return;
    3961        }
    4062
    41         $products = json_decode($products_raw, true);
    42         if (json_last_error() !== JSON_ERROR_NONE) {
    43             wp_send_json_error(['message' => esc_html__('Invalid JSON data', 'limbo')]);
     63        if (!is_array($products)) {
     64            wp_send_json_error([
     65                'message' => 'Products data must be an array',
     66                'code' => 'invalid_format'
     67            ]);
    4468            return;
    4569        }
    4670
    47         if (!is_array($products)) {
    48             wp_send_json_error(['message' => esc_html__('Products data must be an array', 'limbo')]);
    49             return;
    50         }
     71        limbo_log_error("Starting import of " . count($products) . " products");
    5172
    5273        $imported_count = 0;
     
    5576        foreach ($products as $product) {
    5677            try {
    57                 // Sanitize and validate product data
     78                limbo_log_error("Processing product: " . $product['productName']);
     79               
     80                // Sanitize product data
    5881                $product_data = limbo_sanitize_product_data($product);
    5982               
     
    6386                if ($product_id) {
    6487                    $imported_count++;
    65                     limbo_log_error("Successfully imported product: " . $product_data['productName']);
     88                    limbo_log_error("Successfully created product ID: " . $product_id);
     89                } else {
     90                    throw new Exception("Failed to create product");
    6691                }
    6792
    6893            } catch (Exception $e) {
    69                 /* translators: %1$s: product name, %2$s: error message */
    70                 $errors[] = sprintf(
    71                     esc_html__('Error importing %1$s: %2$s', 'limbo'),
    72                     isset($product['productName']) ? sanitize_text_field($product['productName']) : 'unknown product',
     94                $error_msg = sprintf(
     95                    'Error importing %s: %s',
     96                    isset($product['productName']) ? $product['productName'] : 'unknown product',
    7397                    $e->getMessage()
    7498                );
    75                 limbo_log_error("Import error: " . $e->getMessage());
     99                $errors[] = $error_msg;
     100                limbo_log_error($error_msg);
    76101            }
    77102        }
     
    80105            wp_send_json_success([
    81106                'imported' => $imported_count,
    82                 'errors' => $errors
     107                'errors' => $errors,
     108                'message' => "Successfully imported {$imported_count} products"
    83109            ]);
    84110        } else {
    85111            wp_send_json_error([
    86                 'message' => esc_html__('No products were imported', 'limbo'),
    87                 'errors' => $errors
    88             ]);
    89         }
     112                'message' => 'No products were imported',
     113                'errors' => $errors,
     114                'code' => 'import_failed'
     115            ]);
     116        }
     117
    90118    } catch (Exception $e) {
    91         limbo_log_error("Import error: " . $e->getMessage());
    92         /* translators: %s: error message */
     119        limbo_log_error("Critical import error: " . $e->getMessage());
    93120        wp_send_json_error([
    94             'message' => sprintf(
    95                 esc_html__('Import failed: %s', 'limbo'),
    96                 $e->getMessage()
    97             ),
     121            'message' => 'Import failed: ' . $e->getMessage(),
     122            'code' => 'critical_error',
    98123            'errors' => isset($errors) ? $errors : []
    99124        ]);
     
    191216        }
    192217
     218        // Create connection with Limbo server
     219        $connection_result = limbo_create_product_connection($product_id, $product_data['_id'], $product_data['sellerId']);
     220        if (!$connection_result['success']) {
     221            limbo_log_error("Warning: Failed to create Limbo connection: " . $connection_result['message']);
     222        }
     223
    193224        return $product_id;
    194225    }
     
    277308 */
    278309function limbo_handle_product_images($product_id, $wc_product, $images) {
     310    limbo_log_error("=== Starting product image import for product ID: " . $product_id . " ===");
     311    limbo_log_error("Number of images to process: " . count($images));
     312   
    279313    $image_ids = array();
    280    
    281     foreach ($images as $image_url) {
    282         if (empty($image_url)) continue;
    283        
     314    $failed_images = array();
     315   
     316    foreach ($images as $index => $image_url) {
     317        limbo_log_error("Processing image " . ($index + 1) . " of " . count($images));
     318       
     319        if (empty($image_url)) {
     320            limbo_log_error("❌ Empty image URL at index " . $index);
     321            continue;
     322        }
     323
     324        // Add small delay between image processing to prevent overload
     325        if ($index > 0) {
     326            sleep(1);
     327        }
     328
    284329        $image_id = limbo_import_image($image_url);
     330       
    285331        if ($image_id) {
    286332            $image_ids[] = $image_id;
     333            limbo_log_error("✓ Image " . ($index + 1) . " successfully processed");
     334        } else {
     335            $failed_images[] = $image_url;
     336            limbo_log_error("❌ Failed to process image " . ($index + 1));
    287337        }
    288338    }
    289339   
    290340    if (!empty($image_ids)) {
    291         set_post_thumbnail($product_id, $image_ids[0]);
    292         $wc_product->set_image_id($image_ids[0]);
    293        
    294         $gallery_image_ids = array_slice($image_ids, 1);
    295         if (!empty($gallery_image_ids)) {
    296             $wc_product->set_gallery_image_ids($gallery_image_ids);
    297         }
    298        
    299         $wc_product->save();
    300     }
    301 }
    302 
    303 /**
    304  * Import an image from URL
     341        // Set featured image
     342        $featured_result = set_post_thumbnail($product_id, $image_ids[0]);
     343        limbo_log_error($featured_result ? "✓ Featured image set" : "❌ Failed to set featured image");
     344       
     345        // Set gallery images
     346        $gallery_ids = array_slice($image_ids, 1);
     347        if (!empty($gallery_ids)) {
     348            $wc_product->set_gallery_image_ids($gallery_ids);
     349            limbo_log_error("✓ Gallery images set: " . implode(', ', $gallery_ids));
     350        }
     351       
     352        $save_result = $wc_product->save();
     353        limbo_log_error($save_result ? "✓ Product saved with images" : "❌ Failed to save product with images");
     354    }
     355
     356    limbo_log_error("=== End product image import ===");
     357    return count($image_ids);
     358}
     359
     360/**
     361 * Import an image from URL using WordPress Filesystem
    305362 */
    306363function limbo_import_image($url) {
     
    309366    require_once(ABSPATH . 'wp-admin/includes/image.php');
    310367
     368    // Detailed URL logging
     369    limbo_log_error("=== Starting image import ===");
     370    limbo_log_error("Original URL: " . $url);
     371   
     372    // URL cleanup and validation
     373    $url = str_replace(' ', '%20', $url);
     374    $decoded_url = urldecode($url);
     375    limbo_log_error("Decoded URL: " . $decoded_url);
     376
    311377    if (empty($url) || !filter_var($url, FILTER_VALIDATE_URL)) {
     378        limbo_log_error("❌ Invalid URL format: " . $url);
    312379        return false;
    313380    }
    314381
    315     $existing_attachment = attachment_url_to_postid($url);
    316     if ($existing_attachment) {
    317         return $existing_attachment;
    318     }
    319 
     382    // Test URL accessibility
     383    $response = wp_remote_head($url);
     384    if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
     385        limbo_log_error("❌ URL not accessible: " . $url);
     386        return false;
     387    }
     388
     389    // Download file
    320390    $tmp = download_url($url);
    321391    if (is_wp_error($tmp)) {
     392        limbo_log_error("❌ Download failed: " . $tmp->get_error_message());
    322393        return false;
    323394    }
    324395
     396    // Prepare file array
    325397    $file_array = array(
    326         'name' => basename(wp_parse_url($url, PHP_URL_PATH)),
     398        'name' => wp_basename($url),
    327399        'tmp_name' => $tmp
    328400    );
    329401
     402    // Handle sideload
    330403    $id = media_handle_sideload($file_array, 0);
    331404
    332405    if (is_wp_error($id)) {
     406        limbo_log_error("❌ Sideload failed: " . $id->get_error_message());
    333407        wp_delete_file($tmp);
    334408        return false;
    335409    }
    336410
     411    limbo_log_error("✓ Successfully imported image. ID: " . $id);
     412    limbo_log_error("=== End image import ===");
     413   
    337414    return $id;
    338415}
     
    393470
    394471/**
    395  * Log error messages
     472 * Log error messages with proper debug checking
    396473 */
    397474function limbo_log_error($message) {
    398     $logger = wc_get_logger();
    399     $logger->error(
    400         sprintf(
    401             '[Limbo Plugin] %s',
    402             wp_privacy_anonymize_data($message, 'text')
     475    if (defined('WP_DEBUG') && WP_DEBUG) {
     476        if (function_exists('wc_get_logger')) {
     477            $logger = wc_get_logger();
     478            $logger->error($message, ['source' => 'limbo-import']);
     479        }
     480    }
     481}
     482
     483/**
     484 * Check filesystem permissions using WordPress Filesystem
     485 */
     486function limbo_check_filesystem_permissions() {
     487    global $wp_filesystem;
     488    require_once(ABSPATH . 'wp-admin/includes/file.php');
     489    WP_Filesystem();
     490   
     491    $upload_dir = wp_upload_dir();
     492    $base_dir = $upload_dir['basedir'];
     493   
     494    limbo_log_error("Checking upload directory permissions:");
     495    limbo_log_error("Upload base dir: " . $base_dir);
     496    limbo_log_error("Is writable: " . ($wp_filesystem->is_writable($base_dir) ? 'Yes' : 'No'));
     497    limbo_log_error("Directory permissions: " . substr(sprintf('%o', $wp_filesystem->getchmod($base_dir)), -4));
     498   
     499    // Get process user info safely
     500    $process_user = function_exists('posix_getpwuid') ? posix_getpwuid(posix_geteuid())['name'] : 'Unknown';
     501    limbo_log_error("PHP process user: " . $process_user);
     502}
     503
     504/**
     505 * Create connection between WooCommerce and Limbo products
     506 */
     507function limbo_create_product_connection($wc_product_id, $limbo_product_id, $seller_id) {
     508    // Verify nonce
     509    if (!check_ajax_referer('limbo-import-nonce', 'security', false)) {
     510        return array(
     511            'success' => false,
     512            'message' => 'Security check failed'
     513        );
     514    }
     515
     516    // Validate and sanitize shop domain
     517    $shop_domain = '';
     518    if (isset($_POST['shopDomain'])) {
     519        $shop_domain = sanitize_text_field(wp_unslash($_POST['shopDomain']));
     520    }
     521   
     522    if (empty($shop_domain)) {
     523        return array(
     524            'success' => false,
     525            'message' => 'Invalid shop domain'
     526        );
     527    }
     528   
     529    $body = array(
     530        'woocommerceProductId' => (string)$wc_product_id,
     531        'limboProductId' => $limbo_product_id,
     532        'sellerId' => $seller_id,
     533        'shopDomain' => $shop_domain
     534    );
     535
     536    $response = wp_remote_post('https://www.serverlimbo.com/seller/woocommerce/create-connection', array(
     537        'method' => 'POST',
     538        'timeout' => 45,
     539        'redirection' => 5,
     540        'httpversion' => '1.0',
     541        'blocking' => true,
     542        'headers' => array(
     543            'Content-Type' => 'application/json'
    403544        ),
    404         array('source' => 'limbo-import')
     545        'body' => json_encode($body),
     546        'cookies' => array()
     547    ));
     548
     549    if (is_wp_error($response)) {
     550        limbo_log_error("Connection API error: " . $response->get_error_message());
     551        return array(
     552            'success' => false,
     553            'message' => $response->get_error_message()
     554        );
     555    }
     556
     557    $response_body = json_decode(wp_remote_retrieve_body($response), true);
     558    $status_code = wp_remote_retrieve_response_code($response);
     559
     560    if ($status_code !== 201) {
     561        limbo_log_error("Connection API failed with status {$status_code}");
     562        return array(
     563            'success' => false,
     564            'message' => isset($response_body['message']) ? $response_body['message'] : 'Unknown error'
     565        );
     566    }
     567
     568    limbo_log_error("Successfully created connection with Limbo server");
     569    return array(
     570        'success' => true,
     571        'message' => 'Connection created successfully',
     572        'data' => $response_body
    405573    );
    406574}
  • limbo/trunk/admin/import/limbo-import.php

    r3198812 r3253459  
    3939    wp_localize_script('limbo-import-script', 'limboImportData', array(
    4040        'ajaxurl' => admin_url('admin-ajax.php'),
    41         'nonce' => wp_create_nonce('limbo-import-nonce')
     41        'nonce' => wp_create_nonce('limbo-import-nonce'),
     42        'pluginUrl' => plugins_url('', dirname(__FILE__))
    4243    ));
    4344
  • limbo/trunk/admin/limbo-connections/js/limbo-connections.js

    r3198812 r3253459  
    193193
    194194            try {
    195                 const shopDomain = window.location.hostname;
     195                const shopDomain = window.location.origin;
    196196                const connectionsToDelete = Array.from(selectedConnections).map(connectionId => ({
    197197                    shopDomain,
     
    384384            console.log('User data found:', parsedUserData.id);
    385385           
    386             const shopDomain = window.location.hostname;
     386            const shopDomain = window.location.origin;
    387387            console.log('Shop domain:', shopDomain);
    388388
  • limbo/trunk/js/product-page.js

    r3198812 r3253459  
    22    $('#limbo-redirect-btn').on('click', async function() {
    33        const woocommerceProductId = $(this).data('product-id');
    4         const shopDomain = limboData.shopDomain;
     4        const shopDomain = window.location.origin;
    55       
    66        try {
    7             // Call the Limbo API to get the Limbo product ID
    8             const response = await fetch('https://www.serverlimbo.com/seller/woocommerce/get-limbo-product-id', {
     7            const response = await fetch('https://www.serverlimbo.com/seller/woocommerce/get-connection-by-woocommerce-product-id', {
    98                method: 'POST',
    109                headers: {
     
    1918            const data = await response.json();
    2019           
    21             if (data.success && data.limboProductId) {
    22                 // Open new window with Limbo product page
    23                 window.open(limboData.limboPublicUrl + data.limboProductId, '_blank');
     20            if (data.success && data.connection && data.connection.limboProductId) {
     21                // Open popup window
     22                const width = 500;
     23                const height = 600;
     24                const left = (window.screen.width / 2) - (width / 2);
     25                const top = (window.screen.height / 2) - (height / 2);
     26               
     27                window.open(
     28                    limboData.limboPublicUrl + data.connection.limboProductId,
     29                    'LimboProduct',
     30                    `width=${width},height=${height},top=${top},left=${left},resizable=yes,scrollbars=yes`
     31                );
    2432            } else {
    2533                console.error('Failed to get Limbo product ID:', data.message);
    26                 alert(data.message || 'This product is not available on Limbo.');
     34                alert(data.message || 'No connection found for this product.');
    2735            }
    2836        } catch (error) {
  • limbo/trunk/limbo.php

    r3198812 r3253459  
    134134add_action( 'admin_enqueue_scripts', 'limbo_enqueue_admin_scripts' );
    135135
    136 // Add Limbo button to product page
     136// Add Limbo button and modal to product page
    137137function limbo_add_button() {
    138138    global $product;
    139139    if ( $product ) {
    140         echo '<button type="button" id="limbo-redirect-btn" class="button alt" data-product-id="' . esc_attr( $product->get_id() ) . '">' . esc_html__( 'View on Limbo', 'limbo' ) . '</button>';
     140        ?>
     141        <!-- Limbo Button -->
     142        <button type="button" id="limbo-redirect-btn" class="button alt" data-product-id="<?php echo esc_attr( $product->get_id() ); ?>">
     143            <?php echo esc_html__( 'View on Limbo', 'limbo' ); ?>
     144        </button>
     145       
     146        <!-- Limbo Modal -->
     147        <div id="limbo-modal" class="limbo-modal">
     148            <div class="limbo-modal-content">
     149                <div class="limbo-modal-header">
     150                    <span class="limbo-close">&times;</span>
     151                </div>
     152                <div class="limbo-modal-body">
     153                    <iframe id="limbo-iframe" frameborder="0" allowfullscreen></iframe>
     154                </div>
     155            </div>
     156        </div>
     157        <?php
    141158    }
    142159}
  • limbo/trunk/readme.txt

    r3198812 r3253459  
    33Tags: woocommerce, products, import, export
    44Requires at least: 5.0
    5 Tested up to: 6.7
    6 Stable tag: 1.0.1
     5Tested up to: 6.8
     6Stable tag: 1.0.2
    77Requires PHP: 7.2
    88License: GPLv2 or later
     
    269269
    270270== Changelog ==
    271 = 1.0.1 =
     271= 1.0.2 =
     272* Added new features and improved existing ones
     273* Fixed bugs and enhanced overall functionality
     274* Updated documentation and added more detailed instructions
     275* Improved user interface and usability
     276* Added new configuration options
     277* Enhanced security measures and data protection
    272278* Initial release
Note: See TracChangeset for help on using the changeset viewer.