Plugin Directory

Changeset 3401530


Ignore:
Timestamp:
11/24/2025 04:46:09 AM (4 months ago)
Author:
codemenschen
Message:

Version 4.6.0 - Released: November 24, 2025

Location:
gift-voucher
Files:
975 added
8 edited

Legend:

Unmodified
Added
Removed
  • gift-voucher/trunk/assets/js/voucher-script.js

    r3375423 r3401530  
    307307    $('#voucherPaymentButton').on('click', function () {
    308308
     309        var $btn = $(this);
     310
     311        // Prevent duplicate submissions: if already clicked, ignore subsequent clicks
     312        if ($btn.hasClass('clicked')) {
     313            return false;
     314        }
     315
    309316        if (!$('input[name=acceptVoucherTerms]').is(':checked')) {
    310317            alert(frontend_ajax_object.accept_terms);
    311318            return false;
     319        }
     320
     321        // Mark button as clicked and disable it to prevent multiple submissions
     322        $btn.addClass('clicked').prop('disabled', true);
     323
     324        // Disable all form controls inside the voucher form to prevent any interaction
     325        if (typeof form !== 'undefined' && form && form.length) {
     326            form.find('input,select,textarea,button').prop('disabled', true);
     327        } else {
     328            $('#voucher-multistep-form').find('input,select,textarea,button').prop('disabled', true);
    312329        }
    313330
     
    331348        var style = $('#chooseStyle').val();
    332349        var code = $('.codeCard').val();
    333 
    334         $('#voucher-multistep-form #voucherPaymentButton').addClass('clicked');
    335350
    336351        $.ajax({
     
    375390            error: function () {
    376391                alert(frontend_ajax_object.error_occur);
    377                 $('#voucher-multistep-form #voucherPaymentButton').removeClass('clicked');
     392                // Remove clicked state and re-enable the button and all form controls so user can try again
     393                $('#voucherPaymentButton').removeClass('clicked').prop('disabled', false);
     394                if (typeof form !== 'undefined' && form && form.length) {
     395                    form.find('input,select,textarea,button').prop('disabled', false);
     396                } else {
     397                    $('#voucher-multistep-form').find('input,select,textarea,button').prop('disabled', false);
     398                }
    378399            }
    379400        });
  • gift-voucher/trunk/gift-voucher.php

    r3394006 r3401530  
    77 * Author: Codemenschen GmbH
    88 * Author URI: https://www.codemenschen.at/
    9  * Version: 4.5.9
     9 * Version: 4.6.0
    1010 * Text Domain: gift-voucher
    1111 * Domain Path: /languages
     
    3939}
    4040
    41 define('WPGIFT_VERSION', '4.5.9');
     41define('WPGIFT_VERSION', '4.6.0');
    4242define('WPGIFT__MINIMUM_WP_VERSION', '4.0');
    4343define('WPGIFT__PLUGIN_DIR', untrailingslashit(plugin_dir_path(__FILE__)));
     
    722722{
    723723  $word = html_entity_decode(wp_strip_all_tags(stripslashes($word)), ENT_NOQUOTES, 'UTF-8');
    724   $word = iconv('UTF-8', 'windows-1252', $word);
     724  // Keep UTF-8 encoding to support emoji and special characters
     725  // Removed: iconv('UTF-8', 'windows-1252', $word) which was stripping emoji
    725726  return $word;
     727}
     728
     729/**
     730 * Convert UTF-8 text to ANSI for PDF compatibility
     731 * Removes emoji and non-Latin characters but preserves common special chars
     732 * @param string $text UTF-8 text that may contain emoji
     733 * @return string Text safe for FPDF rendering
     734 */
     735function wpgv_text_to_pdf_safe($text)
     736{
     737  // First, try to convert to windows-1252 (Latin-1 Extended)
     738  // This preserves more characters than pure ASCII
     739  $text = html_entity_decode(wp_strip_all_tags(stripslashes($text)), ENT_NOQUOTES, 'UTF-8');
     740
     741  // Remove emoji and other Unicode symbols
     742  // This regex removes most emoji and special Unicode characters
     743  $text = preg_replace('/[\x{1F300}-\x{1F9FF}]/u', '', $text);  // Emoji ranges
     744  $text = preg_replace('/[\x{2600}-\x{27BF}]/u', '', $text);    // Miscellaneous symbols
     745  $text = preg_replace('/[\x{FE00}-\x{FE0F}]/u', '', $text);    // Variation selectors
     746  $text = preg_replace('/[\x{200B}-\x{200D}]/u', '', $text);    // Zero-width characters
     747
     748  // Try to convert to windows-1252 which supports accented characters
     749  if (function_exists('iconv')) {
     750    $text = iconv('UTF-8', 'windows-1252//IGNORE', $text);
     751  }
     752
     753  return $text;
    726754}
    727755function wpgv_mailvarstr_multiple($string, $setting_options, $voucher_options_results, $voucherpdf_link)
  • gift-voucher/trunk/include/voucher_metabox.php

    r3186322 r3401530  
    228228  $sizearr = array('', '1000px x 760px', '1000px x 1500px', '1000px x 750px');
    229229  for ($i = 1; $i < 4; $i++) {
    230     echo '<p class="post-attributes-label-wrapper"><label class="post-attributes-label" for="style' . esc_html($i) . '_image">Image - Style ' . esc_html($i) . ' (Recommended: ' . esc_html($sizearr[$i]) . '):</label></p>';
     230    // Append a short note about supported file formats so admins don't pick WEBP by mistake
     231    $supported_note = ' ' . esc_html__('Supported formats: JPG, PNG only.', 'gift-voucher');
     232    echo '<p class="post-attributes-label-wrapper"><label class="post-attributes-label" for="style' . esc_html($i) . '_image">Image - Style ' . esc_html($i) . ' (Recommended: ' . esc_html($sizearr[$i]) . ').' . $supported_note . '</label></p>';
    231233    ?>
    232234    <img class="image_src<?php echo esc_attr($i); ?>" src="" width="100" style="display: none;" />
     
    249251            })
    250252            .on('select', function() {
    251               var attachment = custom_uploader.state().get('selection').first().toJSON();
    252               $('.image_src<?php echo esc_html($i); ?>').attr('src', attachment.url).show();
    253               $('.image_url<?php echo esc_html($i); ?>').val(attachment.id);
    254               $('.remove_image<?php echo esc_html($i); ?>').show();
     253                  var attachment = custom_uploader.state().get('selection').first().toJSON();
     254                  // Client-side validation: only allow JPG/JPEG and PNG images.
     255                  var mime = attachment.mime || attachment.mime_type || attachment.type || '';
     256                  var url = attachment.url || '';
     257                  var allowedMimes = ['image/jpeg', 'image/png'];
     258                  var allowedExt = ['jpg', 'jpeg', 'png'];
     259                  var ok = false;
     260                  if (mime && allowedMimes.indexOf(mime) !== -1) {
     261                    ok = true;
     262                  } else if (url) {
     263                    var parts = url.split('.');
     264                    var ext = parts.length ? parts[parts.length - 1].toLowerCase() : '';
     265                    if (allowedExt.indexOf(ext) !== -1) ok = true;
     266                  }
     267                  if (!ok) {
     268                    alert('<?php echo esc_js( esc_html__("Only JPG and PNG images are supported for Image - Style. Please choose a JPG or PNG file.", "gift-voucher") ); ?>');
     269                    return;
     270                  }
     271                  $('.image_src<?php echo esc_html($i); ?>').attr('src', attachment.url).show();
     272                  $('.image_url<?php echo esc_html($i); ?>').val(attachment.id);
     273                  $('.remove_image<?php echo esc_html($i); ?>').show();
    255274            })
    256275            .open();
     
    292311  $events_meta['style3_image'] = sanitize_text_field($_POST['style3_image']);
    293312
     313  // Validate selected images: only allow JPEG and PNG. If an unsupported
     314  // image (eg. WEBP) is selected we will NOT save it and display an admin notice.
     315  $allowed_mimes = array('image/jpeg', 'image/png');
     316  $invalid_image = false;
     317  foreach (array('style1_image', 'style2_image', 'style3_image') as $img_key) {
     318    $val = $events_meta[$img_key];
     319    if (empty($val)) {
     320      continue;
     321    }
     322    // If value is an attachment ID, use its mime type. Otherwise try to
     323    // detect by file URL/filename.
     324    $mime = '';
     325    if (is_numeric($val)) {
     326      $att_id = absint($val);
     327      $att_post = get_post($att_id);
     328      if ($att_post && isset($att_post->post_mime_type)) {
     329        $mime = $att_post->post_mime_type;
     330      }
     331    } else {
     332      $filetype = wp_check_filetype($val);
     333      if (!empty($filetype['type'])) {
     334        $mime = $filetype['type'];
     335      }
     336    }
     337    if ($mime === '' || !in_array($mime, $allowed_mimes, true)) {
     338      // clear invalid selection so it won't be saved
     339      $events_meta[$img_key] = '';
     340      $invalid_image = true;
     341    }
     342  }
     343
    294344  // Add values of $events_meta as custom fields
    295345  foreach ($events_meta as $key => $value) { // Cycle through the $events_meta array!
     
    306356    if (!$value) delete_post_meta($post_id, $key); // Delete if blank
    307357  }
     358
     359  // If any invalid images were detected, add a query arg so we can show
     360  // an admin notice after redirect back to the edit screen.
     361  if (!empty($invalid_image)) {
     362    add_filter('redirect_post_location', 'wpgv_add_image_error_query_arg', 99);
     363  }
    308364}
     365
     366/**
     367 * Add query arg to post redirect location so admin notice can be shown.
     368 */
     369function wpgv_add_image_error_query_arg($location)
     370{
     371  return add_query_arg('wpgv_image_error', '1', $location);
     372}
     373
     374/**
     375 * Show admin notice when an unsupported image type was selected for voucher style.
     376 */
     377function wpgv_image_error_admin_notice()
     378{
     379  if (!empty($_GET['wpgv_image_error'])) {
     380    echo '<div class="notice notice-warning is-dismissible"><p>' . esc_html__('Warning: Only JPG and PNG images are supported for "Image - Style". The selected image was not saved.', 'gift-voucher') . '</p></div>';
     381  }
     382}
     383add_action('admin_notices', 'wpgv_image_error_admin_notice');
    309384
    310385add_action('save_post', 'wpt_save_voucher_meta', 1, 2); // save the voucher meta fields
  • gift-voucher/trunk/readme.txt

    r3394006 r3401530  
    44Requires at least: 4.0
    55Tested up to: 6.8.3
    6 Stable tag: 4.5.9
     6Stable tag: 4.6.0
    77Requires PHP: 5.6
    88License: GPLv2 or later
     
    226226== Changelog ==
    227227
     228= Version 4.6.0 - Released: November 24, 2025 =
     229* Fix: Personal Message and user input fields now support emoji and special characters in PDF exports.
     230* Improvement: Removed iconv conversion in `wpgv_em()` to preserve UTF-8 input.
     231* Improvement: Added `wpgv_text_to_pdf_safe()` to safely handle user text for PDF output, stripping or replacing unsupported characters where necessary for FPDF.
     232* Update: Replaced `wpgv_em()` with `wpgv_text_to_pdf_safe()` for user input fields (Personal Message, Your Name, Recipient Name, Email) in all PDF templates.
     233* Fix: Prevent saving unsupported image types for voucher "Image - Style". The admin-side meta now validates images and only accepts JPG/JPEG and PNG; unsupported selections are cleared on save.
     234* Fix: Admin notice added to inform the user when an unsupported image format (e.g. WEBP, SVG) was selected and not saved.
     235* Improvement: Added client-side validation to the Item Details media selector to block non-JPG/PNG files at selection time (improves UX and prevents ambiguous preview errors).
     236* Update: Item Details labels now include a short note: "Supported formats: JPG, PNG only." to guide administrators.
     237* Fix: Prevent duplicate orders by disabling the Pay Now button and all controls inside `#voucher-multistep-form` during submission; controls are re-enabled only on AJAX error.
     238* Improvement: Added client-side guard to ignore repeated clicks on Pay Now to avoid multiple order creation. Files changed: `assets/js/voucher-script.js`
     239
    228240= Version 4.5.9 - Released: November 12, 2025 =
    229241* Fix: The plugin generated 192 characters of unexpected output during activation. If you notice "headers already sent" messages, problems with syndication feeds or other issues, try deactivating or removing this plugin.
  • gift-voucher/trunk/templates/pdfstyles/receipt.php

    r3179739 r3401530  
    6262$receipt->SetFont('Arial', '');
    6363$receipt->SetXY(250, 200);
    64 $receipt->Cell(0, 0, ' ' . wpgv_em($for), 0, 1, 'L', 0);
     64$receipt->Cell(0, 0, ' ' . wpgv_text_to_pdf_safe($for), 0, 1, 'L', 0);
    6565
    6666//From
     
    7171    $receipt->SetFont('Arial', '');
    7272    $receipt->SetXY(250, 220);
    73     $receipt->Cell(0, 0, ' ' . wpgv_em($from), 0, 1, 'L', 0);
     73    $receipt->Cell(0, 0, ' ' . wpgv_text_to_pdf_safe($from), 0, 1, 'L', 0);
    7474}
    7575
     
    8080$receipt->SetFont('Arial', '');
    8181$receipt->SetXY(250, 240);
    82 $receipt->Cell(0, 0, ' ' . wpgv_em($email), 0, 1, 'L', 0);
     82$receipt->Cell(0, 0, ' ' . wpgv_text_to_pdf_safe($email), 0, 1, 'L', 0);
    8383
    8484//Amount
  • gift-voucher/trunk/templates/pdfstyles/style1.php

    r2698686 r3401530  
    2828    $pdf->SetFontSize(25);
    2929    $pdf->MultiCell(550, 25, wpgv_em(get_the_title($itemid)), 0, 'C');
    30    
     30
    3131    //Description
    3232    $pdf->SetXY(30, 500);
     
    5353$pdf->SetTextColor(85,85,85);
    5454$pdf->SetFontSize(15);
    55 $pdf->Cell(265,30,' '.wpgv_em($for),0,1,'L',1);
     55$pdf->Cell(265,30,' '.wpgv_text_to_pdf_safe($for),0,1,'L',1);
    5656
    5757if($buyingfor != 'yourself') {
     
    6666    $pdf->SetTextColor(85,85,85);
    6767    $pdf->SetFontSize(15);
    68     $pdf->Cell(265,30,' '.wpgv_em($from),0,1,'L',1);
     68    $pdf->Cell(265,30,' '.wpgv_text_to_pdf_safe($from),0,1,'L',1);
    6969}
    7070
     
    107107$pdf->Cell(546,100,'',0,1,'L',1);
    108108$pdf->SetXY(35, 672);
    109 $pdf->MultiCell(543,20,wpgv_em($message),0,1,'L',1);
     109$pdf->MultiCell(543,20,wpgv_text_to_pdf_safe($message),0,1,'L',1);
    110110
    111111//Coupon Code
  • gift-voucher/trunk/templates/pdfstyles/style2.php

    r2698686 r3401530  
    5555$pdf->SetTextColor(85,85,85);
    5656$pdf->SetFontSize(15);
    57 $pdf->Cell(265,40,' '.wpgv_em($for),0,1,'L',1);
     57$pdf->Cell(265,40,' '.wpgv_text_to_pdf_safe($for),0,1,'L',1);
    5858
    5959if($buyingfor != 'yourself') {
     
    6868    $pdf->SetTextColor(85,85,85);
    6969    $pdf->SetFontSize(15);
    70     $pdf->Cell(265,40,' '.wpgv_em($from),0,1,'L',1);
     70    $pdf->Cell(265,40,' '.wpgv_text_to_pdf_safe($from),0,1,'L',1);
    7171}
    7272
     
    9898
    9999$pdf->SetXY(35, 458);
    100 $pdf->MultiCell(540,23,wpgv_em($message),0,1,'L',1);
     100$pdf->MultiCell(540,23,wpgv_text_to_pdf_safe($message),0,1,'L',1);
    101101//Date of Expiry
    102102$pdf->SetXY(30, 620);
  • gift-voucher/trunk/templates/pdfstyles/style3.php

    r2698686 r3401530  
    5454$pdf->SetTextColor(85,85,85);
    5555$pdf->SetFontSize(15);
    56 $pdf->Cell(265,40,' '.wpgv_em($for),0,1,'L',1);
     56$pdf->Cell(265,40,' '.wpgv_text_to_pdf_safe($for),0,1,'L',1);
    5757
    5858if($buyingfor != 'yourself') {
     
    6767    $pdf->SetTextColor(85,85,85);
    6868    $pdf->SetFontSize(15);
    69     $pdf->Cell(265,40,' '.wpgv_em($from),0,1,'L',1);
     69    $pdf->Cell(265,40,' '.wpgv_text_to_pdf_safe($from),0,1,'L',1);
    7070}
    7171
     
    9797
    9898$pdf->SetXY(35, 358);
    99 $pdf->MultiCell(540,23,wpgv_em($message),0,1,'L',1);
     99$pdf->MultiCell(540,23,wpgv_text_to_pdf_safe($message),0,1,'L',1);
    100100//Date of Expiry
    101101$pdf->SetXY(30, 520);
Note: See TracChangeset for help on using the changeset viewer.