Grid display for Prestashop 1.5 default theme

I’ve been frequently asked how to turn Prestashop’s default theme product list view into a grid. Today, we will take the basic theme and turn the product list display into a cool grid with 4 items per row.

Download Project Files

Finished result

Grid display for Prestashop 1.5 default theme

Note: I used Prestashop 1.5.0.17 for this tutorial. Since 1.5.1, the image type name must be followed by _default, so, in the “home” case, it will be “home_default”

Let’s get started!

No time for chitchat. If you clicked to see this tut, you only want to turn the considerably not-so-good-looking Prestashop default product list into a cooler product grid. Please, note that the tutorial is for Prestashop 1.5 and uses the base product-list.tpl file of the default theme for this version only. If you are using 1.4 ,you can try to follow along, but don’t blindly copy/paste stuff, or you might get some errors!

Knowing this, login to the admin panel and go to Preferences > Themes. Prestashop 1.5 allows us to create new themes directly from the back office. Click Add new in the top left corner of the page and fill the form as shown in the picture:

Prestashop 1.5 create new themeOf course, you are free to use any name you want. Just be sure you select a theme to copy missing files from, since we are creating a new theme. Choose the default theme for this.

Before editing TPL files, be sure you set Template Caching to Compile cache if templates are updated or Force Compile under Advanced parameters > Performance

Now, you might have noticed I have removed the left column to give the grid a bit more space, and have the design feel less cluttered. To do it, open header.tpl and look for the following lines:

			<!-- Left -->
				<div id="left_column" class="column grid_2 alpha">
					{$HOOK_LEFT_COLUMN}
				</div>

				<!-- Center -->
				<div id="center_column" class=" grid_5">

We need to hide the left column, and widen the center one, so modify it like this:

			{*<div id="left_column" class="column grid_2 alpha">
					{$HOOK_LEFT_COLUMN}
				</div>*}

				<!-- Center -->
				<div id="center_column" class=" grid_7 alpha">

Explanation: I used smarty comments ({* content commented out *}) to hide the left column, then changed the center column class to grid_7 to take up the 2 grid units left empty by the left column. Notice that I added the aplha class so that the column doen’s have a left margin.

Please note that, by just doing this, all modules hooked to the left column will still be processed. To remove them completely and save some memory you will have to go to modules/positions in the admin panel, and remove them from there.

 

Let’s get rid of the list

Now that we have a new theme to play with, go to the newly created folder, then, inside this, css/ and open up product_list.css. This is the stylesheet responsible of the look of the list. Delete everything inside this file, since we will do it from scratch.

Now open the template file product-list.tpl that you find in the theme’s root. Delete everything from line 31 to line 71. The file should now look like this:

{*
* 2007-2012 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
*  @author PrestaShop SA <contact@prestashop.com>
*  @copyright  2007-2012 PrestaShop SA
*  @version  Release: $Revision: 7457 $
*  @license    http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
*  International Registered Trademark &amp; Property of PrestaShop SA
*}

{if isset($products)}
	<!-- Products list -->
	<ul id="product_list" class="clear">
	{foreach from=$products item=product name=products}
	{/foreach}
	</ul>
	<!-- /Products list -->
{/if}

Of course, if you now refresh a category page, you’ll see nothing anymore. Be sure you change the ul class from clear to clearfix.

The TPL file

Let’s go ahead and add some content to this template, shall we? Start by adding the following lines after line 30 (but before the closing foreach):

	<li class="ajax_block_product {if $smarty.foreach.products.first}first_item{elseif $smarty.foreach.products.last}last_item{/if} {if $smarty.foreach.products.iteration%4 == 0}last_row_item{else}item{/if}">
			<a href="{$product.link|escape:'htmlall':'UTF-8'}" class="product_img_link" title="{$product.name|escape:'htmlall':'UTF-8'}">
				<img src="{$link->getImageLink($product.link_rewrite, $product.id_image, 'home')}" alt="{$product.legend|escape:'htmlall':'UTF-8'}" {if isset($homeSize)} width="{$homeSize.width}" height="{$homeSize.height}"{/if} />
				{if isset($product.new) &amp;&amp; $product.new == 1}<span class="new">{l s='New'}</span>{/if}
			</a>
			<p class="clear"></p>
			<h3><a href="{$product.link|escape:'htmlall':'UTF-8'}" title="{$product.name|escape:'htmlall':'UTF-8'}">{$product.name|escape:'htmlall':'UTF-8'|truncate:26:'...':true}</a></h3>

		</li>

