Extend Prestashop Customization Fields (Longer Input and HTML)

Prestashop Customization fields are useful, but very limited in the values they can accept. It this tutorial, we will see how to enable a longer input text in the customizable data, and HTML too!

Download Project Files

The easy part: a longer input text

Enabling a longer input text on the Prestashop customization fields is a piece of cake (alas, the easiest part of this tutorial). By default, customizable text data is saved in a VARCHAR field in the database, with a maximum length of 255. Thus, to add a longer string, it is enough to increase this value, or change the field type to TEXT. I will do the latter.

Login to your control panel, and reach your database with phpMyAdmin (or another software you use to manage the database). Once you have all the tables listed, click on ps_customized_data (note that your prefix might be other than ps_), and then on structure. Finally, hit change for the value field, as shown on the next picture:

Prestashop Customization Fields in the database

A dialog will open. Select TEXT as a new type from the dropdown, and remove 255 from Length / Values.

Prestashop Customization Fields - CHange the database value

Then hit save. We are done! The field now accepts longer data!
If you need the text to be REALLY long, you can try MEDIUMTEXT or LONGTEXT as a type. However, this is usually not needed.

Enabling HTML inputs on Customization fields

Okay, our texts are now as long as we want. But what if we also need to add some HTML? Say, we need to accept a widget code, or we are offering a web-related service and need this kind of data.
In this case, we need to use two overrides: ProductController.php and Cart.php. The former, to validate the field as clean HTML instead of simple text, the latter to properly format and escape tags when adding the entry to the database. Lastly, we will amend blockcart-json.tpl to ensure data is correctly saved if the ajax cart is enabled, without outputting parse errors.

The ProductController override

Let’s start by creating the ProductController override. Head over to override/controllers/front, and create a new file called ProductController.php. Inside, add the following content inside php tags:


Class ProductController extends ProductControllerCore
{

}

Now we need a method override. Specifically, we want to change the textRecord function. Locate the original ProductController.php, which you can find in controllers/front, scroll until you find the whole textRecord() function, which looks about like this (Prestashop 1.5.6 here!):

	protected function textRecord()
	{
		if (!$field_ids = $this->product->getCustomizationFieldIds())
			return false;

		$authorized_text_fields = array();
		foreach ($field_ids as $field_id)
			if ($field_id['type'] == Product::CUSTOMIZE_TEXTFIELD)
				$authorized_text_fields[(int)$field_id['id_customization_field']] = 'textField'.(int)$field_id['id_customization_field'];

		$indexes = array_flip($authorized_text_fields);
		foreach ($_POST as $field_name => $value)
			if (in_array($field_name, $authorized_text_fields) && !empty($value))
			{
				if (!Validate::isMessage($value))
					$this->errors[] = Tools::displayError('Invalid message');
				else
					$this->context->cart->addTextFieldToProduct($this->product->id, $indexes[$field_name], Product::CUSTOMIZE_TEXTFIELD, $value);
			}
			else if (in_array($field_name, $authorized_text_fields) && empty($value))
				$this->context->cart->deleteCustomizationToProduct((int)$this->product->id, $indexes[$field_name]);
	}

If your Prestashop version is different from mine, copy your own function, otherwise you can use this. Paste the whole method inside the override we just created.

Let’s now have a closer look at it. Can you see where it says !Validate::isMessage($value) ? We want HTML, so change it to !Validate::isCleanHtml($value). Nothing more to do here! The final override:

<?php

Class ProductController extends ProductControllerCore
{
	protected function textRecord()
	{
		if (!$field_ids = $this->product->getCustomizationFieldIds())
			return false;

		$authorized_text_fields = array();
		foreach ($field_ids as $field_id)
			if ($field_id['type'] == Product::CUSTOMIZE_TEXTFIELD)
				$authorized_text_fields[(int)$field_id['id_customization_field']] = 'textField'.(int)$field_id['id_customization_field'];

		$indexes = array_flip($authorized_text_fields);
		foreach ($_POST as $field_name => $value)
			if (in_array($field_name, $authorized_text_fields) && !empty($value))
			{
				if (!Validate::isCleanHtml($value))
					$this->errors[] = Tools::displayError('Invalid message');
				else
					$this->context->cart->addTextFieldToProduct($this->product->id, $indexes[$field_name], Product::CUSTOMIZE_TEXTFIELD, $value);
			}
			else if (in_array($field_name, $authorized_text_fields) && empty($value))
				$this->context->cart->deleteCustomizationToProduct((int)$this->product->id, $indexes[$field_name]);
	}
}

