
Save Prestashop Custom fields on “Add to cart” – Part 1
Having to save product customization before adding to the cart can be quite annoying. Some customers might even forget to do it if fields are not required. In the first part of this two-stage tutorial, we will see how to save customization text when the add to cart button is pressed.
- Version used: Prestashop 1.6
Save Prestashop Custom fields on “Add to cart” – Part 2 »
We do need ajax
Before starting, it’s important to notice we do need to activate the ajax cart, as we will be catching the fields’ content and serialize it; then intercept the “add” method of the ajax cart and send another ajax request to the product controller, to save customized data before anything is added to the cart itself.
That said, we need to modify two javascript files, and one controller:
- ajax-cart.js
- tools.js
- ProductController.php
While we can use an override for the controller, and clone the template for the ajax-cart file, we really need to amend the original tools.js, located in the main js/ folder.
That said, in this first part we will only deal with text inputs, leaving the file upload to the next tutorial.
Ajax-cart.php
After reaching the product page (of a product having a text customization field, of course), open up themes/*yourthemename*/modules/blockcart/ajax-cart.js
Locate the following method
add : function(idProduct, idCombination, addedFromProductPage, callerElement, quantity, whishlist)
It should be around line 271 in Prestashop 1.6.0.14
Inside it, at the very beginning, right before:
if (addedFromProductPage && !checkCustomizations())
Add the following:
if(addedFromProductPage && $('#customizationForm').length > 0) { $('#quantityBackup').val($('#quantity_wanted').val()); customAction = $('#customizationForm').attr('action'); $('body select[id^="group_"]').each(function() { customAction = customAction.replace(new RegExp(this.id + '=\\d+'), this.id +'=' + this.value); }); }
Explanation: first, we have to make sure we are adding to the cart from the single product view (it would make no sense in the list) and that the current item does have customization fields. What comes inside is almost a 1:1 copy of the saveCustomization() method we can find in the product.js file. We need to modify the action so that it considers attributes as well. customAction is the url we will send the ajax POST to.
Therefore, continuing from it:
if(addedFromProductPage && $('#customizationForm').length > 0) { $('#quantityBackup').val($('#quantity_wanted').val()); customAction = $('#customizationForm').attr('action'); $('body select[id^="group_"]').each(function() { customAction = customAction.replace(new RegExp(this.id + '=\\d+'), this.id +'=' + this.value); }); // ajax to product page with custom action var customization_entries = $('#customizationForm').serialize(); $.ajax({ async:false, type: 'POST', data: customization_entries+ '&ajax=1', dataType: 'json', url: customAction, success: function(data){ } }) }
Explanation: after serializing the array’s entries (remember we are only using text fields for the time being), we send them over to the actionUrl (that is, the ProductController) so it can further take care of our data. Notice I also appended &ajax=1 as the controller will need to know it’s receiving an ajax request. Time to move to the override!
IMPORTANT! Make sure you set the ajax request as async:false, otherwise the add to cart will run before our customization is saved!
Note: do not try adding the product to the cart at this stage, it will not work, saying the customization field is required.
The Product Controller
Having our javascript all setup, let’s deal with the product controller. To make it quick, I will append the new method to the original file, but you can feel free to use an override instead. What it needs is a method that handles data before anything is outputted to screen. Fortunately, we don’t even need to create it, it’s built in, and it is named postProcess. The only issue is that the ProductController.php file doesn’t use, so we need to append it ourselves.
Open up controllers/front/ProductController.php, reach the end of the file, and add the following (make sure you are inside the class!)
public function postProcess() { if (Tools::getValue('ajax') && Tools::isSubmit('submitCustomizedDatas')) { if (!$this->context->cart->id && isset($_COOKIE[$this->context->cookie->getName()])) { $this->context->cart->add(); $this->context->cookie->id_cart = (int)$this->context->cart->id; } $this->pictureUpload(); $this->textRecord(); $this->formTargetFormat(); if($this->errors) { $error_list = implode('; ', $this->errors); die(Tools::jsonEncode(array('errors' => $error_list))); } else die(Tools::jsonEncode(array('success' => true))); } }
Explanation: We only need to run this method for our ajax call, and only when customization data is sent over. After checking it, we simply run the methods Prestashop uses when submitting a regular customization form:
$this->pictureUpload(); $this->textRecord(); $this->formTargetFormat();
Please notice pictureUpload is currently not being used, as we are not uploading anything. Also, we need to create a new cart in case it does not exist, before adding the text to it, so it has an id to deal with.
Then, we check for errors, sending them back to the ajax-cart.js file if there are, otherwise returning success. Since we want to make sure data has been saved, let’s go back to our JS for a second, and do something on the “success” method of the ajax call:
if(addedFromProductPage && $('#customizationForm').length > 0) { $('#quantityBackup').val($('#quantity_wanted').val()); customAction = $('#customizationForm').attr('action'); $('body select[id^="group_"]').each(function() { customAction = customAction.replace(new RegExp(this.id + '=\\d+'), this.id +'=' + this.value); }); // ajax to product page with custom action var customization_entries = $('#customizationForm').serialize(); $.ajax({ type: 'POST', data: customization_entries+ '&ajax=1', dataType: 'json', url: customAction, success: function(data){ if(typeof(data.errors) !== 'undefined') { alert('Error while saving customization data'); return; } } }) }
We basically only added this part
if(typeof(data.errors) !== 'undefined') { alert('Error while saving customization data'); return; }
To the success handler, that triggers when the ajax call is successful. Of course, you might want to expand this, and add a further level of checks to make sure data has really been saved. However, if the field is required, your product will not be added to the cart, in any case.
At this point, try writing something in the field, then click add to cart. What? Not working? Why? Prestashop can be nasty to deal with; we have to perform one last modification.
Tools.js
The last file we need to deal with might be a pain in case you upgrade. Therefore, make sure you keep a backup of the modification and/or write these steps somewhere, in case you need to apply them again. Open up js/tools.js. What we are interested in is the checkCustomizations method:
function checkCustomizations() { var pattern = new RegExp(' ?filled ?'); if (typeof customizationFields != 'undefined') for (var i = 0; i < customizationFields.length; i++) { /* If the field is required and empty then we abort */ if (parseInt(customizationFields[i][1]) == 1 && ($('#' + customizationFields[i][0]).html() == '' || $('#' + customizationFields[i][0]).text() != $('#' + customizationFields[i][0]).val()) && !pattern.test($('#' + customizationFields[i][0]).attr('class'))) return false; } return true; }
Pay attention to the following line
function checkCustomizations() { if (parseInt(customizationFields[i][1]) == 1 && ($('#' + customizationFields[i][0]).html() == '' || $('#' + customizationFields[i][0]).text() != $('#' + customizationFields[i][0]).val()) && !pattern.test($('#' + customizationFields[i][0]).attr('class'))) return false;
This is what is currently preventing us from saving our customization. Actually, it gets saved, but the product is not added to the cart.
let’s get rid of a good portion of it
if (parseInt(customizationFields[i][1]) == 1 && ($('#' + customizationFields[i][0]).val() == '')) return false;
The only thing we are doing to check it, is making sure it has a value. THat is all we need for now!
Refresh and test, it should be working now!
Next up…
Saving text customization fields when hitting the add to cart button was not too complicated. Things will get really nasty in the next tutorial, when we will deal with asynchronous file uploads! Stay tuned!