Explanation: The first line is the most important one. Have a close look (I know it’s a bit messy, unfortunatly the syntax highlight doesn’t have a smarty brush!) at the class of the list item:

class="ajax_block_product {if $smarty.foreach.products.first}first_item{elseif $smarty.foreach.products.last}last_item{/if} {if $smarty.foreach.products.iteration%4 == 0}last_row_item{else}item{/if}"

Notice the “{if $smarty.foreach.products.iteration%4 == 0}last_row_item” part of the code. If you want to change the number of items displayed, change the 4 to something else. Of course, you’ll then need to change the css accordingly.

The first item we are placing in the list item is the product image, wrapped in a link that points to the single product view. We also add a to ensure new products can be hotspotted inside the link. Then, we place an H3 tag with the name of the product, and again, link it to the product itself.

Next, we have to deal with the price block. Add the following just after the closing h3:

		
<div class="content_price">

    {if isset($product.show_price) &amp;&amp; $product.show_price &amp;&amp; !isset($restricted_country_mode)}<span class="price" style="display: inline;">{if !$priceDisplay}{convertPrice price=$product.price}{else}{convertPrice price=$product.price_tax_exc}{/if}</span><br />{/if}
				{if isset($product.available_for_order) &amp;&amp; $product.available_for_order &amp;&amp; !isset($restricted_country_mode)}<span class="availability">{if ($product.allow_oosp || $product.quantity > 0)}{l s='Available'}{elseif (isset($product.quantity_all_versions) &amp;&amp; $product.quantity_all_versions > 0)}{l s='Product available with different options'}{else}{l s='Out of stock'}{/if}</span>{/if}
</div>

Inside this last div, we can also place some text to let customers know if a product is on sale, or has a reduced price. If none of this situations is true, we just add an empty span to fill the space and give a uniform height to the elements:

{if isset($product.on_sale) &amp;&amp; $product.on_sale &amp;&amp; isset($product.show_price) &amp;&amp; $product.show_price &amp;&amp; !$PS_CATALOG_MODE}<span class="on_sale">{l s='On sale!'}</span>
				{elseif isset($product.reduction) &amp;&amp; $product.reduction &amp;&amp; isset($product.show_price) &amp;&amp; $product.show_price &amp;&amp; !$PS_CATALOG_MODE}<span class="discount">{l s='Reduced price!'}</span>
				{else}
				<span style="height:16px; margin: 5px 0; display: block"></span>
{/if}

Finally, we can add the “add to cart” button (again, inside the same content_prices div):

			{if ($product.id_product_attribute == 0 || (isset($add_prod_display) &amp;&amp; ($add_prod_display == 1))) &amp;&amp; $product.available_for_order &amp;&amp; !isset($restricted_country_mode) &amp;&amp; $product.minimal_quantity <= 1 &amp;&amp; $product.customizable != 2 &amp;&amp; !$PS_CATALOG_MODE}

					{if ($product.allow_oosp || $product.quantity > 0)}
						{if isset($static_token)}
							<a class="button ajax_add_to_cart_button exclusive" rel="ajax_id_product_{$product.id_product|intval}" href="{$link->getPageLink('cart',false, NULL, "add&amp;id_product={$product.id_product|intval}&amp;token={$static_token}", true)}" title="{l s='Add to cart'}"><span></span>{l s='Add to cart'}</a>
						{else}
							<a class="button ajax_add_to_cart_button exclusive" rel="ajax_id_product_{$product.id_product|intval}" href="{$link->getPageLink('cart',false, NULL, "add&amp;id_product={$product.id_product|intval}", true)}" title="{l s='Add to cart'}"><span></span>{l s='Add to cart'}</a>
						{/if}						
					{else}
						<span class="exclusive"><span></span>{l s='Add to cart'}</span><br />
					{/if}
				{/if}

 

The list is already finished, and you can jump to the next section at this point. However, if you need a further feature, you can add the comparator link. As before, in the same div.

{if isset($comparator_max_item) &amp;&amp; $comparator_max_item}
				<p class="compare">
					<input type="checkbox" class="comparator" id="comparator_item_{$product.id_product}" value="comparator_item_{$product.id_product}" {if isset($compareProducts) &amp;&amp; in_array($product.id_product, $compareProducts)}checked="checked"{/if} /> 
					<label for="comparator_item_{$product.id_product}">{l s='Select to compare'}</label>
				</p>
{/if}