?>

The Cart Class override

Next thing to settle: we need to avoid our html to be stripped out of the string when it’s added to the database. Instead, we want tags to be converted to their visual representation (not real html, but characters resembling it, like &gt; for example). Therefore, go to override/classes, and create a new file called Cart.php. As always, fill it with some basic code:

<?php

Class Cart extends CartCore
{

}

?>

This time, we need to extend the _addCustomization method. Copy it from the original Cart.php, which you can find in classes/. It should look like this (again, I’m using 1.5.6):

	public function _addCustomization($id_product, $id_product_attribute, $index, $type, $field, $quantity)
	{
		$exising_customization = Db::getInstance()->executeS('
			SELECT cu.`id_customization`, cd.`index`, cd.`value`, cd.`type` FROM `'._DB_PREFIX_.'customization` cu
			LEFT JOIN `'._DB_PREFIX_.'customized_data` cd
			ON cu.`id_customization` = cd.`id_customization`
			WHERE cu.id_cart = '.(int)$this->id.'
			AND cu.id_product = '.(int)$id_product.'
			AND in_cart = 0'
		);

		if ($exising_customization)
		{
			// If the customization field is alreay filled, delete it
			foreach ($exising_customization as $customization)
			{
				if ($customization['type'] == $type && $customization['index'] == $index)
				{
					Db::getInstance()->execute('
						DELETE FROM `'._DB_PREFIX_.'customized_data`
						WHERE id_customization = '.(int)$customization['id_customization'].'
						AND type = '.(int)$customization['type'].'
						AND `index` = '.(int)$customization['index']);
					if ($type == Product::CUSTOMIZE_FILE)
					{
						@unlink(_PS_UPLOAD_DIR_.$customization['value']);
						@unlink(_PS_UPLOAD_DIR_.$customization['value'].'_small');
					}
					break;
				}
			}
			$id_customization = $exising_customization[0]['id_customization'];
		}
		else
		{
			Db::getInstance()->execute(
				'INSERT INTO `'._DB_PREFIX_.'customization` (`id_cart`, `id_product`, `id_product_attribute`, `quantity`)
				VALUES ('.(int)$this->id.', '.(int)$id_product.', '.(int)$id_product_attribute.', '.(int)$quantity.')'
			);
			$id_customization = Db::getInstance()->Insert_ID();
		}

		$query = 'INSERT INTO `'._DB_PREFIX_.'customized_data` (`id_customization`, `type`, `index`, `value`)
			VALUES ('.(int)$id_customization.', '.(int)$type.', '.(int)$index.', \''.pSql($field).'\')';

		if (!Db::getInstance()->execute($query))
			return false;
		return true;
	}

And paste it into the new cart override.

At this point, can you see the last $query variable, at the end of the method?

$query = 'INSERT INTO `'._DB_PREFIX_.'customized_data` (`id_customization`, `type`, `index`, `value`)
			VALUES ('.(int)$id_customization.', '.(int)$type.', '.(int)$index.', \''.pSql($field).'\')';

Now we need to properly save our HTML. We don’t need REAL html, but a string representing it correctly, so that it can be read in the back office, and on the order summary as well. Therefore, we need to escape tags with htmlspecialchars, and remove <br/> added automatically by the textarea, to avoid corrupting the code.

Right before the previously mentioned $query, add:

$escaped_field = htmlspecialchars(str_replace('<br />', "\n", $field));

Then, refer to it in the query:

$query = 'INSERT INTO `'._DB_PREFIX_.'customized_data` (`id_customization`, `type`, `index`, `value`)
			VALUES ('.(int)$id_customization.', '.(int)$type.', '.(int)$index.', \''.pSql($escaped_field).'\')';

Save, and we are done! The final Cart Override:


<?php

Class Cart extends CartCore
{
	public function _addCustomization($id_product, $id_product_attribute, $index, $type, $field, $quantity)
	{
		$exising_customization = Db::getInstance()->executeS('
			SELECT cu.`id_customization`, cd.`index`, cd.`value`, cd.`type` FROM `'._DB_PREFIX_.'customization` cu
			LEFT JOIN `'._DB_PREFIX_.'customized_data` cd
			ON cu.`id_customization` = cd.`id_customization`
			WHERE cu.id_cart = '.(int)$this->id.'
			AND cu.id_product = '.(int)$id_product.'
			AND in_cart = 0'
		);

		if ($exising_customization)
		{
			// If the customization field is alreay filled, delete it
			foreach ($exising_customization as $customization)
			{
				if ($customization['type'] == $type && $customization['index'] == $index)
				{
					Db::getInstance()->execute('
						DELETE FROM `'._DB_PREFIX_.'customized_data`
						WHERE id_customization = '.(int)$customization['id_customization'].'
						AND type = '.(int)$customization['type'].'
						AND `index` = '.(int)$customization['index']);
					if ($type == Product::CUSTOMIZE_FILE)
					{
						@unlink(_PS_UPLOAD_DIR_.$customization['value']);
						@unlink(_PS_UPLOAD_DIR_.$customization['value'].'_small');
					}
					break;
				}
			}
			$id_customization = $exising_customization[0]['id_customization'];
		}
		else
		{
			Db::getInstance()->execute(
				'INSERT INTO `'._DB_PREFIX_.'customization` (`id_cart`, `id_product`, `id_product_attribute`, `quantity`)
				VALUES ('.(int)$this->id.', '.(int)$id_product.', '.(int)$id_product_attribute.', '.(int)$quantity.')'
			);
			$id_customization = Db::getInstance()->Insert_ID();
		}

		$escaped_field = htmlspecialchars(str_replace('<br />', "\n", $field));

		$query = 'INSERT INTO `'._DB_PREFIX_.'customized_data` (`id_customization`, `type`, `index`, `value`)
			VALUES ('.(int)$id_customization.', '.(int)$type.', '.(int)$index.', \''.pSql(htmlspecialchars($escaped_field)).'\')';

		if (!Db::getInstance()->execute($query))
			return false;
		return true;
	}
}

?>

Note: before these changes can take effect, if you are using a recent version of Prestashop, make sure you go to cache/ and delete the class_index file!

The ajax cart issue

If a client inputs html code containing tab spacing, line breaks or carriage returns, then a parse error will occur when adding a product using the ajax cart. Therefore, we need to account for these elements, as javascript can only handle single line strings, and to do this, we must edit blockcart-json.tpl.

Go to modules/blockcart, copy blockcart-json.tpl and paste it into the theme folder /modules/blockcart/. In this new file, locate the following lines (about line 64 on Prestashop 1.5.6.0):

						"value":			"{$data.value|addslashes|replace: '\\\'':'\''}",
						"truncatedValue":	"{$data.value|truncate:28:'...'|addslashes|replace: '\\\'':'\''}"

We need to escape these. Change them to

						"value":			"{$data.value|addslashes|replace: '\\\'':'\''|regex_replace:"/[\r\n\t]/":""}",
						"truncatedValue":	"{$data.value|truncate:28:'...'|addslashes|replace: '\\\'':'\''|regex_replace:"/[\r\n\t]/":""}"

Explanation: using regular expressions, we got rid of every new line(\n), carriage return(\r), and tab space (\t). No worries, if you don’t understand this, it’s not the end of the world!

Resources

Need Prestashop Modules? Have a look at my Prestashop Addons Store!

Looking for quality PrestaShop Web Hosting? Look no further than Arvixe Web Hosting!

Tags: , , , , , , , , , , , , | Posted under PrestaShop | RSS 2.0

Author Spotlight

Fabio Porta

Fabio Porta

Fabio has been involved in web development and design since 2005, when launched his first website at the age of 16. He’s now highly skilled in both client and server side development, along with design, and since August 2012 runs a successful website about PrestaShop tutorials and Prestashop Modules called Nemo’s Post Scriptum, at http://nemops.com

One Comment on Extend Prestashop Customization Fields (Longer Input and HTML)

  1. Parag says:

    Nice blog regarding prestashop. I like it very much.

Leave a Reply

Your email address will not be published. Required fields are marked *


− 9 = 0

You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>