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 for Add to Cart Form:
Code for AJAX Add to Cart in scripts.js file
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.
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:
<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"> </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=""></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=""></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=""> <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:
// ---- 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.
Comment