And that’s it! Now, reload a category page, it should look more or less like this (yes, all screwed!):

Prestashop template screwed

The Stylesheet

Now that the html part is done, the only thing left is the CSS. Open up product_list.css that you cleared before, and start by adding the following code:

ul#product_list {
	list-style-type: none
}
#product_list li {
	text-align: center;
	float: left;
	width: 142px;
	padding: 16px;
	margin-bottom: 14px;
	margin-right: 20px;
	background-color: #f9f9f9
}
#product_list li.last_row_item {margin-right: 0;}

Explanation: first, we remove the list bullets, since we won’t need those, and then setup the style for each list item. Note that the width is calculated based on 4 products per row, and you’ll have to do some math to adjust it to other numbers. The last style is to remove the margin from each last element in a row. If we didn’t do this, the element would just fall to the next line.

If you are experiencing uneven height issues, add a fixed height to #product_list li.

Now, let’s style the image and give a basic color to links

#product_list li a {
	color: #374853;
	text-decoration: none
}
#product_list a.product_img_link {
	overflow:hidden;
	position:relative;
	float: left;
	display:block;
	border: 1px solid #ccc
}
#product_list a.product_img_link img {
	display: block;
	vertical-align: bottom
}

It is important to set the position of a.product_img_link as relative since we will be adding the “new product” label over it, absolutely positioned.

#product_list li span.new {
	display: block;
	position: absolute;
	top: 15px;
	right:-30px;
	padding: 1px 4px;
	width: 101px;
	font-size:10px;
	color: #fff;
	text-align: center;
	text-transform: uppercase;
	-moz-transform: rotate(45deg);
	-webkit-transform: rotate(45deg);
	-o-transform:rotate(45deg);
	-ms-transform: rotate(45deg);
	background-color: #990000
}

 

Then, it’s time for product data. Note that I’m hiding the “availability” label, since i don’t need it.

#product_list li h3 {
	padding:0 0 10px 0;
	font-size:13px;
	color:#000
}

#product_list li p.product_desc {
	overflow: hidden;
	padding:0;
	line-height:16px;
}
#product_list li p.product_desc,
#product_list li p.product_desc a {
	color:#666;
}

#product_list li .discount, ul#product_list li .on_sale, ul#product_list li .online_only {
	display: block;
	font-weight: bold;
	margin: 5px 0;
	padding: 1px 5px;
	color: #990000;
	text-transform: uppercase
}
#product_list li .discount {
	display: inline-block;
	font-size: 10px;
	color: #fff;
	background: none repeat scroll 0 0 #9B0000
}

#product_list li .content_price {
	width: 142px;
	float: left;
}
#product_list li .price {
	display: block;
	padding-bottom: 15px;
	font-weight:bold;
	font-size: 16px;
	color:#990000
}
#product_list li span.availability {
	display:none; /* remove to show availability */
	color: #488C40
}

 

Finally, the “Add to cart” button and the optional compare checkbox

#product_list li .ajax_add_to_cart_button {
	padding-left: 20px
}
#product_list li .ajax_add_to_cart_button span {
	display: block;
	position: absolute;
	top: -1px;
	left: -12px;
	height: 26px;
	width: 26px;
	background: url(../img/icon/pict_add_cart.png) no-repeat 0 0 transparent
}
#product_list li p.compare {padding-bottom: 0;margin-top: 10px;}

 

Save and refresh the page. It should now look like this. If it doesn’t go back and check that your code matches. You can always download the project files to copy directly from there.

Grid display for Prestashop 1.5 default theme

Final Sources

product-list.tpl

Notice: For some reason, the plugin I use to highlight te code changes line 34. Be sure you download the project files and replace that line with the correct img tag, or remove the “if” part (you can also fix it if you know smarty!).

{*
* 2007-2012 PrestaShop
*
* NOTICE OF LICENSE
*
* This source file is subject to the Academic Free License (AFL 3.0)
* that is bundled with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://opensource.org/licenses/afl-3.0.php
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to http://www.prestashop.com for more information.
*
*  @author PrestaShop SA
*  @copyright  2007-2012 PrestaShop SA
*  @version  Release: $Revision: 7457 $
*  @license    http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
*  International Registered Trademark & Property of PrestaShop SA
*}
 
