<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>NemoPS &#187; overrides</title>
	<atom:link href="http://nemops.com/tag/overrides/feed/" rel="self" type="application/rss+xml" />
	<link>http://nemops.com</link>
	<description>Prestashop Tutorials, Modules and More!</description>
	<lastBuildDate>Wed, 05 Dec 2018 13:25:23 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.1.35</generator>
	<item>
		<title>Overriding Modules Controllers in PrestaShop 1.6</title>
		<link>http://nemops.com/overriding-modules-controllers-in-prestashop-1-6/</link>
		<comments>http://nemops.com/overriding-modules-controllers-in-prestashop-1-6/#comments</comments>
		<pubDate>Wed, 02 Mar 2016 11:39:49 +0000</pubDate>
		<dc:creator><![CDATA[Nemo]]></dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[modules]]></category>
		<category><![CDATA[overrides]]></category>
		<category><![CDATA[prestashop]]></category>
		<category><![CDATA[prestashop 1.6]]></category>

		<guid isPermaLink="false">http://nemops.com/?p=2723</guid>
		<description><![CDATA[<p>Thanks to a PrestaShop forums&#8217; user, we can now easily extend modules&#8217; controllers without any hardcoded modification. Let&#8217;s see how do do it! Last Week, forum user alexdee2007 posted an interesting override: it allows us to extend PrestaShop Modules&#8217; controllers. Previously, we would have had to hardcode any modification within the originals, because the core [&#8230;]</p>
<p>The post <a rel="nofollow" href="http://nemops.com/overriding-modules-controllers-in-prestashop-1-6/">Overriding Modules Controllers in PrestaShop 1.6</a> appeared first on <a rel="nofollow" href="http://nemops.com">NemoPS</a>.</p>
]]></description>
				<content:encoded><![CDATA[<p>Thanks to a PrestaShop forums&#8217; user, we can now easily extend modules&#8217; controllers without any hardcoded modification. Let&#8217;s see how do do it!</p>
<p><span id="more-2723"></span></p>
<a class="download-files button style1" href="http://nemops.com/wp-content/uploads/2016/03/Dispatcher.zip" title="Download Project Files">Download Project Files</a>
<p>Last Week, forum user <strong>alexdee2007</strong> posted an interesting override: it allows us to extend PrestaShop Modules&#8217; controllers. Previously, we would have had to hardcode any modification within the originals, because the core system didn&#8217;t allow for such overrides. You can find a link to the original thread at the end of the tutorial.</p>
<div class="separator"></div>
<h2>What does the override do?</h2>
<p>Its concept is very simple, yet smart. It extends the <strong>Dispatcher</strong> class&#8217; <strong>Dispatch()</strong> method, modifying what the system looks for, once loading modules front controllers. Here is the core part:</p>
<pre class="brush: php; title: ; notranslate">
if (file_exists(_PS_OVERRIDE_DIR_ . 'modules/' . $module_name . '/controllers/front/' . $this-&gt;controller . '.php')) {
    include_once(_PS_OVERRIDE_DIR_ . 'modules/' . $module_name . '/controllers/front/' . $this-&gt;controller . '.php');
    $controller_class = $module_name . $this-&gt;controller . 'ModuleFrontControllerOverride';
} else {

    $controller_class = $module_name . $this-&gt;controller . 'ModuleFrontController';
}
</pre>
<p>Basically, it looks for the existence of any file, in the override directory, with the same path and name of the original controller. If it exists, it assigns the name plus &#8220;Override&#8221; to the current class name (which is what PrestaShop does already, for modules).<br />
This way, to extend any Module&#8217;s controller, we can simply create a file inside <em>override/modules/*modulename*/controllers/front</em>, named the same as the original, and then append Override to its Class name.</p>
<div class="separator"></div>
<h2>Video &#8211; A practical example</h2>

	<div class="video-embed">
		<iframe width="640" height="360" src="http://www.youtube.com/embed/nvVgbQZS-Eg" frameborder="0" allowfullscreen></iframe><p><a href="https://www.youtube.com/user/NemoPostScriptum/videos" rel="nofollow" title="Subscribe Post Scriptum's Youtube Channel">Subscribe Post Scriptum's Youtube Channel</a></p>	</div>
<div class="separator"></div>
<h3>Additional Recources</h3>
<ul>
<li><a href="http://nemops.com/prestashop-modules-course" title="PrestaShop Modules Course">PrestaShop Modules Course</a></li>
<li><a href="https://www.prestashop.com/forums/topic/480523-override-front-controller-of-modules/?p=2262437" title="The original Forum Thread">The original Forum Thread</a></li>
</ul>
<p>The post <a rel="nofollow" href="http://nemops.com/overriding-modules-controllers-in-prestashop-1-6/">Overriding Modules Controllers in PrestaShop 1.6</a> appeared first on <a rel="nofollow" href="http://nemops.com">NemoPS</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://nemops.com/overriding-modules-controllers-in-prestashop-1-6/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>How to add new fields to the customer address in Prestashop</title>
		<link>http://nemops.com/new-customer-address-fields-prestashop/</link>
		<comments>http://nemops.com/new-customer-address-fields-prestashop/#comments</comments>
		<pubDate>Tue, 22 Apr 2014 09:21:30 +0000</pubDate>
		<dc:creator><![CDATA[Nemo]]></dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[new fields]]></category>
		<category><![CDATA[overrides]]></category>
		<category><![CDATA[prestashop 1.6]]></category>
		<category><![CDATA[registration]]></category>

		<guid isPermaLink="false">http://nemops.com/?p=1949</guid>
		<description><![CDATA[<p>In today&#8217;s tutorial, we will see how to add new fields to the customer address in Prestashop. UPDATE! If you prefer a simple solution, I created a module that automates the process and does much more, find it here Version used: Prestashop 1.6 (compatible with Prestashop 1.5) Plan of action In order to add a [&#8230;]</p>
<p>The post <a rel="nofollow" href="http://nemops.com/new-customer-address-fields-prestashop/">How to add new fields to the customer address in Prestashop</a> appeared first on <a rel="nofollow" href="http://nemops.com">NemoPS</a>.</p>
]]></description>
				<content:encoded><![CDATA[<p>In today&#8217;s tutorial, we will see how to add new fields to the customer address in Prestashop.</p>
<p><span id="more-1949"></span></p>
<p><strong>UPDATE! If you prefer a simple solution, I created a module that automates the process and does much more, find it <a href="http://store.nemops.com/modules/45-prestashop-address-fields.html#.WhvflkqWaUk" title="PrestaShop Address Fields Module">here</a></strong></p>
<a class="download-files button style1" href="http://nemops.com/wp-content/uploads/2014/04/new_registration_fields.zip" title="Download Project Files">Download Project Files</a>
<ul>
<li>Version used: Prestashop 1.6 (compatible with Prestashop 1.5)</li>
</ul>
<h2>Plan of action</h2>
<p>In order to add a new field to the address registration form, we will be adding a couple of overrides, as well as creating a new database field and modifying the address template file. If you are not familiar with Prestashop overrides, check out my article on <a href="http://nemops.com/extending-prestashop-objects/#.U1WG4Pna6r0" title="how to extend Prestashop objects" target="_blank">how to extend Prestashop objects</a> (although we will have to use a slightly different technique).</p>
<div class="separator"></div>
<h2>The address class and database table</h2>
<p>First things first, we need something to play with. We want the customer to be able to fill in a field which doesn&#8217;t currently exist, therefore let&#8217;s login to the database, access the <strong>ps_address</strong> table and create a new field: <strong>my_custom_field</strong>. I made it a 64 long VARCHAR field.</p>
<p>Next we need to tell the address object (class) that it has a new field to deal with. Create a new file inside <em>override/classes/</em> and call it <strong>Address.php</strong>. Add the following inside php tags:</p>
<pre class="brush: php; title: ; notranslate">



class Address extends AddressCore
{

	public $my_custom_field;


	public static $definition = array(
		'table' =&gt; 'address',
		'primary' =&gt; 'id_address',
		'fields' =&gt; array(
			'id_customer' =&gt; 		array('type' =&gt; self::TYPE_INT, 'validate' =&gt; 'isNullOrUnsignedId', 'copy_post' =&gt; false),
			'id_manufacturer' =&gt; 	   array('type' =&gt; self::TYPE_INT, 'validate' =&gt; 'isNullOrUnsignedId', 'copy_post' =&gt; false),
			'id_supplier' =&gt; 		array('type' =&gt; self::TYPE_INT, 'validate' =&gt; 'isNullOrUnsignedId', 'copy_post' =&gt; false),
			'id_warehouse' =&gt; 		array('type' =&gt; self::TYPE_INT, 'validate' =&gt; 'isNullOrUnsignedId', 'copy_post' =&gt; false),
			'id_country' =&gt; 		array('type' =&gt; self::TYPE_INT, 'validate' =&gt; 'isUnsignedId', 'required' =&gt; true),
			'id_state' =&gt; 			array('type' =&gt; self::TYPE_INT, 'validate' =&gt; 'isNullOrUnsignedId'),
			'alias' =&gt; 				array('type' =&gt; self::TYPE_STRING, 'validate' =&gt; 'isGenericName', 'required' =&gt; true, 'size' =&gt; 32),
			'company' =&gt; 			array('type' =&gt; self::TYPE_STRING, 'validate' =&gt; 'isGenericName', 'size' =&gt; 64),
			'lastname' =&gt; 			array('type' =&gt; self::TYPE_STRING, 'validate' =&gt; 'isName', 'required' =&gt; true, 'size' =&gt; 32),
			'firstname' =&gt; 			array('type' =&gt; self::TYPE_STRING, 'validate' =&gt; 'isName', 'required' =&gt; true, 'size' =&gt; 32),
			'vat_number' =&gt;	 		array('type' =&gt; self::TYPE_STRING, 'validate' =&gt; 'isGenericName'),
			'address1' =&gt; 			array('type' =&gt; self::TYPE_STRING, 'validate' =&gt; 'isAddress', 'required' =&gt; true, 'size' =&gt; 128),
			'address2' =&gt; 			array('type' =&gt; self::TYPE_STRING, 'validate' =&gt; 'isAddress', 'size' =&gt; 128),
			'postcode' =&gt; 			array('type' =&gt; self::TYPE_STRING, 'validate' =&gt; 'isPostCode', 'size' =&gt; 12),
			'city' =&gt; 				array('type' =&gt; self::TYPE_STRING, 'validate' =&gt; 'isCityName', 'required' =&gt; true, 'size' =&gt; 64),
			'other' =&gt; 				array('type' =&gt; self::TYPE_STRING, 'validate' =&gt; 'isMessage', 'size' =&gt; 300),
			'phone' =&gt; 				array('type' =&gt; self::TYPE_STRING, 'validate' =&gt; 'isPhoneNumber', 'size' =&gt; 32),
			'phone_mobile' =&gt; 		array('type' =&gt; self::TYPE_STRING, 'validate' =&gt; 'isPhoneNumber', 'size' =&gt; 32),
			'dni' =&gt; 				array('type' =&gt; self::TYPE_STRING, 'validate' =&gt; 'isDniLite', 'size' =&gt; 16),
			'deleted' =&gt; 			array('type' =&gt; self::TYPE_BOOL, 'validate' =&gt; 'isBool', 'copy_post' =&gt; false),
			'date_add' =&gt; 			array('type' =&gt; self::TYPE_DATE, 'validate' =&gt; 'isDateFormat', 'copy_post' =&gt; false),
			'date_upd' =&gt; 			array('type' =&gt; self::TYPE_DATE, 'validate' =&gt; 'isDateFormat', 'copy_post' =&gt; false),
			'my_custom_field' =&gt; 	array('type' =&gt; self::TYPE_STRING, 'validate' =&gt; 'isGenericName', 'size' =&gt; 64),

		),
	);
}
</pre>
<p><strong>Explanation:</strong> if you read my article on how to extend Prestashop Objects, you will notice I approached this override a little differently. I am not assigning the new field upon instance creation, but <strong>I am directly overriding its definition</strong>. The reason is simple: the Address definition is called statically when creating a new address in the front office, and if we added the new field in the construct method, we would have missed it from the list.</p>
<p>Please notice that this definition comes from <strong>Prestashop 1.6.0.5</strong>, and I therefore recommend to use your own from the original Address class, in case you have a different Prestashop version.</p>
<div class="separator"></div>
<h2>The back office Address Controller</h2>
<p>We are half the way through already, and at this point we need to override the back office controller responsible for displaying the address modification form for each customer.</p>
<p>Create a new file named <strong>AdminAddressesController.php</strong> in <em>override/controllers/admin/</em>. We need to extend the renderForm() method; thus, head over the main <em>controllers/admin</em> folder, open up the original <strong>AdminAddressesController.php</strong>, locate the <strong>renderForm()</strong> method and copy it. Then, add the following inside php tags in our <strong>new</strong> controller override:</p>
<pre class="brush: php; title: ; notranslate">

Class AdminAddressesController extends AdminAddressesControllerCore
{

}

</pre>
<p>And paste the renderForm() code inside the class. Here is how mine looks like, taken from Prestashop 1.6.0.5:</p>
<pre class="brush: php; title: ; notranslate">

Class AdminAddressesController extends AdminAddressesControllerCore
{


	public function renderForm()
	{
		$this-&gt;fields_form = array(
			'legend' =&gt; array(
				'title' =&gt; $this-&gt;l('Addresses'),
				'icon' =&gt; 'icon-envelope-alt'
			),
			'input' =&gt; array(
				array(
					'type' =&gt; 'text_customer',
					'label' =&gt; $this-&gt;l('Customer'),
					'name' =&gt; 'id_customer',
					'required' =&gt; false,
				),
				array(
					'type' =&gt; 'text',
					'label' =&gt; $this-&gt;l('Identification Number'),
					'name' =&gt; 'dni',
					'required' =&gt; false,
					'col' =&gt; '4',
					'hint' =&gt; $this-&gt;l('DNI / NIF / NIE')
				),			
				array(
					'type' =&gt; 'text',
					'label' =&gt; $this-&gt;l('Address alias'),
					'name' =&gt; 'alias',
					'required' =&gt; true,
					'col' =&gt; '4',
					'hint' =&gt; $this-&gt;l('Invalid characters:').' &amp;lt;&amp;gt;;=#{}'
				),
				array(
					'type' =&gt; 'text',
					'label' =&gt; $this-&gt;l('Home phone'),
					'name' =&gt; 'phone',
					'required' =&gt; false,
					'col' =&gt; '4',
					'hint' =&gt; Configuration::get('PS_ONE_PHONE_AT_LEAST') ? sprintf($this-&gt;l('You must register at least one phone number.')) : ''
				),
				array(
					'type' =&gt; 'text',
					'label' =&gt; $this-&gt;l('Mobile phone'),
					'name' =&gt; 'phone_mobile',
					'required' =&gt; false,
					'col' =&gt; '4',
					'hint' =&gt; Configuration::get('PS_ONE_PHONE_AT_LEAST') ? sprintf($this-&gt;l('You must register at least one phone number.')) : ''
				),
				array(
					'type' =&gt; 'textarea',
					'label' =&gt; $this-&gt;l('Other'),
					'name' =&gt; 'other',
					'required' =&gt; false,
					'cols' =&gt; 15,
					'rows' =&gt; 3,
					'hint' =&gt; $this-&gt;l('Forbidden characters:').' &amp;lt;&amp;gt;;=#{}'
				),
			),
			'submit' =&gt; array(
				'title' =&gt; $this-&gt;l('Save'),
			)
		);
		$id_customer = (int)Tools::getValue('id_customer');
		if (!$id_customer &amp;&amp; Validate::isLoadedObject($this-&gt;object))
			$id_customer = $this-&gt;object-&gt;id_customer;
		if ($id_customer)
		{
			$customer = new Customer((int)$id_customer);
			$token_customer = Tools::getAdminToken('AdminCustomers'.(int)(Tab::getIdFromClassName('AdminCustomers')).(int)$this-&gt;context-&gt;employee-&gt;id);
		}

		$this-&gt;tpl_form_vars = array(
			'customer' =&gt; isset($customer) ? $customer : null,
			'tokenCustomer' =&gt; isset ($token_customer) ? $token_customer : null
		);

		// Order address fields depending on country format
		$addresses_fields = $this-&gt;processAddressFormat();
		// we use  delivery address
		$addresses_fields = $addresses_fields['dlv_all_fields'];

		$temp_fields = array();

		foreach ($addresses_fields as $addr_field_item)
		{
			if ($addr_field_item == 'company')
			{
				$temp_fields[] = array(
					'type' =&gt; 'text',
					'label' =&gt; $this-&gt;l('Company'),
					'name' =&gt; 'company',
					'required' =&gt; false,
					'col' =&gt; '4',
					'hint' =&gt; $this-&gt;l('Invalid characters:').' &amp;lt;&amp;gt;;=#{}'
				);
				$temp_fields[] = array(
					'type' =&gt; 'text',
					'label' =&gt; $this-&gt;l('VAT number'),
					'col' =&gt; '2',
					'name' =&gt; 'vat_number'
				);
			}
			else if ($addr_field_item == 'lastname')
			{
				if (isset($customer) &amp;&amp;
					!Tools::isSubmit('submit'.strtoupper($this-&gt;table)) &amp;&amp;
					Validate::isLoadedObject($customer) &amp;&amp;
					!Validate::isLoadedObject($this-&gt;object))
					$default_value = $customer-&gt;lastname;
				else
					$default_value = '';

				$temp_fields[] = array(
					'type' =&gt; 'text',
					'label' =&gt; $this-&gt;l('Last Name'),
					'name' =&gt; 'lastname',
					'required' =&gt; true,
					'col' =&gt; '4',
					'hint' =&gt; $this-&gt;l('Invalid characters:').' 0-9!&amp;amp;lt;&amp;amp;gt;,;?=+()@#&quot;�{}_$%:',
					'default_value' =&gt; $default_value,
				);
			}
			else if ($addr_field_item == 'firstname')
			{
				if (isset($customer) &amp;&amp;
					!Tools::isSubmit('submit'.strtoupper($this-&gt;table)) &amp;&amp;
					Validate::isLoadedObject($customer) &amp;&amp;
					!Validate::isLoadedObject($this-&gt;object))
					$default_value = $customer-&gt;firstname;
 	 	 	 	else
 	 	 	 		$default_value = '';

				$temp_fields[] = array(
					'type' =&gt; 'text',
					'label' =&gt; $this-&gt;l('First Name'),
					'name' =&gt; 'firstname',
					'required' =&gt; true,
					'col' =&gt; '4',
					'hint' =&gt; $this-&gt;l('Invalid characters:').' 0-9!&amp;amp;lt;&amp;amp;gt;,;?=+()@#&quot;�{}_$%:',
					'default_value' =&gt; $default_value,
				);
			}
			else if ($addr_field_item == 'address1')
			{
				$temp_fields[] = array(
					'type' =&gt; 'text',
					'label' =&gt; $this-&gt;l('Address'),
					'name' =&gt; 'address1',
					'col' =&gt; '6',
					'required' =&gt; true,
				);
			}
			else if ($addr_field_item == 'address2')
			{
				$temp_fields[] = array(
					'type' =&gt; 'text',
					'label' =&gt; $this-&gt;l('Address').' (2)',
					'name' =&gt; 'address2',
					'col' =&gt; '6',
					'required' =&gt; false,
				);
			}
			elseif ($addr_field_item == 'postcode')
			{
				$temp_fields[] = array(
					'type' =&gt; 'text',
					'label' =&gt; $this-&gt;l('Zip/Postal Code'),
					'name' =&gt; 'postcode',
					'col' =&gt; '2',
					'required' =&gt; true,
				);
			}
			else if ($addr_field_item == 'city')
			{
				$temp_fields[] = array(
					'type' =&gt; 'text',
					'label' =&gt; $this-&gt;l('City'),
					'name' =&gt; 'city',
					'col' =&gt; '4',
					'required' =&gt; true,
				);
			}
			else if ($addr_field_item == 'country' || $addr_field_item == 'Country:name')
			{
				$temp_fields[] = array(
					'type' =&gt; 'select',
					'label' =&gt; $this-&gt;l('Country'),
					'name' =&gt; 'id_country',
					'required' =&gt; false,
					'col' =&gt; '4',
					'default_value' =&gt; (int)$this-&gt;context-&gt;country-&gt;id,
					'options' =&gt; array(
						'query' =&gt; Country::getCountries($this-&gt;context-&gt;language-&gt;id),
						'id' =&gt; 'id_country',
						'name' =&gt; 'name'
					)
				);
				$temp_fields[] = array(
					'type' =&gt; 'select',
					'label' =&gt; $this-&gt;l('State'),
					'name' =&gt; 'id_state',
					'required' =&gt; false,
					'col' =&gt; '4',
					'options' =&gt; array(
						'query' =&gt; array(),
						'id' =&gt; 'id_state',
						'name' =&gt; 'name'
					)
				);
			}
		}

		// merge address format with the rest of the form
		array_splice($this-&gt;fields_form['input'], 3, 0, $temp_fields);

		return parent::renderForm();
	}
	
}

</pre>
<p>We must edit the $this->fields_form variable to add a new input field; right after this:</p>
<pre class="brush: php; title: ; notranslate">
				array(
					'type' =&gt; 'text',
					'label' =&gt; $this-&gt;l('Identification Number'),
					'name' =&gt; 'dni',
					'required' =&gt; false,
					'col' =&gt; '4',
					'hint' =&gt; $this-&gt;l('DNI / NIF / NIE')
				),	
</pre>
<p>Add the following</p>
<pre class="brush: php; title: ; notranslate">
				array(
					'type' =&gt; 'text',
					'label' =&gt; $this-&gt;l('My custom field'),
					'name' =&gt; 'my_custom_field',
					'required' =&gt; false,
					'col' =&gt; '4',
					'hint' =&gt; $this-&gt;l('Just a custom field!')
				),	
</pre>
<p><strong>Note:</strong> make sure the &#8220;name&#8221; matches the one of the new attribute previously added to both the database and Address class object!</p>
<p>Lastly, at the end of the method, change:</p>
<pre class="brush: php; title: ; notranslate">
return parent::renderForm();
</pre>
<p>To</p>
<pre class="brush: php; title: ; notranslate">
return AdminController::renderForm();
</pre>
<p>So that the new fields list is not replaced by the original one.</p>
<p>If the Address class or/and controller were not previously overridden, at this point you must reach	the <em>cache/</em> folder and erase <strong>class_index.php</strong>; as always. After doing it, overrides will take place.</p>
<div class="separator"></div>
<h2>The Front Office Address Template</h2>
<p>As very last step, let&#8217;s now add the custom field to the front office template, so it can be filled in by clients when they register. Open up <strong>address.tpl</strong>, located in the theme folder. I am using the default bootstrap template, so your file might look differently in case you have a custom one! Locate:</p>
<pre class="brush: php; html-script: true; title: ; notranslate">

			{if $field_name eq 'vat_number'}
				&lt;div id=&quot;vat_area&quot;&gt;
					&lt;div id=&quot;vat_number&quot;&gt;
						&lt;div class=&quot;form-group&quot;&gt;
							&lt;label for=&quot;vat-number&quot;&gt;{l s='VAT number'}&lt;/label&gt;
							&lt;input type=&quot;text&quot; class=&quot;form-control validate&quot; data-validate=&quot;{$address_validation.$field_name.validate}&quot; id=&quot;vat-number&quot; name=&quot;vat_number&quot; value=&quot;{if isset($smarty.post.vat_number)}{$smarty.post.vat_number}{else}{if isset($address-&gt;vat_number)}{$address-&gt;vat_number|escape:'html':'UTF-8'}{/if}{/if}&quot; /&gt;
						&lt;/div&gt;
					&lt;/div&gt;
				&lt;/div&gt;
			{/if}
</pre>
<p>And right after it, add:</p>
<pre class="brush: php; html-script: true; title: ; notranslate">

			{if $field_name eq 'my_custom_field'}
				&lt;div id=&quot;vat_area&quot;&gt;
					&lt;div id=&quot;my_custom_field&quot;&gt;
						&lt;div class=&quot;form-group&quot;&gt;
							&lt;label for=&quot;my-custom-field&quot;&gt;{l s='My Custom Field'}&lt;/label&gt;
							&lt;input type=&quot;text&quot; class=&quot;form-control validate&quot; data-validate=&quot;{$address_validation.$field_name.validate}&quot; id=&quot;my-custom-field&quot; name=&quot;my_custom_field&quot; value=&quot;{if isset($smarty.post.my_custom_field)}{$smarty.post.my_custom_field}{else}{if isset($address-&gt;my_custom_field)}{$address-&gt;my_custom_field|escape:'html':'UTF-8'}{/if}{/if}&quot; /&gt;
						&lt;/div&gt;
					&lt;/div&gt;
				&lt;/div&gt;
			{/if}
</pre>
<p>Save and refresh, we&#8217;re done!</p>
<p><strong>TIP:</strong> if you don&#8217;t see any change in the front office, make sure you turn on recompilation from <em>Advanced Parameters > Performance</em>, and clear Smarty cache as well</p>
<div class="separator"></div>
<h2>Optional: Making the new field mandatory</h2>
<p>If you really need your customers to input something in that new field, than another override is necessary. Create a new file within <em>override/controllers/front</em> and call it <strong>AddressController.php</strong>. Paste the following inside php tags, ad always:</p>
<pre class="brush: php; title: ; notranslate">

Class AddressController extends AddressControllerCore
{

}
</pre>
<p>We need to override the <strong>processSubmitAddress()</strong> method. Therefore, if your Prestashop version is not 1.6.0.5, go ahead and copy your original one inside this new override; otherwise you can use the following:</p>
<pre class="brush: php; title: ; notranslate">

	protected function processSubmitAddress()
	{
		$address = new Address();
		$this-&gt;errors = $address-&gt;validateController();
		$address-&gt;id_customer = (int)$this-&gt;context-&gt;customer-&gt;id;

		// Check page token
		if ($this-&gt;context-&gt;customer-&gt;isLogged() &amp;&amp; !$this-&gt;isTokenValid())
			$this-&gt;errors[] = Tools::displayError('Invalid token.');

		// Check phone
		if (Configuration::get('PS_ONE_PHONE_AT_LEAST') &amp;&amp; !Tools::getValue('phone') &amp;&amp; !Tools::getValue('phone_mobile'))
			$this-&gt;errors[] = Tools::displayError('You must register at least one phone number.');
		if ($address-&gt;id_country)
		{
			// Check country
			if (!($country = new Country($address-&gt;id_country)) || !Validate::isLoadedObject($country))
				throw new PrestaShopException('Country cannot be loaded with address-&gt;id_country');

			if ((int)$country-&gt;contains_states &amp;&amp; !(int)$address-&gt;id_state)
				$this-&gt;errors[] = Tools::displayError('This country requires you to chose a State.');

			$postcode = Tools::getValue('postcode');		
			/* Check zip code format */
			if ($country-&gt;zip_code_format &amp;&amp; !$country-&gt;checkZipCode($postcode))
				$this-&gt;errors[] = sprintf(Tools::displayError('The Zip/Postal code you\'ve entered is invalid. It must follow this format: %s'), str_replace('C', $country-&gt;iso_code, str_replace('N', '0', str_replace('L', 'A', $country-&gt;zip_code_format))));
			elseif(empty($postcode) &amp;&amp; $country-&gt;need_zip_code)
				$this-&gt;errors[] = Tools::displayError('A Zip/Postal code is required.');
			elseif ($postcode &amp;&amp; !Validate::isPostCode($postcode))
				$this-&gt;errors[] = Tools::displayError('The Zip/Postal code is invalid.');

			// Check country DNI
			if ($country-&gt;isNeedDni() &amp;&amp; (!Tools::getValue('dni') || !Validate::isDniLite(Tools::getValue('dni'))))
				$this-&gt;errors[] = Tools::displayError('The identification number is incorrect or has already been used.');
			else if (!$country-&gt;isNeedDni())
				$address-&gt;dni = null;
		}
		// Check if the alias exists
		if (!$this-&gt;context-&gt;customer-&gt;is_guest &amp;&amp; !empty($_POST['alias']) &amp;&amp; (int)$this-&gt;context-&gt;customer-&gt;id &gt; 0)
		{
			$id_address = Tools::getValue('id_address');
			if(Configuration::get('PS_ORDER_PROCESS_TYPE') &amp;&amp; (int)Tools::getValue('opc_id_address_'.Tools::getValue('type')) &gt; 0)
				$id_address = Tools::getValue('opc_id_address_'.Tools::getValue('type'));
 	
			if (Db::getInstance()-&gt;getValue('
				SELECT count(*)
				FROM '._DB_PREFIX_.'address
				WHERE `alias` = \''.pSql($_POST['alias']).'\'
				AND id_address != '.(int)$id_address.'
				AND id_customer = '.(int)$this-&gt;context-&gt;customer-&gt;id.'
				AND deleted = 0') &gt; 0)
				$this-&gt;errors[] = sprintf(Tools::displayError('The alias &quot;%s&quot; has already been used. Please select another one.'), Tools::safeOutput($_POST['alias']));
		}

		// Check the requires fields which are settings in the BO
		$this-&gt;errors = array_merge($this-&gt;errors, $address-&gt;validateFieldsRequiredDatabase());

		// Don't continue this process if we have errors !
		if ($this-&gt;errors &amp;&amp; !$this-&gt;ajax)
			return;

		// If we edit this address, delete old address and create a new one
		if (Validate::isLoadedObject($this-&gt;_address))
		{
			if (Validate::isLoadedObject($country) &amp;&amp; !$country-&gt;contains_states)
				$address-&gt;id_state = 0;
			$address_old = $this-&gt;_address;
			if (Customer::customerHasAddress($this-&gt;context-&gt;customer-&gt;id, (int)$address_old-&gt;id))
			{
				if ($address_old-&gt;isUsed())
					$address_old-&gt;delete();
				else
				{
					$address-&gt;id = (int)($address_old-&gt;id);
					$address-&gt;date_add = $address_old-&gt;date_add;
				}
			}
		}
		
		if ($this-&gt;ajax &amp;&amp; Tools::getValue('type') == 'invoice' &amp;&amp; Configuration::get('PS_ORDER_PROCESS_TYPE'))
		{
			$this-&gt;errors = array_unique(array_merge($this-&gt;errors, $address-&gt;validateController()));			
			if (count($this-&gt;errors))
			{
				$return = array(
					'hasError' =&gt; (bool)$this-&gt;errors,
					'errors' =&gt; $this-&gt;errors
				);
				die(Tools::jsonEncode($return));
			}
		}
		
		// Save address
		if ($result = $address-&gt;save())
		{			
			// Update id address of the current cart if necessary
			if (isset($address_old) &amp;&amp; $address_old-&gt;isUsed())
				$this-&gt;context-&gt;cart-&gt;updateAddressId($address_old-&gt;id, $address-&gt;id);
			else // Update cart address
				$this-&gt;context-&gt;cart-&gt;autosetProductAddress();

			if ((bool)(Tools::getValue('select_address', false)) == true OR (Tools::getValue('type') == 'invoice' &amp;&amp; Configuration::get('PS_ORDER_PROCESS_TYPE')))
				$this-&gt;context-&gt;cart-&gt;id_address_invoice = (int)$address-&gt;id;
			elseif (Configuration::get('PS_ORDER_PROCESS_TYPE'))
				$this-&gt;context-&gt;cart-&gt;id_address_invoice = (int)$this-&gt;context-&gt;cart-&gt;id_address_delivery;
			$this-&gt;context-&gt;cart-&gt;update();

			if ($this-&gt;ajax)
			{
				$return = array(
					'hasError' =&gt; (bool)$this-&gt;errors,
					'errors' =&gt; $this-&gt;errors,
					'id_address_delivery' =&gt; (int)$this-&gt;context-&gt;cart-&gt;id_address_delivery,
					'id_address_invoice' =&gt; (int)$this-&gt;context-&gt;cart-&gt;id_address_invoice
				);
				die(Tools::jsonEncode($return));
			}

			// Redirect to old page or current page
			if ($back = Tools::getValue('back'))
			{
				if ($back == Tools::secureReferrer(Tools::getValue('back')))
					Tools::redirect(html_entity_decode($back));
				$mod = Tools::getValue('mod');
				Tools::redirect('index.php?controller='.$back.($mod ? '&amp;back='.$mod : ''));
			}
			else
				Tools::redirect('index.php?controller=addresses');
		}		
		$this-&gt;errors[] = Tools::displayError('An error occurred while updating your address.');
	}
</pre>
<p>Right before the // CHeck Phone comment, add:</p>
<pre class="brush: php; title: ; notranslate">
		if ( !Tools::getValue('my_custom_field'))
			$this-&gt;errors[] = Tools::displayError('The custom field is mandatory!');
</pre>
<p>So that an error will be thrown if your clients leave that field empty!</p>
<p>Remember to erase the class index file again, of course.</p>
<div class="separator"></div>
<h2>Adding the new field to the address format in Prestashop</h2>
<p>As a side note, be aware that in order to display the new field we added we need to change the address format for each country. I am not currently aware of a simple way to apply address changes to all countries at once. Therefore, head over to <strong>Localization > Countries</strong>, click on a country name and add the new field to the address box:</p>
<p><a href="http://nemops.com/wp-content/uploads/2014/04/new_registration_fields_bo.jpg"><img src="http://nemops.com/wp-content/uploads/2014/04/new_registration_fields_bo-680x216.jpg" alt="Adding the new field to the address format in Prestashop" width="680" height="216" class="aligncenter size-large wp-image-1954" /></a></p>
<div class="separator"></div>
<h2>What for new Customer Fields?</h2>
<p>Throughout this tutorial, we added a new field to the Address object. However, it is also possible to create a new basic customer field, to sit along name, lastname and email in the very basic registration (even without an address). To do so, you can simply apply the same process to the <strong>Customer</strong> class, and relative controllers. Just be aware that you will need to edit a couple of different template files: <strong>identity.tpl</strong> and <strong>authentication.tpl</strong>, as well as <strong>order-opc-new-account.tpl</strong> if you use the one page checkout!</p>
<div class="separator"></div>
<p><strong>UPDATE! If you prefer a simple solution, I created a module that automates the process and does much more, find it <a href="http://store.nemops.com/modules/45-prestashop-address-fields.html#.WhvflkqWaUk" title="PrestaShop Address Fields Module">here</a></strong></p>
<h3>Additional Resources</h3>
<ul>
<li>
		<a href="http://nemops.com/extending-prestashop-objects/#.U1WG4Pna6r0" title="How to extend Prestashop objects" target="_blank">How to extend Prestashop objects</a>
	</li>
</ul>
<p>The post <a rel="nofollow" href="http://nemops.com/new-customer-address-fields-prestashop/">How to add new fields to the customer address in Prestashop</a> appeared first on <a rel="nofollow" href="http://nemops.com">NemoPS</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://nemops.com/new-customer-address-fields-prestashop/feed/</wfw:commentRss>
		<slash:comments>60</slash:comments>
		</item>
		<item>
		<title>Properly extending Prestashop Objects</title>
		<link>http://nemops.com/extending-prestashop-objects/</link>
		<comments>http://nemops.com/extending-prestashop-objects/#comments</comments>
		<pubDate>Mon, 03 Jun 2013 13:51:07 +0000</pubDate>
		<dc:creator><![CDATA[Nemo]]></dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[Classes]]></category>
		<category><![CDATA[overrides]]></category>
		<category><![CDATA[prestashop]]></category>

		<guid isPermaLink="false">http://nemops.com/?p=1334</guid>
		<description><![CDATA[<p>Extending Prestashop Objects in the proper way can be a hit-and-miss process because of the uneven core structure. In this tutorial we will add a whole new custom field to the product class and see how to make it editable from the back office. Introduction Prestashop offers quite enough options to satisfy most of the [&#8230;]</p>
<p>The post <a rel="nofollow" href="http://nemops.com/extending-prestashop-objects/">Properly extending Prestashop Objects</a> appeared first on <a rel="nofollow" href="http://nemops.com">NemoPS</a>.</p>
]]></description>
				<content:encoded><![CDATA[<p>Extending Prestashop Objects in the proper way can be a hit-and-miss process because of the uneven core structure. In this tutorial we will add a whole new custom field to the product class and see how to make it editable from the back office.</p>
<p><span id="more-1334"></span></p>
<a class="download-files button style1" href="http://nemops.com/wp-content/uploads/2013/06/extending_prestashop_objects_PF.zip" title="Download Project Files">Download Project Files</a>
<h2>Introduction</h2>
<p>Prestashop offers quite enough options to satisfy most of the e-merchants. However, there are situations where we really need an extra field for a type of object, and we can&#8217;t achieve the result with the different base funcionalities. In today&#8217;s tutorial we will be adding a new custom field to the product object, and then display it in the product page in the front office. Not only that, but we will also see how to make the field editable from the back office (and the exceptions beyond the product object type).</p>
<p>We will basically do this:</p>
<ul>
<li>Add the proper database field</li>
<li>Add the Product Class override</li>
<li>Edit the Product admin page template</li>
<li>Edit the product.tpl file of our theme to display the new field</li>
</ul>
<p>&nbsp;</p>
<p>Note that Prestashop allows you to override without the need of adding your files manually, by simply creating your overrides in a module&#8217;s folder, it would add them automatically when the module is installed. However, I find the automated process to cause more troubles than benefits, therefore I&#8217;ll go for a manual override</p>
<div class="separator"></div>
<h2>Step 1 &#8211; Database and Product Override</h2>
<p>Let&#8217;s start off by adding the new field in the database. You can use any tool you prefer, I will go for phpmyAdmin.</p>
<p>Access your Prestashop database and locate the *prefix*<strong>product</strong> table. The prifix should be ps_, if you didn&#8217;t change it. I will stay generic, so I will add a simple test field to hold any kind of content. We will see how to create translatable fields later on in the tutorial. Create a new column with the following settings:</p>
<ul>
<li>Name: extrafield</li>
<li>Type: text</li>
</ul>
<p>&nbsp;</p>
<p>Notice that <strong>the column name should reflect the name of the variable you will assign to the product in the class override.</strong> Keep this in mind when you ad your own fields.</p>
<p>Now that we&#8217;re done with the table, let&#8217;s move to the override. Create a new file named <strong>Product.php</strong> (with the capital P) in <em>override/classes</em>. Open it up in a code editor and add the following snippet:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php 
Class Product extends ProductCore
{
	
}
?&gt;
</pre>
<p><strong>Note:</strong> I added the closing php tag for my syntax highliter to work properly, but you can feel free to leave it out.</p>
<p>This is the usual way to override an object in Prestashop: <strong>ObjectName extends ObjectNameCore</strong>. Not to hard to remember, is it?</p>
<p>At this point you&#8217;ll need to erase the <strong>class_index.php</strong> file located in the <em>cache/</em> folder. This wouldn&#8217;t have been necessary if we used an auto override generated by a module</p>
<p>To be sure the override is working, add some garbage text like &#8216;sdfafgyusar&#8217; inside that file so that you&#8217;re sure it will break, and reload the Prestashop page. If it breaks, the override is being loaded.</p>
<p>Get rid of the garbage text and instead chenge your class as follows:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php 
Class Product extends ProductCore
{
	public $extrafield;

	public function __construct($id_product = null, $full = false, $id_lang = null, $id_shop = null, Context $context = null)
	{
		self::$definition['fields']['extrafield'] = array('type' =&gt; self::TYPE_STRING, 'validate' =&gt; 'isGenericName', 'size' =&gt; 64);
		parent::__construct($id_product, $full, $id_lang, $id_shop, $context);
	}
}
?&gt;
</pre>
<p><strong>Explanation:</strong> What we are doing here is basically letting the class file know it has a new database column to take into consideration. Note that if you don&#8217;t need to edit the field in the back office, the construct part is not needed as it&#8217;s meant to validate the input field when adding it in the Product admin panel. We are telling Prestashop it must be a generic string, and it can be no longer than 64 characters. You can leave the validate and size parts away, if you want, but <strong>always be sure the extra field is added to the definitions list before calling the parent constructor.</strong> Also, pay attention at the original class contructor as that and yours must have the same arguments, or at least the same ones. This means you can add another optional parameter, but the original ones <strong>must be there</strong></p>
<p>Here are the various types a property can be</p>
<ul>
<li>TYPE_INT</li>
<li>TYPE_BOOL</li>
<li>TYPE_STRING</li>
<li>TYPE_FLOAT</li>
<li>TYPE_DATE</li>
<li>TYPE_HTML</li>
<li>TYPE_NOTHING</li>
</ul>
<p>&nbsp;</p>
<p>If you want to add a whole object as property (in a case like categories or manufacturers) you can also use the <strong>HAS_ONE</strong> and <strong>HAS_MANY</strong> object types. We won&#8217;t dive deep into this kind of extension, at the moment.</p>
<p>As for the validation, there are many things you can check the input against. For a complete list you can check all the methods of the <strong>Validate</strong> class.</p>
<div class="separator"></div>
<h2>Step 2 &#8211; Creating the  new Back Office input</h2>
<p>Okay, we have our field. And as I said that&#8217;s it if you are happy with changing the value via CSV or every time in the database. Since this is not the case in most of the situations, we now need a user friendly way to edit the new field. This is where editing the back office template becomes necessary. <strong>BUT</strong> be careful: this is not always the case. It&#8217;s true for products, since the interface of this type of object is built with .tpls like the front office. However, many other objects (I would say, basically all of them) don&#8217;t make extensive use of templates, but relay on controller to manage the way they display data. We will see how to deal with this kind of exception later on in the tut.</p>
<p>For now, reach the admin folder, then go to <em>/themes/default/template/controllers/products</em>. In this folder, you&#8217;ll see a bunch of tpl files whose names are equal to the name of the sections the product page is divided into. For simplicity, I will choose the first one, <strong>informations</strong>. Copy <strong>informations.tpl</strong> and go back to the main folder. Now access <em>override/controllers/admin/templates/</em>. We need to recreate the controller name folder structure inside, in our case, simply <em>products</em>. THe final directory structure is <em>override/controllers/admin/templates/products/</em>. Once you&#8217;re done, paste the information template file inside.</p>
<p>Open it, then locate the following snippet</p>
<pre class="brush: php; html-script: true; title: ; notranslate">
		&lt;tr&gt;
			&lt;td class=&quot;col-left&quot;&gt;&lt;label&gt;{$bullet_common_field} {l s='UPC:'}&lt;/label&gt;&lt;/td&gt;
			&lt;td style=&quot;padding-bottom:5px;&quot;&gt;
				&lt;input size=&quot;55&quot; maxlength=&quot;12&quot; type=&quot;text&quot; name=&quot;upc&quot; value=&quot;{$product-&gt;upc|escape:html:'UTF-8'}&quot; style=&quot;width: 130px; margin-right: 5px;&quot; /&gt; &lt;span class=&quot;small&quot;&gt;{l s='(US, Canada)'}&lt;/span&gt;
			&lt;/td&gt;
		&lt;/tr&gt;

</pre>
<p>It&#8217;s the one that displays the UPC code for the product. As we are creating a non-translatable generic field, a good position for it would be after the UPC code input. Therefore, after the previous table row, add this one (before the table closing tag of course!)</p>
<pre class="brush: php; html-script: true; title: ; notranslate">
		&lt;tr&gt;
			&lt;td class=&quot;col-left&quot;&gt;&lt;label&gt;{$bullet_common_field} {l s='Extra Field:'}&lt;/label&gt;&lt;/td&gt;
			&lt;td style=&quot;padding-bottom:5px;&quot;&gt;
				&lt;input size=&quot;55&quot; maxlength=&quot;12&quot; type=&quot;text&quot; name=&quot;extrafield&quot; value=&quot;{$product-&gt;extrafield|escape:html:'UTF-8'}&quot; style=&quot;width: 130px; margin-right: 5px;&quot; /&gt; &lt;span class=&quot;small&quot;&gt;{l s='(Our Extra FIeld)'}&lt;/span&gt;
			&lt;/td&gt;
		&lt;/tr&gt;

</pre>
<p><strong>Explanation:</strong> we are basically replicating the UPC box, with some adjustments to display that field ($product->extrafield instead of $product->upc). <strong>Pay attention to the name of the input</strong> as it must be equal to the name of the object property we used when defining the class and constructor.</p>
<p>And that&#8217;s basically it, add some content and save it, it will be added in the database!</p>
<div class="separator"></div>
<h2>Step 3 &#8211; Displaying the new Property in the template</h2>
<p>After all we did, this part will be a piece of cake. It couldn&#8217;t be easier: open up <strong>product.tpl</strong> located in your theme&#8217;s folder, and add the following snippet where you want the extra field to appear:</p>
<pre class="brush: php; html-script: true; title: ; notranslate">

&lt;p&gt;{l s='Our extra field'}: {$product-&gt;extrafield}&lt;/p&gt;

</pre>
<p>Piece o&#8217;cake! Now let&#8217;s move to something trickier, <strong>creating a translatable field</strong></p>
<div class="separator"></div>
<h2>Part 4 &#8211; Translatable fields</h2>
<p>The process of creating a translatable field instead of a generic one slightly differs from what we did before, but not that much. Instead of adding the new column to the product table, let&#8217;s add it to product_lang with the following properties:</p>
<ul>
<li>Name: extra_description</li>
<li>Type: text</li>
</ul>
<p>&nbsp;</p>
<p>Open up our beloved product override again, and change it as follows:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php

Class Product extends ProductCore
{
	public $extrafield;
	public $extra_description;

	public function __construct($id_product = null, $full = false, $id_lang = null, $id_shop = null, Context $context = null)
	{
		self::$definition['fields']['extrafield'] = array('type' =&gt; self::TYPE_STRING, 'validate' =&gt; 'isReference', 'size' =&gt; 64);
		self::$definition['fields']['extra_description'] = array('type' =&gt; self::TYPE_STRING, 'validate' =&gt; 'isGenericName', 'size' =&gt; 64, 'lang' =&gt; true, 'required' =&gt; true);
		parent::__construct($id_product, $full, $id_lang, $id_shop, $context);
		
	}
}

?&gt;

</pre>
<p>Just some slight modifications as you can see. We added the property the same way, but then slightly modified it&#8217;s definition: we added &#8216;lang=>true&#8217; to let Prestashop know this field must be taken from the product language table, and it&#8217;s required when saving the product.</p>
<p>Now onto adding it to the back office. Same informations.tpl file we used before, but this time the right place is after the product name. Here&#8217;s how that table row reads:</p>
<pre class="brush: php; html-script: true; title: ; notranslate">
		&lt;tr&gt;
			&lt;td class=&quot;col-left&quot;&gt;
				{include file=&quot;controllers/products/multishop/checkbox.tpl&quot; field=&quot;name&quot; type=&quot;default&quot; multilang=&quot;true&quot;}
				&lt;label&gt;{l s='Name:'}&lt;/label&gt;
			&lt;/td&gt;
			&lt;td style=&quot;padding-bottom:5px;&quot; class=&quot;translatable&quot;&gt;
			{foreach from=$languages item=language}
				&lt;div class=&quot;lang_{$language.id_lang}&quot; style=&quot;{if !$language.is_default}display: none;{/if} float: left;&quot;&gt;
						&lt;input class=&quot;{$class_input_ajax}{if !$product-&gt;id}copy2friendlyUrl{/if} updateCurrentText&quot; size=&quot;43&quot; type=&quot;text&quot; {if !$product-&gt;id}disabled=&quot;disabled&quot;{/if}
						id=&quot;name_{$language.id_lang}&quot; name=&quot;name_{$language.id_lang}&quot;
						value=&quot;{$product-&gt;name[$language.id_lang]|htmlentitiesUTF8|default:''}&quot;/&gt;&lt;sup&gt; *&lt;/sup&gt;
					&lt;span class=&quot;hint&quot; name=&quot;help_box&quot;&gt;{l s='Invalid characters:'} &lt;&gt;;=#{}&lt;span class=&quot;hint-pointer&quot;&gt;&amp;nbsp;&lt;/span&gt;
					&lt;/span&gt;
				&lt;/div&gt;
			{/foreach}
			&lt;/td&gt;
		&lt;/tr&gt;
</pre>
<p>Right after it, add:</p>
<pre class="brush: php; html-script: true; title: ; notranslate">
		&lt;tr&gt;
			&lt;td class=&quot;col-left&quot;&gt;
				{include file=&quot;controllers/products/multishop/checkbox.tpl&quot; field=&quot;name&quot; type=&quot;default&quot; multilang=&quot;true&quot;}
				&lt;label&gt;{l s='Extra Description:'}&lt;/label&gt;
			&lt;/td&gt;
			&lt;td style=&quot;padding-bottom:5px;&quot; class=&quot;translatable&quot;&gt;
			{foreach from=$languages item=language}
				&lt;div class=&quot;lang_{$language.id_lang}&quot; style=&quot;{if !$language.is_default}display: none;{/if} float: left;&quot;&gt;
						&lt;input size=&quot;43&quot; type=&quot;text&quot; {if !$product-&gt;id}disabled=&quot;disabled&quot;{/if}
						id=&quot;extra_description_{$language.id_lang}&quot; name=&quot;extra_description_{$language.id_lang}&quot;
						value=&quot;{$product-&gt;extra_description[$language.id_lang]|htmlentitiesUTF8|default:''}&quot;/&gt;&lt;sup&gt; *&lt;/sup&gt;
					&lt;/span&gt;
				&lt;/div&gt;
			{/foreach}
			&lt;/td&gt;
		&lt;/tr&gt;	
</pre>
<p><strong>Explanation:</strong> A couple of things to notice: first:</p>
<pre class="brush: php; html-script: true; title: ; notranslate">

			&lt;td class=&quot;col-left&quot;&gt;
				{include file=&quot;controllers/products/multishop/checkbox.tpl&quot; field=&quot;name&quot; type=&quot;default&quot; multilang=&quot;true&quot;}
				&lt;label&gt;{l s='Extra Description:'}&lt;/label&gt;
			&lt;/td&gt;

</pre>
<p>See the checkbox.tpl inclusion? This is useful for multishop environments, and allows you to have a different text value for each of your shops.</p>
<p>Next:</p>
<pre class="brush: php; html-script: true; title: ; notranslate">
			&lt;td style=&quot;padding-bottom:5px;&quot; class=&quot;translatable&quot;&gt;
			{foreach from=$languages item=language}
				&lt;div class=&quot;lang_{$language.id_lang}&quot; style=&quot;{if !$language.is_default}display: none;{/if} float: left;&quot;&gt;
						&lt;input size=&quot;43&quot; type=&quot;text&quot; {if !$product-&gt;id}disabled=&quot;disabled&quot;{/if}
						id=&quot;extra_description_{$language.id_lang}&quot; name=&quot;extra_description_{$language.id_lang}&quot;
						value=&quot;{$product-&gt;extra_description[$language.id_lang]|htmlentitiesUTF8|default:''}&quot;/&gt;&lt;sup&gt; *&lt;/sup&gt;
					&lt;/span&gt;
				&lt;/div&gt;
			{/foreach}
			&lt;/td&gt;

</pre>
<p>In this table cell, as we need to display one field for each language, we need to go through all of the languages set, and display the input accordingly. Notice that <strong>the name and id of the input field MUST be in this format: &#8216;fieldname_{$language.id_lang}&#8217; so that it is unique for each language.</strong> Type something &amp; save.</p>
<p>And what about displaying it? Well, it&#8217;s the same as the previous property, simply add this in product.tpl:</p>
<pre class="brush: php; html-script: true; title: ; notranslate">
&lt;p&gt;{$product-&gt;extra_description}&lt;/p&gt;

</pre>
<div class="separator"></div>
<h2>Adding extra fields to other Object types</h2>
<p>As I mentioned at the beginning of the tutorial, products use a different input system for the back office, compared to all the other object types. We will now use categories as an example of inputting extra properties for these objects.</p>
<p>First of all, create the new database column for the <strong>category</strong> table as we did before. Use any name you like, I will call it <strong>extravar</strong> and it will be, again, a text field.</p>
<p>Now add the category override following the same steps used for the product, or download and add the Category.php override file you find in the project archive. Then, we are ready to start.</p>
<h3>The Admin*ObjectName*Controller</h3>
<p>These other objects&#8217; forms in the back office are rendered using controllers, therefore we would need another override. BUT because of Prestashop&#8217;s fault, you can&#8217;t directly extend the method used to render the form. We could add an extra field by using a dedicated variable, but for some weird reason it only allows us to add one single field. Hopefully, it will get fixed soon. Therefore, despite being bad practice, we need to grab the entire <strong>renderForm</strong> method from the original controller and paste it into our new override with some slight modifications. Go to <em>controllers/admin/</em> and open the file named <strong>AdminCategoriesController.php</strong></p>
<p>Copy the whole <strong>renderForm()</strong> method. Now go to <em>override/controllers/admin</em> and create a new file named <strong>AdminCategoriesController.php</strong>. Inside it, add the class declaration:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php 
Class AdminCategoriesController extends AdminCategoriesControllerCore
{
	
}
?&gt;
</pre>
<p>Then, paste the renderForm method:</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php 
Class AdminCategoriesController extends AdminCategoriesControllerCore
{
		public function renderForm()
	{
		$this-&gt;initToolbar();
		$obj = $this-&gt;loadObject(true);
		$id_shop = Context::getContext()-&gt;shop-&gt;id;
		$selected_cat = array((isset($obj-&gt;id_parent) &amp;&amp; $obj-&gt;isParentCategoryAvailable($id_shop))? (int)$obj-&gt;id_parent : (int)Tools::getValue('id_parent', Category::getRootCategory()-&gt;id));
		$unidentified = new Group(Configuration::get('PS_UNIDENTIFIED_GROUP'));
		$guest = new Group(Configuration::get('PS_GUEST_GROUP'));
		$default = new Group(Configuration::get('PS_CUSTOMER_GROUP'));

		$unidentified_group_information = sprintf($this-&gt;l('%s - All people without a valid customer account.'), '&lt;b&gt;'.$unidentified-&gt;name[$this-&gt;context-&gt;language-&gt;id].'&lt;/b&gt;');
		$guest_group_information = sprintf($this-&gt;l('%s - Customer who placed an order with the guest checkout.'), '&lt;b&gt;'.$guest-&gt;name[$this-&gt;context-&gt;language-&gt;id].'&lt;/b&gt;');
		$default_group_information = sprintf($this-&gt;l('%s - All people who have created an account on this site.'), '&lt;b&gt;'.$default-&gt;name[$this-&gt;context-&gt;language-&gt;id].'&lt;/b&gt;');
		$root_category = Category::getRootCategory();
		$root_category = array('id_category' =&gt; $root_category-&gt;id, 'name' =&gt; $root_category-&gt;name);
		$this-&gt;fields_form = array(
			'tinymce' =&gt; true,
			'legend' =&gt; array(
				'title' =&gt; $this-&gt;l('Category'),
				'image' =&gt; '../img/admin/tab-categories.gif'
			),
			'input' =&gt; array(
				array(
					'type' =&gt; 'text',
					'label' =&gt; $this-&gt;l('Name:'),
					'name' =&gt; 'name',
					'lang' =&gt; true,
					'size' =&gt; 48,
					'required' =&gt; true,
					'class' =&gt; 'copy2friendlyUrl',
					'hint' =&gt; $this-&gt;l('Invalid characters:').' &lt;&gt;;=#{}',
				),
				array(
					'type' =&gt; 'radio',
					'label' =&gt; $this-&gt;l('Displayed:'),
					'name' =&gt; 'active',
					'required' =&gt; false,
					'class' =&gt; 't',
					'is_bool' =&gt; true,
					'values' =&gt; array(
						array(
							'id' =&gt; 'active_on',
							'value' =&gt; 1,
							'label' =&gt; $this-&gt;l('Enabled')
						),
						array(
							'id' =&gt; 'active_off',
							'value' =&gt; 0,
							'label' =&gt; $this-&gt;l('Disabled')
						)
					)
				),
				array(
					'type' =&gt; 'categories',
					'label' =&gt; $this-&gt;l('Parent category:'),
					'name' =&gt; 'id_parent',
					'values' =&gt; array(
						'trads' =&gt; array(
							 'Root' =&gt; $root_category,
							 'selected' =&gt; $this-&gt;l('Selected'),
							 'Collapse All' =&gt; $this-&gt;l('Collapse All'),
							 'Expand All' =&gt; $this-&gt;l('Expand All')
						),
						'selected_cat' =&gt; $selected_cat,
						'input_name' =&gt; 'id_parent',
						'use_radio' =&gt; true,
						'use_search' =&gt; false,
						'disabled_categories' =&gt; array(4),
						'top_category' =&gt; Category::getTopCategory(),
						'use_context' =&gt; true,
					)
				),
				array(
					'type' =&gt; 'radio',
					'label' =&gt; $this-&gt;l('Root Category:'),
					'name' =&gt; 'is_root_category',
					'required' =&gt; false,
					'is_bool' =&gt; true,
					'class' =&gt; 't',
					'values' =&gt; array(
						array(
							'id' =&gt; 'is_root_on',
							'value' =&gt; 1,
							'label' =&gt; $this-&gt;l('Yes')
						),
						array(
							'id' =&gt; 'is_root_off',
							'value' =&gt; 0,
							'label' =&gt; $this-&gt;l('No')
						)
					)
				),
				array(
					'type' =&gt; 'textarea',
					'label' =&gt; $this-&gt;l('Description:'),
					'name' =&gt; 'description',
					'lang' =&gt; true,
					'rows' =&gt; 10,
					'cols' =&gt; 100,
					'hint' =&gt; $this-&gt;l('Invalid characters:').' &lt;&gt;;=#{}'
				),
				array(
					'type' =&gt; 'file',
					'label' =&gt; $this-&gt;l('Image:'),
					'name' =&gt; 'image',
					'display_image' =&gt; true,
					'desc' =&gt; $this-&gt;l('Upload a category logo from your computer.')
				),
				array(
					'type' =&gt; 'text',
					'label' =&gt; $this-&gt;l('Meta title:'),
					'name' =&gt; 'meta_title',
					'lang' =&gt; true,
					'hint' =&gt; $this-&gt;l('Forbidden characters:').' &lt;&gt;;=#{}'
				),
				array(
					'type' =&gt; 'text',
					'label' =&gt; $this-&gt;l('Meta description:'),
					'name' =&gt; 'meta_description',
					'lang' =&gt; true,
					'hint' =&gt; $this-&gt;l('Forbidden characters:').' &lt;&gt;;=#{}'
				),
				array(
					'type' =&gt; 'tags',
					'label' =&gt; $this-&gt;l('Meta keywords:'),
					'name' =&gt; 'meta_keywords',
					'lang' =&gt; true,
					'hint' =&gt; $this-&gt;l('Forbidden characters:').' &lt;&gt;;=#{}',
					'desc' =&gt; $this-&gt;l('To add &quot;tags,&quot; click in the field, write something, and then press &quot;Enter.&quot;')
				),
				array(
					'type' =&gt; 'text',
					'label' =&gt; $this-&gt;l('Friendly URL:'),
					'name' =&gt; 'link_rewrite',
					'lang' =&gt; true,
					'required' =&gt; true,
					'hint' =&gt; $this-&gt;l('Only letters and the minus (-) character are allowed.')
				),
				array(
					'type' =&gt; 'group',
					'label' =&gt; $this-&gt;l('Group access:'),
					'name' =&gt; 'groupBox',
					'values' =&gt; Group::getGroups(Context::getContext()-&gt;language-&gt;id),
					'info_introduction' =&gt; $this-&gt;l('You now have three default customer groups.'),
					'unidentified' =&gt; $unidentified_group_information,
					'guest' =&gt; $guest_group_information,
					'customer' =&gt; $default_group_information,
					'desc' =&gt; $this-&gt;l('Mark all of the customer groups you;d like to have access to this category.')
				)
			),
			'submit' =&gt; array(
				'title' =&gt; $this-&gt;l('Save'),
				'class' =&gt; 'button'
			)
		);
		
		$this-&gt;tpl_form_vars['shared_category'] = Validate::isLoadedObject($obj) &amp;&amp; $obj-&gt;hasMultishopEntries(); 
		$this-&gt;tpl_form_vars['PS_ALLOW_ACCENTED_CHARS_URL'] = (int)Configuration::get('PS_ALLOW_ACCENTED_CHARS_URL');
		if (Shop::isFeatureActive())
			$this-&gt;fields_form['input'][] = array(
				'type' =&gt; 'shop',
				'label' =&gt; $this-&gt;l('Shop association:'),
				'name' =&gt; 'checkBoxShopAsso',
			);
		// remove category tree and radio button &quot;is_root_category&quot; if this category has the root category as parent category to avoid any conflict
		if ($this-&gt;_category-&gt;id_parent == Category::getTopCategory()-&gt;id &amp;&amp; Tools::isSubmit('updatecategory'))
			foreach ($this-&gt;fields_form['input'] as $k =&gt; $input)
				if (in_array($input['name'], array('id_parent', 'is_root_category')))
					unset($this-&gt;fields_form['input'][$k]);

		if (Tools::isSubmit('add'.$this-&gt;table.'root'))
			unset($this-&gt;fields_form['input'][2],$this-&gt;fields_form['input'][3]);

		if (!($obj = $this-&gt;loadObject(true)))
			return;

		$image = ImageManager::thumbnail(_PS_CAT_IMG_DIR_.'/'.$obj-&gt;id.'.jpg', $this-&gt;table.'_'.(int)$obj-&gt;id.'.'.$this-&gt;imageType, 350, $this-&gt;imageType, true);

		$this-&gt;fields_value = array(
			'image' =&gt; $image ? $image : false,
			'size' =&gt; $image ? filesize(_PS_CAT_IMG_DIR_.'/'.$obj-&gt;id.'.jpg') / 1000 : false
		);

		// Added values of object Group
		$category_groups_ids = $obj-&gt;getGroups();

		$groups = Group::getGroups($this-&gt;context-&gt;language-&gt;id);
		// if empty $carrier_groups_ids : object creation : we set the default groups
		if (empty($category_groups_ids))
		{
			$preselected = array(Configuration::get('PS_UNIDENTIFIED_GROUP'), Configuration::get('PS_GUEST_GROUP'), Configuration::get('PS_CUSTOMER_GROUP'));
			$category_groups_ids = array_merge($category_groups_ids, $preselected);
		}
		foreach ($groups as $group)
			$this-&gt;fields_value['groupBox_'.$group['id_group']] = Tools::getValue('groupBox_'.$group['id_group'], (in_array($group['id_group'], $category_groups_ids)));

		return AdminController::renderForm();
	}
}
?&gt;
</pre>
<p>Massive, but no fear we only need to amend it slightly. First of all, change the last line to</p>
<pre class="brush: php; title: ; notranslate">

return AdminController::renderForm();
</pre>
<p>This way, we are bypassing the original categories controller call, which would otherwise cause the form to appear two times. Next, let&#8217;s amend the fields_form array. If you look at the whole method you&#8217;ll understand why we can&#8217;t extend it: if we add something to the array from the extension class, then call the parent, the new parameter will never see the light as the array is being recreated from scratch. If we place the constructor before, the content will be outputted before we add the parameter. That&#8217;s why we need to use this kind of trick. It&#8217;s not optimal as we bypass the direct parent, but at the moment it&#8217;s the only way to go.</p>
<p>In any case, add this new array to the fields_form fields list, right after the category name. </p>
<pre class="brush: php; title: ; notranslate">
				array(
					'type' =&gt; 'text',
					'label' =&gt; $this-&gt;l('Our new field:'),
					'name' =&gt; 'extravar',
					'size' =&gt; 128
				),
</pre>
<p>And that&#8217;s basically it. If you add a languaged field like we did for the product, you&#8217;d only need to specify lang => true in the array of the new field, and the form helper will take cart of displaying all the proper HTML. At this point, you can display it in category.tpl as we did with the product extension.</p>
<div class="separator"></div>
<h2>Conclusion</h2>
<p>As you saw, extending a Prestashop class object is not terribly difficult. There are still some flaws with most of the controller-driven forms, but hopefully the Prestateam will fix them, so that we can use a simpler method in the next releases</p>
<h3>Additional Resources</h3>
<ul>
<li><a href="http://nemops.com/creating-new-pages-in-prestashop/" title="Creating new pages for your Prestashop store">Creating new pages for your Prestashop store</a></li>
</ul>
<p>The post <a rel="nofollow" href="http://nemops.com/extending-prestashop-objects/">Properly extending Prestashop Objects</a> appeared first on <a rel="nofollow" href="http://nemops.com">NemoPS</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://nemops.com/extending-prestashop-objects/feed/</wfw:commentRss>
		<slash:comments>34</slash:comments>
		</item>
	</channel>
</rss>
