<?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; category</title>
	<atom:link href="http://nemops.com/tag/category/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>Display products from subcategories in PrestaShop 1.6</title>
		<link>http://nemops.com/prestashop-16-display-products-from-subcategories/</link>
		<comments>http://nemops.com/prestashop-16-display-products-from-subcategories/#comments</comments>
		<pubDate>Wed, 25 Jan 2017 11:52:29 +0000</pubDate>
		<dc:creator><![CDATA[Nemo]]></dc:creator>
				<category><![CDATA[Tips n Tricks]]></category>
		<category><![CDATA[category]]></category>
		<category><![CDATA[prestashop 1.6]]></category>
		<category><![CDATA[products]]></category>
		<category><![CDATA[subcategories]]></category>

		<guid isPermaLink="false">http://nemops.com/?p=2970</guid>
		<description><![CDATA[<p>Are you wondering how to display products from subcategories, without using the layered navigation module? Let&#8217;s see it for PrestaShop 1.6!</p>
<p>The post <a rel="nofollow" href="http://nemops.com/prestashop-16-display-products-from-subcategories/">Display products from subcategories in PrestaShop 1.6</a> appeared first on <a rel="nofollow" href="http://nemops.com">NemoPS</a>.</p>
]]></description>
				<content:encoded><![CDATA[<p>Are you wondering how to display products from subcategories, without using the layered navigation module? Let&#8217;s see it for PrestaShop 1.6!</p>
<p><span id="more-2970"></span></p>

	<div class="video-embed">
		<iframe width="640" height="360" src="http://www.youtube.com/embed/6BBM62S6I08" 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>
<p>The post <a rel="nofollow" href="http://nemops.com/prestashop-16-display-products-from-subcategories/">Display products from subcategories 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/prestashop-16-display-products-from-subcategories/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Hooking modules to the Category Back Office in Prestashop</title>
		<link>http://nemops.com/hook-modules-prestashop-category-back-office/</link>
		<comments>http://nemops.com/hook-modules-prestashop-category-back-office/#comments</comments>
		<pubDate>Tue, 17 May 2016 09:42:05 +0000</pubDate>
		<dc:creator><![CDATA[Nemo]]></dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[back office]]></category>
		<category><![CDATA[category]]></category>
		<category><![CDATA[hooks]]></category>
		<category><![CDATA[prestashop]]></category>

		<guid isPermaLink="false">http://nemops.com/?p=2772</guid>
		<description><![CDATA[<p>If you want to add extra fields to the category configuration page, there is no better way than using a module hooked to DisplayBackOfficeCategory. Let&#8217;s see how to implement it! Starting with a simple module First, download the project file, and place the module you will find inside the &#8220;start&#8221; folder in the modules/ folder [&#8230;]</p>
<p>The post <a rel="nofollow" href="http://nemops.com/hook-modules-prestashop-category-back-office/">Hooking modules to the Category Back Office in Prestashop</a> appeared first on <a rel="nofollow" href="http://nemops.com">NemoPS</a>.</p>
]]></description>
				<content:encoded><![CDATA[<p>If you want to add extra fields to the category configuration page, there is no better way than using a module hooked to DisplayBackOfficeCategory. Let&#8217;s see how to implement it!</p>
<p><span id="more-2772"></span></p>
<a class="download-files button style1" href="http://nemops.com/wp-content/uploads/2016/05/project.zip" title="Download Project Files">Download Project Files</a>
<h2>Starting with a simple module</h2>
<p>First, download the project file, and place the module you will find inside the &#8220;start&#8221; folder in the modules/ folder of your prestashop installation.</p>
<p>Open up displaybocategorytut.php, it&#8217;s just a very basic module structure.</p>
<pre class="brush: php; title: ; notranslate">
if (!defined('_PS_VERSION_'))
	exit;

class displayBoCategoryTut extends Module
{

	protected $_errors = array();
	protected $_html = '';


	public function __construct()
	{
		$this-&gt;name = 'displaybocategorytut';
		$this-&gt;tab = 'front_office_features';
		$this-&gt;version = '1.0';
		$this-&gt;author = 'Nemo';
		$this-&gt;need_instance = 0;
		
		$this-&gt;bootstrap = true;

	 	parent::__construct();

		$this-&gt;displayName = $this-&gt;l('Display BO Category Tutorial');
		$this-&gt;description = $this-&gt;l('Displays an additional field in the category back office');
	}
	
	public function install()
	{
		if (!parent::install())
			return false;
		return true;
	}

	public function uninstall()
	{
		if (!parent::uninstall())
			return false;
		return true;
	}

}

</pre>
<p>The first thing we need is of course some additional data we want to save and retrieve. For this reason, we need an extra method to modify the database, and add a further column to the category table:</p>
<pre class="brush: php; title: ; notranslate">
	public function alterTable($method = 'add')
	{
		if($method == 'add')
			$sql = 'ALTER TABLE ' . _DB_PREFIX_ . 'category ADD `myowninput` VARCHAR (255) NOT NULL';
		else 
			$sql = 'ALTER TABLE ' . _DB_PREFIX_ . 'category DROP COLUMN `myowninput`';

		if(!Db::getInstance()-&gt;Execute($sql))
			return false;
		return true;
	}
</pre>
<p><strong>Explanation</strong>: since we need the extra column, we are using a single method to add and remove it. We are passing in a &#8220;method&#8221; parameter, so that we can switch between actions depending on our needs.</p>
<p>As mentioned, we need this column to be added when installing, and removed when uninstalling, so let&#8217;s amend the install and uninstall methods as well:</p>
<pre class="brush: php; title: ; notranslate">


	public function install()
	{
		if (!parent::install() OR
			!$this-&gt;alterTable() OR
			!$this-&gt;registerHook('displayBackOfficeCategory') OR
			!$this-&gt;registerHook('categoryAddition') OR
			!$this-&gt;registerHook('categoryUpdate')
			)
			return false;
		return true;
	}

	public function uninstall()
	{
		if (!parent::uninstall() OR
			!$this-&gt;alterTable('remove'))
			return false;
		return true;
	}

</pre>
<p>Additionally, I am registering two hooks to update the field&#8217;s value. This would not be necessary if we had a Category class override to take care of the extra field (see more on <a href="http://nemops.com/extending-prestashop-objects/" title="Extending PrestaShop Objects">Extending PrestaShop Objects</a>).</p>
<p>Next, we will need some way to retrieve our custom field from the database</p>
<pre class="brush: php; title: ; notranslate">
	public function getMyOwnInput($id_category)
	{
		return Db::getInstance()-&gt;getValue('SELECT myowninput FROM '._DB_PREFIX_.'category WHERE id_category = '. (int)$id_category);
	}
</pre>
<p>Then, it&#8217;s time to display something in the category back office. Let&#8217;s create the hooking method:</p>
<pre class="brush: php; title: ; notranslate">
	public function hookDisplayBackOfficeCategory($params)
	{

		// we need an actual id, otherwise if we are just adding the category this field can be left empty
		if(Tools::getValue('id_category'))
			$myowninput = $this-&gt;getMyOwnInput(Tools::getValue('id_category'));
		else $myowninput = '';

		$this-&gt;context-&gt;smarty-&gt;assign(array(
			'myowninput'=&gt; $myowninput
		));


		return $this-&gt;display(__FILE__, 'backoffice.tpl');
	}

</pre>
<p><strong>Explanation:</strong> First off, we make sure we have a category ID that we can use to retrieve the value from the database. We use a switch to prevent the script from causing trouble in case there is none (that is, we are just creating a new category). Then, we assign the input value to the template, and return it. We don&#8217;t have it yet, so let&#8217;s create a new file inside <em>views\templates\hook</em>, naming it <strong>backoffice.tpl</strong></p>
<p>Let&#8217;s add some simple markup:</p>
<pre class="brush: php; html-script: true; title: ; notranslate">
&lt;div class=&quot;form-group&quot;&gt;
	&lt;label class=&quot;control-label col-lg-3&quot;&gt;
		&lt;span class=&quot;label-tooltip&quot;&gt;
			{l s='Custom Input' mod='displaybocategorytut'}
		&lt;/span&gt;
	&lt;/label&gt;
	&lt;div class=&quot;col-lg-4&quot;&gt;
		&lt;input type=&quot;text&quot; name=&quot;myowninput&quot; value=&quot;{$myowninput}&quot;&gt;
	&lt;/div&gt;
	&lt;div class=&quot;col-lg-6 col-lg-offset-3&quot;&gt;
	&lt;/div&gt;
&lt;/div&gt;
</pre>
<p>We are ready to install the module! Go ahead and do it from the modules page. If everything goes smoothly as it should, reach a category and click edit (or add one). It should display our new field:</p>
<p><a href="http://nemops.com/wp-content/uploads/2016/05/displaybocategory.png"><img src="http://nemops.com/wp-content/uploads/2016/05/displaybocategory-680x247.png" alt="New input in the PrestaShop Category Back Office " width="680" height="247" class="aligncenter size-large wp-image-2776" /></a></p>
<p>It won&#8217;t do much at the time being, since we are not saving the value on submit. For this, we need another couple of methods that will take advantage of the hooks we registered upon install:</p>
<pre class="brush: php; title: ; notranslate">
	public function hookCategoryAddition($params)
	{
		Db::getInstance()-&gt;update('category', array('myowninput' =&gt; pSQL(Tools::getValue('myowninput'))), 'id_category = ' . $params['category']-&gt;id);
	}

	public function hookCategoryUpdate($params)
	{
		$this-&gt;hookCategoryAddition($params);
	}
</pre>
<p><strong>Explanation:</strong> here we are using some standard code to update the database: the myowninput value is sent over via POST when submitting the page, and the $params variable passed to the method contains a useful Category object, from which we are taking the ID.</p>
<p>Now write something in the field and save, it should be stored in the database! To make sure everything runs smoothly, create a new category as well, adding content to our field before submitting the page.</p>
<p>Once everything works, you can try to expand the module with hooks, in the front office as well, and take full advantage of the new value.</p>
<h3>Additional Resources </h3>
<ul>
<li>
Learn how to develop PrestaShop Modules with my <a href="http://nemops.com/prestashop-modules-course/" title="PrestaShop Modules Course">PrestaShop Modules Course</a>
</li>
</ul>
<p>The post <a rel="nofollow" href="http://nemops.com/hook-modules-prestashop-category-back-office/">Hooking modules to the Category Back Office in Prestashop</a> appeared first on <a rel="nofollow" href="http://nemops.com">NemoPS</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://nemops.com/hook-modules-prestashop-category-back-office/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Removing links from the top level in the PrestaShop top Menu</title>
		<link>http://nemops.com/prestashop-top-menu-removing-links/</link>
		<comments>http://nemops.com/prestashop-top-menu-removing-links/#comments</comments>
		<pubDate>Tue, 24 Nov 2015 10:35:40 +0000</pubDate>
		<dc:creator><![CDATA[Nemo]]></dc:creator>
				<category><![CDATA[Tips n Tricks]]></category>
		<category><![CDATA[blocktopmenu]]></category>
		<category><![CDATA[category]]></category>
		<category><![CDATA[prestashop]]></category>
		<category><![CDATA[top menu]]></category>

		<guid isPermaLink="false">http://nemops.com/?p=2608</guid>
		<description><![CDATA[<p>PrestaShop&#8217;s Top Menu usually lets you click on the first level categories, as well as their children in the mega-dropdown. In this quick tip, we will disable the top level links and let them be triggers for the menu only. Overriding the Top Horizontal Menu Module To make our modification scalable and have it preserve [&#8230;]</p>
<p>The post <a rel="nofollow" href="http://nemops.com/prestashop-top-menu-removing-links/">Removing links from the top level in the PrestaShop top Menu</a> appeared first on <a rel="nofollow" href="http://nemops.com">NemoPS</a>.</p>
]]></description>
				<content:encoded><![CDATA[<p>PrestaShop&#8217;s Top Menu usually lets you click on the first level categories, as well as their children in the mega-dropdown. In this quick tip, we will disable the top level links and let them be triggers for the menu only.</p>
<p><span id="more-2608"></span></p>
<h2>Overriding the Top Horizontal Menu Module</h2>
<p>To make our modification scalable and have it preserve in future upgrades, of not only PrestaShop, but the module itself, we will create an override of it. Please notice overrides are only available for version 1.6.0.11 and newer. If you are using an older PrestaShop version, you will have to amend the core files directly.</p>
<p>Create a new folder named <strong>blocktopmenu</strong> inside <em>override/modules</em>. Within it, create a new file and name it <strong>blocktopmenu.php</strong>. Open it up in your favorite code editor and add some generic override code inside php tags:</p>
<pre class="brush: php; title: ; notranslate">

class BlockTopMenuOverride extends BlockTopMenu
{

}
</pre>
<p>We want to override a method named <strong>generateCategoriesMenu</strong>. It&#8217;s a protected function so we can easily extend it. Make sure you copy and paste the original one from your module here, as mine might differ even slightly:</p>
<pre class="brush: php; title: ; notranslate">

	protected function generateCategoriesMenu($categories, $is_children = 0)
	{
		$html = '';

		foreach ($categories as $key =&gt; $category)
		{
			if ($category['level_depth'] &gt; 1)
			{
				$cat = new Category($category['id_category']);
				$link = Tools::HtmlEntitiesUTF8($cat-&gt;getLink());
			}
			else
				$link = $this-&gt;context-&gt;link-&gt;getPageLink('index');

			$html .= '&lt;li'.(($this-&gt;page_name == 'category'
				&amp;&amp; (int)Tools::getValue('id_category') == (int)$category['id_category']) ? ' class=&quot;sfHoverForce&quot;' : '').'&gt;';
			$html .= '&lt;a href=&quot;'.$link.'&quot; title=&quot;'.$category['name'].'&quot;&gt;'.$category['name'].'&lt;/a&gt;';

			if ($category['level_depth'] &lt; 4 &amp;&amp; isset($category['children']) &amp;&amp; !empty($category['children']))
			{
				$html .= '&lt;ul&gt;';
				$html .= $this-&gt;generateCategoriesMenu($category['children'], 1);

				if ((int)$category['level_depth'] &gt; 1 &amp;&amp; !$is_children)
				{
					$files = scandir(_PS_CAT_IMG_DIR_);

					if (count($files) &gt; 0)
					{
						$html .= '&lt;li class=&quot;category-thumbnail&quot;&gt;';

						foreach ($files as $file)
							if (preg_match('/^'.$category['id_category'].'-([0-9])?_thumb.jpg/i', $file) === 1)
								$html .= '&lt;div&gt;&lt;img src=&quot;'.$this-&gt;context-&gt;link-&gt;getMediaLink(_THEME_CAT_DIR_.$file)
								.'&quot; alt=&quot;'.Tools::SafeOutput($category['name']).'&quot; title=&quot;'
								.Tools::SafeOutput($category['name']).'&quot; class=&quot;imgm&quot; /&gt;&lt;/div&gt;';

						$html .= '&lt;/li&gt;';
					}
				}

				$html .= '&lt;/ul&gt;';
			}

			$html .= '&lt;/li&gt;';
		}

		return $html;
	}
</pre>
<p>We are interested in the following line:</p>
<pre class="brush: php; title: ; notranslate">
			$html .= '&lt;a href=&quot;'.$link.'&quot; title=&quot;'.$category['name'].'&quot;&gt;'.$category['name'].'&lt;/a&gt;';
</pre>
<p>Which is the one responsible for displaying the link to each category. However, if we were to remove the anchor as it is, it would get rid of <strong>all</strong> the links, and we want to keep the ones inside mega menus. We need to add a condition that first checks we are dealing with our top level. How can we do it?<br />
The most logical way would be to check the &#8220;level_depth&#8221; property of the current category. This <em>might</em> work, in case your top menu categories all belong to the same depth level.</p>
<p>However, we can use another, more reliable variable: <strong>$is_children</strong>. It&#8217;s passed to each iteration of the loop used to generate the category tree, and checks whether we are in the top level or not, so it&#8217;s ideal for our purpose. Knowing that, we can replace the previous line with some logic:</p>
<pre class="brush: php; title: ; notranslate">
if ($is_children == 0)
	$html .= '&lt;a&gt;'.$category['name'].'&lt;/a&gt;';
else
	$html .= '&lt;a href=&quot;'.$link.'&quot; title=&quot;'.$category['name'].'&quot;&gt;'.$category['name'].'&lt;/a&gt;';
</pre>
<p>Please notice it needs an anchor wrapper in any case, to retain its style. Save the override, then reach the <em>cache</em> folder and get rid of <strong>class_index.php</strong> so that the override takes place. <strong>Depending on your configuration, you might as well need to go to Advanced Parameters, Performance, and clear cache.</strong></p>
<p>The post <a rel="nofollow" href="http://nemops.com/prestashop-top-menu-removing-links/">Removing links from the top level in the PrestaShop top Menu</a> appeared first on <a rel="nofollow" href="http://nemops.com">NemoPS</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://nemops.com/prestashop-top-menu-removing-links/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Essential Prestashop Functions &#8211; Day 4</title>
		<link>http://nemops.com/prestashop-functions-4/</link>
		<comments>http://nemops.com/prestashop-functions-4/#comments</comments>
		<pubDate>Wed, 12 Aug 2015 09:39:09 +0000</pubDate>
		<dc:creator><![CDATA[Nemo]]></dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[category]]></category>
		<category><![CDATA[cookies]]></category>
		<category><![CDATA[prestashop]]></category>
		<category><![CDATA[products list]]></category>

		<guid isPermaLink="false">http://nemops.com/?p=2504</guid>
		<description><![CDATA[<p>Prestashop has lots of time-saving functions that we can use when developing modules or extensions. Let&#8217;s see how to get various products list and deal with cookies, in this fourth batch. NOTICE: Values with &#8220;=&#8221; in the declaration are optional. Getting products of a Category This is the preferred method to get products from any [&#8230;]</p>
<p>The post <a rel="nofollow" href="http://nemops.com/prestashop-functions-4/">Essential Prestashop Functions &#8211; Day 4</a> appeared first on <a rel="nofollow" href="http://nemops.com">NemoPS</a>.</p>
]]></description>
				<content:encoded><![CDATA[<p>Prestashop has lots of time-saving functions that we can use when developing modules or extensions. Let&#8217;s see how to get various products list and deal with cookies, in this fourth batch.</p>
<p><span id="more-2504"></span></p>
<p><strong>NOTICE: Values with &#8220;=&#8221; in the declaration are optional. </strong></p>
<h2>Getting products of a Category</h2>
<pre class="brush: php; title: ; notranslate">

Category::getProducts($id_lang, $p, $n, $order_by = null, $order_way = null, $get_total = false, $active = true, $random = false, $random_number_products = 1, $check_access = true, Context $context = null);

</pre>
<p>This is the preferred method to get products from any category in Prestashop. It&#8217;s used not only in categories pages, but by the homefeatured module, as well as others.</p>
<h3>Example Usage</h3>
<pre class="brush: php; title: ; notranslate">

$category = new Category(5);

// Retrieves the first 15 products of a category
$products = $category-&gt;getProducts($this-&gt;context-&gt;language-&gt;id, 1, 15);

// Retrieves the first 15 products of a category, returning the number of total products for that category as well. Ordered by price, lowest to highest
$products = $category-&gt;getProducts($this-&gt;context-&gt;language-&gt;id, 1, 15, 'price', 'asc', true);


// Gets a random number of products, in random order (yes, even if we specified it)
$products = $category-&gt;getProducts($this-&gt;context-&gt;language-&gt;id, 1, 15, 'price', 'asc', false, true);


</pre>
<div class="separator"></div>
<h2>Getting new products</h2>
<pre class="brush: php; title: ; notranslate">

Product::getNewProducts($id_lang, $page_number = 0, $nb_products = 10, $count = false, $order_by = null, $order_way = null, Context $context = null);

</pre>
<p>This method can be used statically, without having to instantiate the product class.</p>
<h3>Example Usage</h3>
<pre class="brush: php; title: ; notranslate">

$newProducts = Product::getNewProducts((int) $this-&gt;context-&gt;language-&gt;id, 0, 10);

</pre>
<div class="separator"></div>
<h2>Getting discounted products</h2>
<pre class="brush: php; title: ; notranslate">

Product::getPricesDrop($id_lang, $page_number = 0, $nb_products = 10, $count = false,
		$order_by = null, $order_way = null, $beginning = false, $ending = false, Context $context = null);

</pre>
<p>This method can also be used statically, without having to instantiate the product class.</p>
<h3>Example Usage</h3>
<pre class="brush: php; title: ; notranslate">


// get the last 10 prices drop, ordered by position
$price_drops = Product::getPricesDrop((int) $this-&gt;context-&gt;language-&gt;id, 0, 10);

// get the last 10 prices drops, ordered by price, but only where the offer's start date is after july 23, 2015
$price_drops =  Product::getPricesDrop((int) $this-&gt;context-&gt;language-&gt;id, 0, 10, false,
		'price', 'asc', '2015-7-23 10:45:32');

</pre>
<div class="separator"></div>
<h2>Getting Best Sales</h2>
<pre class="brush: php; title: ; notranslate">

ProductSale::getBestSales($id_lang, $page_number = 0, $nb_products = 10, $order_by = null, $order_way = null)

</pre>
<p>This method can also be used statically, without having to instantiate the product class.</p>
<h3>Example Usage</h3>
<pre class="brush: php; title: ; notranslate">

// get 10 best selling products, ordered by best selling
$products = ProductSale::getBestSales($this-&gt;context-&gt;language-&gt;id, 0, 10);

</pre>
<div class="separator"></div>
<h2>Getting Best Sales (Light)</h2>
<pre class="brush: php; title: ; notranslate">

ProductSale::getBestSalesLight($id_lang, $page_number = 0, $nb_products = 10, Context $context = null)

</pre>
<p>Lighter and quicker version of the above method, which only retrieves strictly necessary information (not recommended to display products in the product-list template)</p>
<h3>Example Usage</h3>
<pre class="brush: php; title: ; notranslate">

// get 5 best selling products, ordered by best selling, called from a hook method
$products = ProductSale::getBestSalesLight((int)$params['cookie']-&gt;id_lang, 0, 5))

</pre>
<div class="separator"></div>
<h2>Adding variables to the cookie object</h2>
<pre class="brush: php; title: ; notranslate">

Cookie::__set($key, $value);

</pre>
<p>Useful to store dynamic information through pages (like user preferences for the current login session)</p>
<h3>Example Usage</h3>
<pre class="brush: php; title: ; notranslate">

// you might want to trigger this when a user clicks on the cookie loaw banner (where any), so that you are not prompting him to accept it on every page
$this-&gt;context-&gt;cookie-&gt;__set('cookielawaccepted', 1);

// The value can hold strings as well (arrays can be saved by serializing them)
$this-&gt;context-&gt;cookie-&gt;__set('mycustomoptionmode', 'test');


</pre>
<div class="separator"></div>
<h2>Checking cookie variables</h2>
<pre class="brush: php; title: ; notranslate">

Cookie::__get($key);

</pre>
<p>Gets the given key&#8217;s value from the cookie object.</p>
<h3>Example Usage</h3>
<pre class="brush: php; title: ; notranslate">

// Following up the previous example, you can use this to avoid prompting the user again
if(!$this-&gt;context-&gt;cookie-&gt;__get('cookielawaccepted'))
{
	// display the message 
}

</pre>
<div class="separator"></div>
<h2>Clearing a cookie variable</h2>
<pre class="brush: php; title: ; notranslate">

Cookie::__unset($key);

</pre>
<p>Removes the given key from the cookie object.</p>
<h3>Example Usage</h3>
<pre class="brush: php; title: ; notranslate">

// removes the cookie law entry,
$this-&gt;context-&gt;cookie-&gt;__unset('cookielawaccepted')

</pre>
<div class="separator"></div>
<h2>Logging a user out</h2>
<pre class="brush: php; title: ; notranslate">

Customer::logout();

</pre>
<h3>Example Usage</h3>
<pre class="brush: php; title: ; notranslate">

// Clears all of the current session data for this customer
$this-&gt;context-&gt;customer-&gt;logout();

</pre>
<div class="separator"></div>
<h3>Additional Resources</h3>
<ul>
<li><a href="http://nemops.com/prestashop-functions-1/#.Vb8upPnzrmg" title="Essential Prestashop Functions – Day 1">Essential Prestashop Functions – Day 1</a></li>
<li><a href="http://nemops.com/prestashop-functions-2/#.Vb9Bxvnzrmg" title="Essential Prestashop Functions – Day 2">Essential Prestashop Functions – Day 2</a></li>
<li><a href="http://nemops.com/prestashop-functions-3/#.Vb9EAPnzrmg" title="Essential Prestashop Functions – Day 3">Essential Prestashop Functions – Day 3</a></li>
<li><a href="http://nemops.com/prestashop-functions-5/#.Ve6fNxHzrmg" title="Essential Prestashop Functions – Day 5">Essential Prestashop Functions – Day 5</a></li>
</ul>
<p>The post <a rel="nofollow" href="http://nemops.com/prestashop-functions-4/">Essential Prestashop Functions &#8211; Day 4</a> appeared first on <a rel="nofollow" href="http://nemops.com">NemoPS</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://nemops.com/prestashop-functions-4/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Adding a second image for Prestashop categories</title>
		<link>http://nemops.com/prestashop-categories-second-image/</link>
		<comments>http://nemops.com/prestashop-categories-second-image/#comments</comments>
		<pubDate>Wed, 29 Oct 2014 10:55:26 +0000</pubDate>
		<dc:creator><![CDATA[Nemo]]></dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[category]]></category>
		<category><![CDATA[image]]></category>
		<category><![CDATA[prestashop]]></category>

		<guid isPermaLink="false">http://nemops.com/?p=2185</guid>
		<description><![CDATA[<p>Prestashop only allows using one image as category thumbnail by default, thus creating issues in having different formats for subcategory images in the product list view. In this tutorial we will add a secondary image to prestashop categories, to increase flexibility on thumbs display when showing them as subcategories. Prestashop version: any 1.6 (used: 1.6.0.9, [&#8230;]</p>
<p>The post <a rel="nofollow" href="http://nemops.com/prestashop-categories-second-image/">Adding a second image for Prestashop categories</a> appeared first on <a rel="nofollow" href="http://nemops.com">NemoPS</a>.</p>
]]></description>
				<content:encoded><![CDATA[<p>Prestashop only allows using one image as category thumbnail by default, thus creating issues in having different formats for subcategory images in the product list view. In this tutorial we will add a secondary image to prestashop categories, to increase flexibility on thumbs display when showing them as subcategories.</p>
<p><span id="more-2185"></span></p>
<ul>
<li>Prestashop version: any 1.6 (used: 1.6.0.9, should equally apply to 1.5, though not tested)</li>
</ul>
<a class="download-files button style1" href="http://nemops.com/wp-content/uploads/2014/10/second_image_for_categories.zip" title="Download Project Files">Download Project Files</a>
<h2>Introduction</h2>
<p>Before starting, it&#8217;s worth noticing this tutorial implies quite a lot of modifications and overrides, and it&#8217;s therefore recommended that you have a solid knowledge of php before doing anything. As always, refer to the <a href="http://doc.prestashop.com/display/PS15/Overriding+default+behaviors" title="Official Prestashop documentation on Overrides">Official Prestashop documentation on Overrides</a> if you are new to the subject. That said, these are the files we need to override/modify:</p>
<ul>
<li>AdminCategoriesController.php: here is where most of the magic will occur, to upload and delete the new image</li>
<li>Category.php: the category class, as we have to implement the new field and image file deletion</li>
<li>category.tpl: to display the new image for subcategories</li>
<li>.htaccess: only needed if you use Friendly urls, otherwise no image will be shown</li>
</ul>
<div class="separator"></div>
<h2>Extending the AdminCategoriesController file</h2>
<p>The categories&#8217; admin controller is the file we will be mostly dealing with. Although we could modify it directly, it&#8217;s always best practice to use an override. Therefore, create a new file in <em>/override/controllers/admin</em> named <strong>AdminCategoriesController.php</strong>, and paste the following inside php tags:</p>
<pre class="brush: php; title: ; notranslate">
class AdminCategoriesController extends AdminCategoriesControllerCore
{
}
</pre>
<p>Then, reach the original <strong>AdminCategoriesController</strong> located within <em>/controllers/admin</em>, open it, locate and copy <strong>the whole renderForm method</strong>. Then, paste it inside the new override:</p>
<pre class="brush: php; title: ; notranslate">


class AdminCategoriesController extends AdminCategoriesControllerCore
{


	public function renderForm()
	{
		$this-&gt;initToolbar();
		$obj = $this-&gt;loadObject(true);
		$id_shop = Context::getContext()-&gt;shop-&gt;id;
		$selected_categories = 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;');

		if (!($obj = $this-&gt;loadObject(true)))
			return;

		$image = _PS_CAT_IMG_DIR_.$obj-&gt;id.'.jpg';
		$image_url = ImageManager::thumbnail($image, $this-&gt;table.'_'.(int)$obj-&gt;id.'.'.$this-&gt;imageType, 350,
			$this-&gt;imageType, true, true);
		$image_size = file_exists($image) ? filesize($image) / 1000 : false;

		$this-&gt;fields_form = array(
			'tinymce' =&gt; true,
			'legend' =&gt; array(
				'title' =&gt; $this-&gt;l('Category'),
				'icon' =&gt; 'icon-tags'
			),
			'input' =&gt; array(
				array(
					'type' =&gt; 'text',
					'label' =&gt; $this-&gt;l('Name'),
					'name' =&gt; 'name',
					'lang' =&gt; true,
					'required' =&gt; true,
					'class' =&gt; 'copy2friendlyUrl',
					'hint' =&gt; $this-&gt;l('Invalid characters:').' &lt;&gt;;=#{}',
				),
				array(
					'type' =&gt; 'switch',
					'label' =&gt; $this-&gt;l('Displayed'),
					'name' =&gt; 'active',
					'required' =&gt; false,
					'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',
					'tree'  =&gt; array(
						'id'                  =&gt; 'categories-tree',
						'selected_categories' =&gt; $selected_categories,
						'disabled_categories' =&gt; !Tools::isSubmit('add'.$this-&gt;table) ? array($this-&gt;_category-&gt;id) : null
					)
				),
				array(
					'type' =&gt; 'textarea',
					'label' =&gt; $this-&gt;l('Description'),
					'name' =&gt; 'description',
					'autoload_rte' =&gt; true,
					'lang' =&gt; true,
					'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,
					'image' =&gt; $image_url ? $image_url : false,
					'size' =&gt; $image_size,
					'delete_url' =&gt; self::$currentIndex.'&amp;'.$this-&gt;identifier.'='.$this-&gt;_category-&gt;id.'&amp;token='.$this-&gt;token.'&amp;deleteImage=1',
					'hint' =&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('To add &quot;tags,&quot; click in the field, write something, and then press &quot;Enter.&quot;').'&amp;nbsp;'.$this-&gt;l('Forbidden characters:').' &lt;&gt;;=#{}'
				),
				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, numbers, underscore (_) 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,
					'hint' =&gt; $this-&gt;l('Mark all of the customer groups which you would like to have access to this category.')
				)
			),
			'submit' =&gt; array(
				'title' =&gt; $this-&gt;l('Save'),
				'name' =&gt; 'submitAdd'.$this-&gt;table.($this-&gt;_category-&gt;is_root_category &amp;&amp; !Tools::isSubmit('add'.$this-&gt;table) &amp;&amp; !Tools::isSubmit('add'.$this-&gt;table.'root') ? '': 'AndBackToParent')
			)
		);

		$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');
		$this-&gt;tpl_form_vars['displayBackOfficeCategory'] = Hook::exec('displayBackOfficeCategory');

		// Display this field only if multistore option is enabled
		if (Configuration::get('PS_MULTISHOP_FEATURE_ACTIVE') &amp;&amp; Tools::isSubmit('add'.$this-&gt;table.'root'))
		{
			$this-&gt;fields_form['input'][] = array(
				'type' =&gt; 'switch',
				'label' =&gt; $this-&gt;l('Root Category'),
				'name' =&gt; 'is_root_category',
				'required' =&gt; false,
				'is_bool' =&gt; true,
				'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')
					)
				)
			);
			unset($this-&gt;fields_form['input'][2],$this-&gt;fields_form['input'][3]);
		}
		// Display this field only if multistore option is enabled AND there are several stores configured
		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 (!($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)));

		$this-&gt;fields_value['is_root_category'] = (bool)Tools::isSubmit('add'.$this-&gt;table.'root');

		return parent::renderForm();
	}
	
}
</pre>
<p>Notice the last row, <strong>return parent::renderForm();</strong>. Change it to <strong>return AdminController::renderForm();</strong>. if we didn&#8217;t take this counter-measure, all of our changes would have been overridden by the original controller. To make sure the override works, reach the <em>cache/</em> and erase <strong>class_index.php</strong> to enable the new file. Then login to the back office, and check the single category view works as expected. If so, read on.</p>
<h3>Adding the new field</h3>
<p>First off, we will need to add the code that displays any eventual image we upload. To do so, locate the following:</p>
<pre class="brush: php; title: ; notranslate">
		$image = _PS_CAT_IMG_DIR_.$obj-&gt;id.'.jpg';
		$image_url = ImageManager::thumbnail($image, $this-&gt;table.'_'.(int)$obj-&gt;id.'.'.$this-&gt;imageType, 350,
			$this-&gt;imageType, true, true);
		$image_size = file_exists($image) ? filesize($image) / 1000 : false;
</pre>
<p>Right after it, add</p>
<pre class="brush: php; title: ; notranslate">
		$image2 = _PS_CAT_IMG_DIR_.$obj-&gt;id.'_second.jpg';
		$image_url2 = ImageManager::thumbnail($image2, $this-&gt;table.'_'.(int)$obj-&gt;id.'_second.'.$this-&gt;imageType, 350,
			$this-&gt;imageType, true, true);
		$image_size2 = file_exists($image2) ? filesize($image2) / 1000 : false;
</pre>
<p>Which is basically the same with modified names. Next, right below we have the fields list. We need to add our file input here, so that we can later upload the image. Therefore, locate:</p>
<pre class="brush: php; title: ; notranslate">
				array(
					'type' =&gt; 'file',
					'label' =&gt; $this-&gt;l('Image'),
					'name' =&gt; 'image',
					'display_image' =&gt; true,
					'image' =&gt; $image_url ? $image_url : false,
					'size' =&gt; $image_size,
					'delete_url' =&gt; self::$currentIndex.'&amp;'.$this-&gt;identifier.'='.$this-&gt;_category-&gt;id.'&amp;token='.$this-&gt;token.'&amp;deleteImage=1',
					'hint' =&gt; $this-&gt;l('Upload a category logo from your computer.'),
				),
</pre>
<p>And add the following right after it</p>
<pre class="brush: php; title: ; notranslate">
				array(
					'type' =&gt; 'file',
					'label' =&gt; $this-&gt;l('Image2'),
					'name' =&gt; 'image2',
					'display_image' =&gt; true,
					'image' =&gt; $image_url2 ? $image_url2 : false,
					'size' =&gt; $image_size2,
					'delete_url' =&gt; self::$currentIndex.'&amp;'.$this-&gt;identifier.'='.$this-&gt;_category-&gt;id.'&amp;token='.$this-&gt;token.'&amp;deleteImage2=1',
					'hint' =&gt; $this-&gt;l('Upload a secondary category logo from your computer.'),
				),
</pre>
<p>Once again, same code, different names. And, lastly, change this:</p>
<pre class="brush: php; title: ; notranslate">
		$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
		);
</pre>
<p>Into this</p>
<pre class="brush: php; title: ; notranslate">
		$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);
		$image2 = ImageManager::thumbnail(_PS_CAT_IMG_DIR_.'/'.$obj-&gt;id.'_second.jpg', $this-&gt;table.'_'.(int)$obj-&gt;id.'_second.'.$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,
			'image2' =&gt; $image2 ? $image2 : false,
			'size2' =&gt; $image2 ? filesize(_PS_CAT_IMG_DIR_.'/'.$obj-&gt;id.'_second.jpg') / 1000 : false
		);
</pre>
<p>Useless to mention we are doing the same, once more. We are done with renderForm, let&#8217;s deal with <strong>postImage()</strong> now!</p>
<h3>Managing the new image upload and removal</h3>
<p>Trying to fill in the new file input would not produce anything, at the moment. The whole upload magic is held through a method named <strong>postImage()</strong>, which we are going to override and extend. Thus, copy it from the original AdminCategoriesController, and paste it inside the override file. It should look like the following:</p>
<pre class="brush: php; title: ; notranslate">

	protected function postImage($id)
	{
		$ret = parent::postImage($id);
		if (($id_category = (int)Tools::getValue('id_category')) &amp;&amp;
			isset($_FILES) &amp;&amp; count($_FILES) &amp;&amp; $_FILES['image']['name'] != null &amp;&amp;
			file_exists(_PS_CAT_IMG_DIR_.$id_category.'.jpg'))
		{
			$images_types = ImageType::getImagesTypes('categories');
			foreach ($images_types as $k =&gt; $image_type)
			{
				ImageManager::resize(
					_PS_CAT_IMG_DIR_.$id_category.'.jpg',
					_PS_CAT_IMG_DIR_.$id_category.'-'.stripslashes($image_type['name']).'.jpg',
					(int)$image_type['width'], (int)$image_type['height']
				);
			}
		}

		return $ret;
	}
</pre>
<p>Get rid of <strong>return $ret;</strong>, and add the following instead:</p>
<pre class="brush: php; title: ; notranslate">


		$ret2 = $this-&gt;uploadImage($id.'_second', 'image2', $this-&gt;fieldImageSettings['dir'].'/');
		if (($id_category = (int)Tools::getValue('id_category')) &amp;&amp;
			isset($_FILES) &amp;&amp; count($_FILES) &amp;&amp; $_FILES['image2']['name'] != null &amp;&amp;
			file_exists(_PS_CAT_IMG_DIR_.$id_category.'_second.jpg'))
		{
			$images_types = ImageType::getImagesTypes('categories');
			foreach ($images_types as $k =&gt; $image_type)
			{
				ImageManager::resize(
					_PS_CAT_IMG_DIR_.$id_category.'_second.jpg',
					_PS_CAT_IMG_DIR_.$id_category.'_second-'.stripslashes($image_type['name']).'.jpg',
					(int)$image_type['width'], (int)$image_type['height']
				);
			}
		}

		return $ret &amp;&amp; $ret2;

</pre>
<p><strong>Explanation:</strong> first, we are grabbing some code directly from the adminController. We have to use a custom name for the image upload, which is the category id plus _second, using the field &#8220;image2&#8243;. The rest is simply a copy/paste of the above, with, again, changes in the name only. Lastly, we make sure that we return true only if both eventual uploads were successful.</p>
<p><strong>We have a problem though</strong>. At the time being, Prestashop still thinks we only have one image for the category entity. Thus, when uploading any other image for it (excluding thumbs), it will erase the previous one. We can test it right away: upload a new image for the image2 field, you will notice the original category image will be erased. As we don&#8217;t want this, we have to grab <strong>imageUpload()</strong> directly from the AdminController.php file, and extend it. Locate the method, and paste it inside our override. In Prestashop 1.6.0.9, it looks like this: </p>
<pre class="brush: php; title: ; notranslate">
	protected function uploadImage($id, $name, $dir, $ext = false, $width = null, $height = null)
	{
		if (isset($_FILES[$name]['tmp_name']) &amp;&amp; !empty($_FILES[$name]['tmp_name']))
		{
			// Delete old image
			if (Validate::isLoadedObject($object = $this-&gt;loadObject()))
				$object-&gt;deleteImage();
			else
				return false;

			// Check image validity
			$max_size = isset($this-&gt;max_image_size) ? $this-&gt;max_image_size : 0;
			if ($error = ImageManager::validateUpload($_FILES[$name], Tools::getMaxUploadSize($max_size)))
				$this-&gt;errors[] = $error;

			$tmp_name = tempnam(_PS_TMP_IMG_DIR_, 'PS');
			if (!$tmp_name)
				return false;

			if (!move_uploaded_file($_FILES[$name]['tmp_name'], $tmp_name))
				return false;

			// Evaluate the memory required to resize the image: if it's too much, you can't resize it.
			if (!ImageManager::checkImageMemoryLimit($tmp_name))
				$this-&gt;errors[] = Tools::displayError('Due to memory limit restrictions, this image cannot be loaded. Please increase your memory_limit value via your server\'s configuration settings. ');

			// Copy new image
			if (empty($this-&gt;errors) &amp;&amp; !ImageManager::resize($tmp_name, _PS_IMG_DIR_.$dir.$id.'.'.$this-&gt;imageType, (int)$width, (int)$height, ($ext ? $ext : $this-&gt;imageType)))
				$this-&gt;errors[] = Tools::displayError('An error occurred while uploading the image.');

			if (count($this-&gt;errors))
				return false;
			if ($this-&gt;afterImageUpload())
			{
				unlink($tmp_name);
				return true;
			}
			return false;
		}
		return true;
	}

</pre>
<p>Pay attention at this snippet:</p>
<pre class="brush: php; title: ; notranslate">

			// Delete old image
			if (Validate::isLoadedObject($object = $this-&gt;loadObject()))
				$object-&gt;deleteImage();
			else
				return false;
</pre>
<p>It&#8217;s where the original image gets erased to make room for a new one. Change it to:</p>
<pre class="brush: php; title: ; notranslate">

			// Delete old image
			if (Validate::isLoadedObject($object = $this-&gt;loadObject()))
			{
				if($name == 'image2')
					$object-&gt;deleteImage2();
				else $object-&gt;deleteImage();
			} else
				return false;
</pre>
<p>It won&#8217;t work yet as didn&#8217;t override the Category class and added the deleteImage2 method. Before leaving this file, we need to extend one, last function, <strong>postProcess()</strong>. Copy it again from the original AdminCategoriesController, it should be something like:</p>
<pre class="brush: php; title: ; notranslate">

	public function postProcess()
	{
		if (!in_array($this-&gt;display, array('edit', 'add')))
			$this-&gt;multishop_context_group = false;
		if (Tools::isSubmit('forcedeleteImage') || (isset($_FILES['image']) &amp;&amp; $_FILES['image']['size'] &gt; 0) || Tools::getValue('deleteImage'))
		{
			$this-&gt;processForceDeleteImage();
			if (Tools::isSubmit('forcedeleteImage'))
				Tools::redirectAdmin(self::$currentIndex.'&amp;token='.Tools::getAdminTokenLite('AdminCategories').'&amp;conf=7');
		}

		return parent::postProcess();
	}
</pre>
<p>We need to take care of the secondary image deletion:</p>
<pre class="brush: php; title: ; notranslate">

	public function postProcess()
	{
		if (!in_array($this-&gt;display, array('edit', 'add')))
			$this-&gt;multishop_context_group = false;
		if (Tools::isSubmit('forcedeleteImage') || (isset($_FILES['image']) &amp;&amp; $_FILES['image']['size'] &gt; 0) || Tools::getValue('deleteImage'))
		{
			$this-&gt;processForceDeleteImage();
			if (Tools::isSubmit('forcedeleteImage'))
				Tools::redirectAdmin(self::$currentIndex.'&amp;token='.Tools::getAdminTokenLite('AdminCategories').'&amp;conf=7');
		} else if(Tools::getValue('deleteImage2'))
		{
			$category = $this-&gt;loadObject(true);

			if (Validate::isLoadedObject($category))
				if($category-&gt;deleteImage2(true))
					Tools::redirectAdmin(self::$currentIndex.'&amp;token='.Tools::getAdminTokenLite('AdminCategories').'&amp;updatecategory&amp;id_category='.$category-&gt;id.'&amp;conf=7');
		}

		return parent::postProcess();
	}
</pre>
<p>And we are done with this file, let&#8217;s extend the Category class now.</p>
<div class="separator"></div>
<h2>Overriding the category class</h2>
<p>Create a new file inside <em>override/classes</em> and name it <strong>Category.php</strong> (or use an existing override if you have it). First of all, we need to test it the back office functionality, so let&#8217;s add that deleteImage2() method:</p>
<pre class="brush: php; title: ; notranslate">


Class Category extends CategoryCore
{


	public function deleteImage2($force_delete = false)
	{
		if (!$this-&gt;id)
			return false;
		
		if ($force_delete || !$this-&gt;hasMultishopEntries())
		{
			/* Deleting object images and thumbnails (cache) */
			if ($this-&gt;image_dir)
			{
				if (file_exists($this-&gt;image_dir.$this-&gt;id.'_second.'.$this-&gt;image_format)
					&amp;&amp; !unlink($this-&gt;image_dir.$this-&gt;id.'_second.'.$this-&gt;image_format))
					return false;
			}
			if (file_exists(_PS_TMP_IMG_DIR_.$this-&gt;def['table'].'_'.$this-&gt;id.'_second.'.$this-&gt;image_format)
				&amp;&amp; !unlink(_PS_TMP_IMG_DIR_.$this-&gt;def['table'].'_'.$this-&gt;id.'_second.'.$this-&gt;image_format))
				return false;
			if (file_exists(_PS_TMP_IMG_DIR_.$this-&gt;def['table'].'_mini_'.$this-&gt;id.'_second.'.$this-&gt;image_format)
				&amp;&amp; !unlink(_PS_TMP_IMG_DIR_.$this-&gt;def['table'].'_mini_'.$this-&gt;id.'_second.'.$this-&gt;image_format))
				return false;
	
			$types = ImageType::getImagesTypes();
			foreach ($types as $image_type)
				if (file_exists($this-&gt;image_dir.$this-&gt;id.'_second-'.stripslashes($image_type['name']).'.'.$this-&gt;image_format)
				&amp;&amp; !unlink($this-&gt;image_dir.$this-&gt;id.'_second-'.stripslashes($image_type['name']).'.'.$this-&gt;image_format))
					return false;
		}
		return true;
	}
}
</pre>
<p>To create it, I simply copied the original deleteImage from the <strong>objectModel</strong>, and modified the name of each entry to reflect our convention (_second).</p>
<p>Time to test the back office! Access the categories tab, then open up one of them and try adding an image. Then, delete this image to check if that works as well. Then again add one, and one immediately after to check it gets over-written. Lastly, make sure the original one isn&#8217;t erased during this process, and the new one is not affected by any operation on the first onee. </p>
<p>After checking this, it&#8217;s time too display the new thumb. Since we will use it in subcategories, we need to assign it at the time they are retrieved for the template display. This is held through the <strong>getSubcategories()</strong> method of the Category class. Thus, copy the original one and paste it inside our override:</p>
<pre class="brush: php; title: ; notranslate">
	public function getSubCategories($id_lang, $active = true)
	{
		$sql_groups_where = '';
		$sql_groups_join = '';
		if (Group::isFeatureActive())
		{
			$sql_groups_join = 'LEFT JOIN `'._DB_PREFIX_.'category_group` cg ON (cg.`id_category` = c.`id_category`)';
			$groups = FrontController::getCurrentCustomerGroups();
			$sql_groups_where = 'AND cg.`id_group` '.(count($groups) ? 'IN ('.implode(',', $groups).')' : '='.(int)Group::getCurrent()-&gt;id);
		}

		$result = Db::getInstance(_PS_USE_SQL_SLAVE_)-&gt;executeS('
		SELECT c.*, cl.id_lang, cl.name, cl.description, cl.link_rewrite, cl.meta_title, cl.meta_keywords, cl.meta_description
		FROM `'._DB_PREFIX_.'category` c
		'.Shop::addSqlAssociation('category', 'c').'
		LEFT JOIN `'._DB_PREFIX_.'category_lang` cl ON (c.`id_category` = cl.`id_category` AND `id_lang` = '.(int)$id_lang.' '.Shop::addSqlRestrictionOnLang('cl').')
		'.$sql_groups_join.'
		WHERE `id_parent` = '.(int)$this-&gt;id.'
		'.($active ? 'AND `active` = 1' : '').'
		'.$sql_groups_where.'
		GROUP BY c.`id_category`
		ORDER BY `level_depth` ASC, category_shop.`position` ASC');

		foreach ($result as &amp;$row)
		{
			
			$row['legend'] = 'no picture';
		}
		return $result;
	}
</pre>
<p>Then, right after this:</p>
<pre class="brush: php; title: ; notranslate">
$row['id_image'] = Tools::file_exists_cache(_PS_CAT_IMG_DIR_.$row['id_category'].'.jpg') ? (int)$row['id_category'] : Language::getIsoById($id_lang).'-default';
</pre>
<p>Add our new image definition</p>
<pre class="brush: php; title: ; notranslate">
$row['id_image2'] = Tools::file_exists_cache(_PS_CAT_IMG_DIR_.$row['id_category'].'_second.jpg') ? (int)$row['id_category'] .'_second' : Language::getIsoById($id_lang).'-default';
</pre>
<p>And we are done with php! </p>
<div class="separator"></div>
<h2>Display the new image in the template</h2>
<p>We are almost there. Open <strong>category.tpl</strong>, located in the theme&#8217;s folder. Locate:</p>
<pre class="brush: php; html-script: true; title: ; notranslate">
{if $subcategory.id_image}
	&lt;img class=&quot;replace-2x&quot; src=&quot;{$link-&gt;getCatImageLink($subcategory.link_rewrite, $subcategory.id_image, 'medium_default')|escape:'html':'UTF-8'}&quot; alt=&quot;&quot; width=&quot;{$mediumSize.width}&quot; height=&quot;{$mediumSize.height}&quot; /&gt;
{else}
</pre>
<p>And change it to</p>
<pre class="brush: php; html-script: true; title: ; notranslate">
{if $subcategory.id_image2}
	&lt;img class=&quot;replace-2x&quot; src=&quot;{$link-&gt;getCatImageLink($subcategory.link_rewrite, $subcategory.id_image2, 'medium_default')|escape:'html':'UTF-8'}&quot; alt=&quot;&quot; width=&quot;{$mediumSize.width}&quot; height=&quot;{$mediumSize.height}&quot; /&gt;
{else}
</pre>
<p>This will be enough if friendly urls are not enabled. <strong>But what if we are using rewritten URLs?</strong>. Sadly, we need to hardcode one, last modification in the <strong>.htaccess file</strong>. It is not exactly bulletproof, but it worked out well in all my tests. Therefore, open your <strong>.htaccess</strong>, and add the following <strong>at the very beginning, right BEFORE &#8220;# ~~start~~ Do not remove this comment, Prestashop will keep automatically the code outside this comment when .htaccess will be generated again&#8221;</strong></p>
<pre class="brush: php; title: ; notranslate">
&lt;IfModule mod_rewrite.c&gt;
RewriteRule ^c/([0-9]+)_second(\-[\.*_a-zA-Z0-9-]*)(-[0-9]+)?/.+\.jpg$ %{ENV:REWRITEBASE}img/c/$1_second$2$3.jpg [L]
&lt;/IfModule&gt;
</pre>
<p>This will make sure our &#8220;_second&#8221; text in the image path won&#8217;t be treated as part of the category ID, thus making it impossible to retrieve the picture.</p>
<div class="separator"></div>
<h2>Conclusion</h2>
<p>Despite being a bit cumbersome, adding a secondary image for categories (or actually any other entity such as manufacturers or suppliers) is indeed possible by using this technique. The final trick for rewritten-url environments is to make sure the proper regEx is added right at the beginning of the .htaccess file.</p>
<p>The post <a rel="nofollow" href="http://nemops.com/prestashop-categories-second-image/">Adding a second image for Prestashop categories</a> appeared first on <a rel="nofollow" href="http://nemops.com">NemoPS</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://nemops.com/prestashop-categories-second-image/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
	</channel>
</rss>