{if isset($products)}

    <ul id="product_list" class="clearfix">
    {foreach from=$products item=product name=products}

	<li class="ajax_block_product {if $smarty.foreach.products.first}first_item{elseif $smarty.foreach.products.last}last_item{/if} {if $smarty.foreach.products.iteration%4 == 0}last_row_item{else}item{/if}">
	    <a href="{$product.link|escape:'htmlall':'UTF-8'}" class="product_img_link" title="{$product.name|escape:'htmlall':'UTF-8'}">
	       <img src="{$link->getImageLink($product.link_rewrite, $product.id_image, 'home')}" alt="{$product.legend|escape:'htmlall':'UTF-8'}" {if isset($homeSize)} width="{$homeSize.width}" height="{$homeSize.height}"{/if} /> 
	        {if isset($product.new) && $product.new == 1}<span class="new">{l s='New'}</span>{/if}
	    </a>
	    <p class="clear"></p>
	    <h3><a href="{$product.link|escape:'htmlall':'UTF-8'}" title="{$product.name|escape:'htmlall':'UTF-8'}">{$product.name|escape:'htmlall':'UTF-8'|truncate:26:'...':true}</a></h3>
		<div class="content_price">
		 
		    {if isset($product.show_price) && $product.show_price && !isset($restricted_country_mode)}<span class="price" style="display: inline;">{if !$priceDisplay}{convertPrice price=$product.price}{else}{convertPrice price=$product.price_tax_exc}{/if}</span><br />{/if}
		                {if isset($product.available_for_order) && $product.available_for_order && !isset($restricted_country_mode)}<span class="availability">{if ($product.allow_oosp || $product.quantity > 0)}{l s='Available'}{elseif (isset($product.quantity_all_versions) && $product.quantity_all_versions > 0)}{l s='Product available with different options'}{else}{l s='Out of stock'}{/if}</span>{/if}


			{if isset($product.on_sale) && $product.on_sale && isset($product.show_price) && $product.show_price && !$PS_CATALOG_MODE}<span class="on_sale">{l s='On sale!'}</span>
			                {elseif isset($product.reduction) && $product.reduction && isset($product.show_price) && $product.show_price && !$PS_CATALOG_MODE}<span class="discount">{l s='Reduced price!'}</span>
			                {else}
			                <span style="height:16px; margin: 5px 0; display: block"></span>
			{/if}
			{if ($product.id_product_attribute == 0 || (isset($add_prod_display) && ($add_prod_display == 1))) && $product.available_for_order && !isset($restricted_country_mode) && $product.minimal_quantity <= 1 && $product.customizable != 2 && !$PS_CATALOG_MODE}
			 
			    {if ($product.allow_oosp || $product.quantity > 0)}
			        {if isset($static_token)}
			            <a class="button ajax_add_to_cart_button exclusive" rel="ajax_id_product_{$product.id_product|intval}" href="{$link->getPageLink('cart',false, NULL, "add&id_product={$product.id_product|intval}&token={$static_token}", true)}" title="{l s='Add to cart'}"><span></span>{l s='Add to cart'}</a>
			        {else}
			            <a class="button ajax_add_to_cart_button exclusive" rel="ajax_id_product_{$product.id_product|intval}" href="{$link->getPageLink('cart',false, NULL, "add&id_product={$product.id_product|intval}", true)}" title="{l s='Add to cart'}"><span></span>{l s='Add to cart'}</a>
			        {/if}                       
			    {else}
			        <span class="exclusive"><span></span>{l s='Add to cart'}</span><br />
			    {/if}
			{/if}
			{if isset($comparator_max_item) && $comparator_max_item}
                <p class="compare">
                    <input type="checkbox" class="comparator" id="comparator_item_{$product.id_product}" value="comparator_item_{$product.id_product}" {if isset($compareProducts) && in_array($product.id_product, $compareProducts)}checked="checked"{/if} /> 
                    <label for="comparator_item_{$product.id_product}">{l s='Select to compare'}</label>
                </p>
			{/if}		
		</div>

	 
	</li>

    {/foreach}
    </ul>

{/if}	

 

product_list.css

