Add Invisible reCaptcha v2 to PROD page for AJAX Add to Cart Form

Collapse
X
 
  • Time
  • Show
Clear All
new posts

  • SidFeyDesigns
    replied
    I think this is a bit out of my skill set to get working properly.

    Even if I did get it to work, I just realized that if a user has javascript disabled, then they won't be able to add products to the cart. Can't seem to find a current noscript fallback.

    This makes me want to remove reCaptcha for our checkout as well.

    Somehow we still have lots of users with javascript disabled.

    Which is why we have noscript fallbacks all over our site.

    I guess we will have to deal with the bot spam.

    Or perhaps add a hidden field that won't allow forms to submit if it is filled out by a bot.

    Thanks for the help anyways though.

    Appreciate it.

    Leave a comment:


  • Matt Zimmermann
    replied
    I would append to the button's onClick call.

    Leave a comment:


  • SidFeyDesigns
    replied
    Okay.

    Do i also need to change the add to cart button html to onsubmit? or just the function in the Scripts.js file?

    Code:
                        <span onclick="document.forms.add.action = '&mvtj:urls:BASK:auto;'; document.forms.add.elements.Action.value = 'ADPR';">
                            <input type="submit" value="Add to Cart" data-value="Add to Cart" id="js-add-to-cart" class="button button-block corners uppercase add-to-cart black bg-sky bold" />
                        </span>

    Leave a comment:


  • Matt Zimmermann
    replied
    It should be.

    Leave a comment:


  • SidFeyDesigns
    replied
    Okay. Thanks guys.

    I would prefer it to run after everything is validated.

    That way the reCaptcha is only executed if all the required attributes are filled out or selected.

    Would that be a similar situation as you suggested Matt?

    Leave a comment:


  • Matt Zimmermann
    replied
    I'm not really familiar with adding reCaptcha, however if you need that function to run prior to the submit, I would modify the add to cart function to be onSubmit of the form and add the execute call as an onClick of the button.

    Leave a comment:


  • Bruce - PhosphorMedia
    replied
    I'd think the most obvious point would be at the start. And if not true, just fail silently.

    Leave a comment:


  • Add Invisible reCaptcha v2 to PROD page for AJAX Add to Cart Form

    We get a lot of bot activity spamming our PROD page attributes which creates carts with spammy links and information.

    So, to combat that, I would like to add the invisible recaptcha v2 to our PROD page for the Add to Cart form.

    We are on the most current update for Miva running the Suivant ReadyTheme.

    Here is what I have done so far using google's guide and some other more generic online guides:

    Code Added to Head Tag:

    Code:
        <script type="text/javascript">
            var onSubmit = function(response) {
                document.getElementById("js-purchase-product").submit(); // send response to your backend service
            };
        </script>
    Code for Add to Cart Form:

    Code:
            <form method="post" action="&mvte:urls:BASK:auto;" name="add" id="js-purchase-product">
                <input type="hidden" name="Old_Screen" value="&mvte:global:Screen;" />
                <input type="hidden" name="Old_Search" value="&mvte:global:Search;" />
                <input type="hidden" name="Action" value="ADPR" />
                <input type="hidden" name="Product_Code" value="&mvte:product:code;" />
                <input type="hidden" name="Category_Code" value="&mvte:global:category_code;" />
                <input type="hidden" name="Offset" value="&mvte:global:Offset;" />
                <input type="hidden" name="AllOffset" value="&mvte:global:AllOffset;" />
                <input type="hidden" name="CatListingOffset" value="&mvte:global:CatListingOffset;" />
                <input type="hidden" name="RelatedOffset" value="&mvte:global:RelatedOffset;" />
                <input type="hidden" name="SearchOffset" value="&mvte:global:SearchOffset;" />
                <div class="row">
                    <mvt:if expr="l.settings:product:inv_active OR l.settings:attributemachine:product:inv_active">
                        <div id="js-inventory-message" class="column whole print-hide">
                            <p>&mvt:product:inv_long;</p>
                        </div>
                    </mvt:if>
                    <div class="column whole">
                        <mvt:item name="customfields" param="Read_Product_Code( l.settings:product:code, 'familytree', g.familytree )" />
                        <mvt:if expr="NOT ISNULL g.familytree">
                            <div id="family-tree">&mvt:global:familytree;</div>
                        </mvt:if>
                        <mvt:item name="customfields" param="Read_Product_Code( l.settings:product:code, 'productbulletpoints', g.productbulletpoints )" />
                        <mvt:if expr="NOT ISNULL g.productbulletpoints">
                            <div>&mvt:global:productbulletpoints;</div>
                        </mvt:if>
                        <mvt:if expr="l.settings:product:code EQ 'EFTGH' OR l.settings:product:code EQ 'EFTSH'">
                            <div class="align-right">
                                <p class="italic">Done Adding Hearts to Your Tree?</p>
                                <a href="https://&mvt:global:domain:name;/&mvte:product:code;.html#RelatedProducts" rel="nofollow" class="button corners bg-sky mbm1-25" style="white-space:normal;height:auto;line-height:1;padding:0.5rem">Click Here to Add Discs</a>
                            </div>
                        <mvt:elseif expr="l.settings:product:code EQ 'EFTGD' OR l.settings:product:code EQ 'EFTSD' OR l.settings:product:code EQ 'EFTDD' OR l.settings:product:code EQ 'EFTDA' OR l.settings:product:code EQ 'EFTADB' OR l.settings:product:code EQ 'EFTPD'">
                            <div class="align-right">
                                <p class="italic">Done Adding Discs to Your Tree?</p>
                                <a href="https://&mvt:global:domain:name;/&mvte:product:code;.html#RelatedProducts" rel="nofollow" class="button corners bg-sky mbm1-25" style="white-space:normal;height:auto;line-height:1;padding:0.5rem">Click Here to Add Hearts</a>
                            </div>
                        </mvt:if>
                        <div id="js-purchase-message" class="message message-warning purchase-message"></div>
                    </div>
                    <div id="js-product-attributes" class="column whole product-attributes mtp1-25 mbm1-25">
                        <!--[if gte IE 9]><!-->
                            <script src="&mvte:global:theme_path;/js/jquery-3.4.0.min.js"></script>
                        <!--<![endif]-->
                        <mvt:item name="product_attributes" param="product:id" />
                    </div>
                    <mvt:if expr="g.hasSwatches">
                        <div class="column whole product-swatches">
                            <label>&mvte:global:swatch_prompt;</label>
                            <span id="js-swatch-name" class="bold swatch-name">&nbsp;</span>
                            <hr noshade />
                            <div id="js-swatches"></div>
                        </div>
                    </mvt:if>
    
    
                    <div class="column whole np">
                        <div class="g-recaptcha" data-sitekey="SITE-KEY-XXXXXXXXXXXX" data-callback="onSubmit" data-badge="inline" data-size="invisible"></div>
                        <script src="https://www.google.com/recaptcha/api.js" async defer></script>
                    </div>
                    <!-- end invisible recaptcha -->
    
    
                    <a id="AddToCart"></a>
                </div>
                <div class="row corners add-to-cart-wrap bg-lt-gray">
                    <div class="column whole align-center">
                        <div class="bold">Price Subtotal<br /><span class="small normal">(with options added)</span></div>
                        <mvt:if expr="l.settings:product:price GT 0">
                            <div id="js-price-value" class="h3 charcoal nm" data-base-price="&mvt:product:price;">&mvt:product:formatted_price;</div>
                        <mvt:else>
                            <div id="js-price-value" class="all-hidden" data-base-price="&mvt:product:price;"></div>
                        </mvt:if>
                        <br />
                    </div>
                    <div class="column whole small-half medium-whole large-two-fifths x-large-three-tenths print-hide">
                        <div class="row quantity-wrap align-center">
                            <div class="column whole np">
                                <span id="js-decrease-quantity" class="bg-gray corners-left decrease-quantity" unselectable="on"
                                 data-rt-icon="&#xf068;"></span>
                                <input type="tel" name="Quantity" value="1" id="l-quantity" class="align-center" style="font-size:1rem" />
                                <span id="js-increase-quantity" class="bg-gray corners-right increase-quantity" unselectable="on"
                                 data-rt-icon="&#xf067;"></span>
                            </div>
                        </div>
                        <mvt:if expr="NOT l.settings:subscription:mandatory">
                            <div class="row align-center">
                                <div class="column whole np">
                                    <span data-mmnodisable="true">
                                        <span onClick="document.forms.add.action = '&mvtj:urls:WISH:secure;'; document.forms.add.elements.Action.value = 'ATWL';" class="small" data-rt-icon="&#xf004;">
                                            <mvt:item name="buttons" param="AddToWishList" />
                                        </span>
                                    </span>
                                </div>
                            </div>
                        </mvt:if>
                    </div>
                    <div class="column whole small-half medium-whole large-three-fifths x-large-seven-tenths print-hide">
                        <div class="breaker small-all-hidden medium-all-shown large-all-hidden"></div>
    
    <mvt:comment> ========== for Attribute Magic module ========== </mvt:comment>
    <mvt:if expr="g.ATMG_Edit_Item">
                        <span onclick="document.forms.add.action = '&mvtj:urls:BASK:auto;'; document.forms.add.elements.Action.value = 'RGRP,ADPR';">
                            <input type="submit" value="Replace Item In Cart" data-value="Replace Item In Cart" id="add-to-cart" class="button button-block corners uppercase add-to-cart black bg-yellow bold" />
                            <input type="hidden" name="Basket_Group" value="&mvte:global:Basket_Group;" />
                        </span>
    <mvt:else>
                        <span onclick="document.forms.add.action = '&mvtj:urls:BASK:auto;'; document.forms.add.elements.Action.value = 'ADPR';">
                            <input type="submit" value="Add to Cart" data-value="Add to Cart" id="js-add-to-cart" class="button button-block corners uppercase add-to-cart black bg-sky bold" />
                        </span>
    </mvt:if>
                    </div>
                </div>
            </form>
    Code for AJAX Add to Cart in scripts.js file

    Code:
            // ---- AJAX Add To Cart ---- //
    
            function addToCart () {
    
                $('#js-add-to-cart').on('click', function (e) {
    
                    var purchaseForm = $('#js-purchase-product');
    
                    // Check the form is not currently submitting
    
                    if (purchaseForm.data('formstatus') !== 'submitting') {
    
                        // Set up variables
    
                        var form = purchaseForm,
    
                            formData = form.serialize(),
    
                            randomNo = Math.ceil(Math.random() * 1000000), // IE Hack: Creating random number to refresh ajax call
    
                            formUrl = form.attr('action'),
    
                            formMethod = form.attr('method'),
    
                            responseMessage = $('#js-purchase-message'),
    
                            miniBasket = $('#js-mini-basket-container'),
    
                            processingImage = $('#js-processing-purchase'),
    
                            purchaseButton = $(this),
    
                            purchaseButtonText = purchaseButton.val();
    
    
    
                        if (/\?/.test(formUrl)) {
    
                            formUrl = formUrl + '&v=' + randomNo;
    
                        }
    
                        else {
    
                            formUrl = formUrl + '?v=' + randomNo;
    
                        };
    
    
    
                        // Add status data to form
    
                        form.data('formstatus', 'submitting');
    
    
    
                        // Show processing message
    
                        processingImage.show();
    
                        purchaseButton.toggleDisabled().val('Processing...');
    
                        responseMessage.html('').hide();
    
    
    
                        // Send data to server for validation
    
                        $.ajax({
    
                            url: formUrl,
    
                            type: formMethod,
    
                            data: formData,
    
                            success: function(data, textStatus, jqXHR) {
    
                                if (data.search(/id="js-BASK"/i) != -1) {
    
                                    $('html, body').animate({scrollTop: '0px'}, 250);
    
                                    var responseMiniBasket = $(data).find('#js-mini-basket-container'),
    
                                        miniBasketCount = responseMiniBasket.contents()[1].getAttribute('data-itemcount'),
    
                                        miniBasketSubtotal = ' ' + responseMiniBasket.contents()[1].getAttribute('data-subtotal'),
    
                                        miniBasketLinkCount = $('#js-mini-basket-count, #js-mobile-basket-button .notification'),
    
                                        miniBasketLinkSubtotal = $('#js-mini-basket-subtotal');
    
    
    
                                    miniBasketLinkCount.text(miniBasketCount); // Update basket quantity (display only)
    
                                    miniBasketLinkSubtotal.text(miniBasketSubtotal); // Update basket subtotal (display only)
    
    
    
                                    miniBasket.html(responseMiniBasket.contents()).addClass('open');
                                    $('.mini-basket-table-wrap').scrollTop($('.mini-basket-table-wrap')[0].scrollHeight);
    
                                    setTimeout(function () {
    
                                        miniBasket.removeClass('open');
    
                                        if ( $( "#family-tree" ).length ) {
    
                                            $(document).ready(function(){
                                                var url = "/family-tree-hearts-discs.html";
                                                $(location).attr('href',url);
                                            });
    
                                        };
    
                                        if ( $( "#wholesale-family-tree" ).length ) {
    
                                            $(document).ready(function(){
                                                var url = "/wholesale-family-tree-hearts-discs.html";
                                                $(location).attr('href',url);
                                            });
    
                                        };
    
                                    }, 3000);
    
                                    // Re-Initialize Attribute Machine (if it is active)
    
                                    if (typeof attrMachCall !== 'undefined') {
    
                                        attrMachCall.Initialize();
    
                                    };
    
                                }
    
                                else if(data.search(/id="js-PATR"/i) != -1) {
    
                                    var missingAttrs = [];
    
                                    form.find('.required').each(function () {
    
                                        missingAttrs.push(' ' + $(this).attr('title'));
    
                                    });
    
                                    responseMessage.html('All <em class="red">Required</em> options have not been selected.<br />Please review the following options: <span class="red">' + missingAttrs + '</span>.').fadeIn();
                                        $('html, body').animate({scrollTop: ($('#js-purchase-message').offset().top - 100)},500);
    
                                }
    
                                else if(data.search(/id="js-PLMT"/i) != -1) {
    
                                    responseMessage.html('We do not have enough of the Size/Color you have selected.<br />Please adjust your quantity.').fadeIn().delay(3000).fadeOut();
                                        $('html, body').animate({scrollTop: ($('#js-inventory-message').offset().top - 100)},500);
    
                                }
    
                                else if(data.search(/id="js-POUT"/i) != -1) {
    
                                    responseMessage.html('The Size/Color you have selected is out of stock.<br />Please review your options or check back later.').fadeIn().delay(3000).fadeOut();
                                        $('html, body').animate({scrollTop: ($('#js-inventory-message').offset().top - 100)},500); 
    
                                }
    
                                else {
    
                                    responseMessage.html('Please review options.').fadeIn().delay(3000).fadeOut();
                                        $('html, body').animate({scrollTop: ($('#js-purchase-message').offset().top - 100)},500);
    
                                };
    
    
    
                                // Hide processing message and reset formstatus
    
                                processingImage.hide();
    
                                purchaseButton.toggleDisabled().val(purchaseButtonText);
    
                                form.data('formstatus', 'idle');
    
                            },
    
                            error: function (jqXHR, textStatus, errorThrown) {
    
                            }
    
                        });
    
                    };
    
                    // Prevent form from submitting
    
                    e.stopImmediatePropagation();
                    e.preventDefault();
    
                });
    
            };
    
            var addToCart = new addToCart;

    The trouble I am having is:


    Where do I add grecaptcha.execute();?


    I want to keep the functionality of the AJAX Add to Cart and Form Validation.


    Here is a link to a product page for reference: https://www.loveisarose.com/ILYR11.html



    Thanks in advance for any help or light shed on the situation.
Working...
X