ul#product_list {
	list-style-type: none
}
	#product_list li {
		text-align: center;
		float: left;
		width: 142px;
		padding: 16px;
		margin-bottom: 14px;
		margin-right: 20px;
		background-color: #f9f9f9
	}
	#product_list li.last_row_item {margin-right: 0;}

	#product_list li a {
		color: #374853;
		text-decoration: none
	}
	#product_list a.product_img_link {
	overflow:hidden;
	position:relative;
	float: left;
	display:block;
	border: 1px solid #ccc
	}
	#product_list a.product_img_link img {
		display: block;
		vertical-align: bottom
	}

	#product_list li span.new {
		display: block;
		position: absolute;
		top: 15px;
		right:-30px;
		padding: 1px 4px;
		width: 101px;
		font-size:10px;
		color: #fff;
		text-align: center;
		text-transform: uppercase;
		-moz-transform: rotate(45deg);
		-webkit-transform: rotate(45deg);
		-o-transform:rotate(45deg);
		-ms-transform: rotate(45deg);
		background-color: #990000
	}
	#product_list li h3 {
		padding:0 0 10px 0;
		font-size:13px;
		color:#000
	}

	#product_list li p.product_desc {
		overflow: hidden;
		padding:0;
		line-height:16px;
	}
	#product_list li p.product_desc,
	#product_list li p.product_desc a {
		color:#666;
	}

	#product_list li .discount, ul#product_list li .on_sale, ul#product_list li .online_only {
		display: block;
		font-weight: bold;
		margin: 5px 0;
		padding: 1px 5px;
		color: #990000;
		text-transform: uppercase
	}
	#product_list li .discount {
		display: inline-block;
		font-size: 10px;
		color: #fff;
		background: none repeat scroll 0 0 #9B0000
	}

	#product_list li .content_price {
		width: 142px;
		float: left;
	}
		#product_list li .price {
			display: block;
			padding-bottom: 15px;
			font-weight:bold;
			font-size: 16px;
			color:#990000
		}
		#product_list li span.availability {
			display:none; /* remove to show availability */
			color: #488C40
		}
	#product_list li .ajax_add_to_cart_button {
		padding-left: 20px
	}
	#product_list li .ajax_add_to_cart_button span {
		display: block;
		position: absolute;
		top: -1px;
		left: -12px;
		height: 26px;
		width: 26px;
		background: url(../img/icon/pict_add_cart.png) no-repeat 0 0 transparent
	}
	#product_list li p.compare {padding-bottom: 0;margin-top: 10px;}

Conclusion

And that’s it! You should now have a clean grid display for your Prestashop theme, and be able to set up a new one with your own dimensions in the future.

You like the tuts and want to say "thank you"? Well, you can always feel free to donate:

  • reza

    thank you for this tutorial.
    but I’ve problem after changing this codes, with modules same as new product at home or featured product at home.
    they didn’t show.
    how I can resolve this problem?
    my version is : 1.5.6.2.

    Thank you

  • http://www.tjek-internetpriser.dk Aviator Bobo

    Thanks a million to Nemo for this tutorial.. And loads of thanks to you guys who have commented solutions to problems! :) I did this category with you guys help… http://Dragebyen.dk

    Now I only need to fix the middle of the category… The seems to be a empty space, for some reason? :) Will play with the css-code to figure it out I guess… :)

  • Alex

    How can i resize the photo’s in the product list? I have now four in a row. But the photo’s goes outside (the size) of the box end has a overlap.

    Alex

  • Alex

    I don’t know why you have “&&” in your fractionated tutorial and not “&&”, as in the complete file. It gives an error.

  • Detlev Langras

    I’ve got a problem! Everytime i try to change the code in the CSS and TPL file my category page turns out blank. I have P.S. 1.5.6.1 and i used the home_default option. Could someone help me?

  • LL

    Hi Nemo, how can I use this for the “Featured Products” in the main page? Thank you.

  • http://radiantbarriers.com RedShark

    Great job! I followed the tutorial and missed a step but just went back and did a copy/paste. When I did that it worked great. I had to make some minor adjustments as I have re-sized my default images. No prob! A little css tweak and it worked perfect. Thanks again!

  • al

    Hi there!

    Great tut, thanks!

    Removed right column, everything is fine, except:
    – the category block content disappears when set to Dynamic
    – the subcategories block is still in list mode, how do i turn it to grid mode as well?

    Thanks again!

  • http://www.pauazap.com Kehos

    Thanks for the help, this was very useful to me!

    I have to say that my products don’t show their images, but I’m sure it’s a mistake I did. All worked perfectly but that, really thanks another time!

    • Pg

      I have the same problem of Kehos

      Products in grid, but no images preview :(

      Please….any help ?

      • sarin

        Please edit this line

        getImageLink($product.link_rewrite, $product.id_image, ‘home’)}

        and change it to

        getImageLink($product.link_rewrite, $product.id_image, ‘home_default’)}
        you should be able to view images after that

You like the tuts and want to say "thank you"? Well, you can always feel free to donate: