This is tutorial for PrestShop 1.5.x, if you're looking for solution for PrestaShop 1.7.x you can find it here:
In this article I want to show you how to create grid / list / mini list switcher for PrestaShop products view in each category page in your store.This guide doesn't use any core modification. All changes that we will make are related to theme and javascripts. We will edit files:
example of grid / list / mini list switcher for prestashop products view
see it live! prestashop grid / list switcher
Grid view for preoducts click to enlarge |
List view for products click to enlarge |
click to enlarge |
How everything works? After clicking on button we will change ID of <ul> object in product-list.tpl file, depending on this ID browser will use different styles to display products in selected format (grid, list, mini-list). Buttons in switcher will create also cookie to remember which view type was selected.... and thats all :)
Step 1: adding switcher buttons
For the first you must download switching buttons. then upload them to your theme directory /img/mypresta/ directory. If you don't have this directory, just create it and upload files there.
Then open your theme product-sort.tpl file, move your cursor to the end of the file. Right before code <!-- /Sort products --> add buttons code. I created main <div> object with class buttons_switcher, inside this <div> i placed three <span> elements, each element is a button (grid, list, minilist)
<div class="buttons_switcher"> <span class="button_grid"></span> <span class="button_list"></span> <span class="button_minilist"></span> </div>
Step 2: changing product-list.tpl code
Now it's time to modify product-list.tpl file. This file displaying list of products. We must add there several lines of new code. This code will create correct ID of <ul> object depending on selected view method. Contents of product-list.tpl file below. Just copy code to your file.
{if isset($products)} <!-- Products list --> <ul id="product_list{if isset($smarty.cookies.switchercookie) && $smarty.cookies.switchercookie=="grid"}_grid{/if}{if (isset($smarty.cookies.switchercookie) &&$smarty.cookies.switchercookie=="list") OR !isset($smarty.cookies.switchercookies)}{/if}{if isset($smarty.cookies.switchercookie) &&$smarty.cookies.switchercookie=="minilist"}_mini{/if}" class="clear prdlist"> {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.index % 2}alternate_item{else}item{/if} clearfix"> <div class="left_block"> {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} autocomplete="off"/> <label for="comparator_item_{$product.id_product}">{l s='Select to compare'}</label> </p> {/if} </div> <div class="center_block"> <a href="{$product.link|escape:'htmlall':'UTF-8'}" class="product_img_link" title="{$product.name|escape:'htmlall':'UTF-8'}"> {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>{/if} <img src="{$link->getImageLink($product.link_rewrite, $product.id_image, 'home_default')|escape:'html'}" 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> <h3>{if isset($product.new) && $product.new == 1}<span class="new">{l s='New'}</span>{/if} {if isset($product.pack_quantity) && $product.pack_quantity}{$product.pack_quantity|intval|cat:' x '}{/if}<a href="{$product.link|escape:'htmlall':'UTF-8'}" title="{$product.name|escape:'htmlall':'UTF-8'}">{$product.name|truncate:35:'...'|escape:'htmlall':'UTF-8'}</a></h3> <p class="product_desc"><a href="{$product.link|escape:'htmlall':'UTF-8'}" title="{$product.description_short|strip_tags:'UTF-8'|truncate:360:'...'}" >{$product.description_short|strip_tags:'UTF-8'|truncate:360:'...'}</a></p> </div> <div class="right_block"> {if (!$PS_CATALOG_MODE AND ((isset($product.show_price) && $product.show_price) || (isset($product.available_for_order) && $product.available_for_order)))} <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}<span class="warning_inline">{l s='Out of stock'}</span>{/if}</span>{/if} </div> {if isset($smarty.cookies.switchercookie) &&$smarty.cookies.switchercookie=="minilist"} <div class="minilist-badges"> {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>{/if} </div> {/if} {/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=1&id_product={$product.id_product|intval}&token={$static_token}", false)|escape:'html'}" 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=1&id_product={$product.id_product|intval}", false)|escape:'html'}" 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} <a class="button lnk_view" href="{$product.link|escape:'htmlall':'UTF-8'}" title="{l s='View'}">{l s='View'}</a> </div> </li> {/foreach} </ul> <!-- /Products list --> {/if}
Step 3: CSS styles for our new .tpl file
Now it's time to create CSS styles for new template file. I modified original product_list.css file. I added there 3 new types of product lists. Each of the type (grid, list, mini-list) have got own styles. You can change styles for each of them. Full code of changes below. Just copy styles pand paste them to your product_list.css file located in your theme /css/ directory.
/** PRODUCT LIST **/ #product_list .minilist-badges {display:none;} ul#product_list { list-style-type: none } #product_list li h3 span.new { display:none!important; } #product_list li { margin-bottom: 14px; padding: 12px 8px; border: 1px solid #eee; -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px } #product_list li a { color: #374853; text-decoration: none } #product_list li .left_block { float:left; padding-top:58px; width:15px } #product_list li .left_block .compare label {display:none;} #product_list li p.compare input { vertical-align: text-bottom } #product_list li .center_block { float: left; padding:0 7px; width: 342px;/* 356 */ border-right:1px dotted #ccc } #product_list a.product_img_link { overflow:hidden; position:relative; float: left; display:block; margin-right: 14px; 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); background-color: #990000; transform: rotate(45deg); -ms-transform: rotate(45deg); /* Newer browsers */ } .ie8 #product_list li span.new{top:111px;right:0;width:94%} .ie7 #product_list li span.new {top:111px;right:0;width:94%} #product_list li h3 { padding:0 0 10px 0; font-size:13px; color:#000 } #product_list li a { color: #000; text-decoration: none; } #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 .right_block { position:relative; float: left; width: 145px; text-align: right } #product_list li .discount, ul#product_list li .on_sale, ul#product_list li .online_only { display: block; font-weight: bold; color: #990000; text-transform: uppercase; position:absolute; background:red; color:#FFF; padding:2px 5px; bottom:0px; left:0px; } #product_list li .online_only { margin:0 0 10px 0 } #product_list li .content_price { margin:26px 0 15px 0; } #product_list li .price { display: block; margin-bottom: 15px; font-weight:bold; font-size: 18px; color:#990000 } #product_list li span.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 .lnk_view { display: block; margin-top:15px; padding:0 10px; border:none; font-weight:bold; color:#0088CC; background:url(../img/arrow_right_1.png) no-repeat 100% 4px transparent } #product_list li .lnk_view:hover {text-decoration:underline} /** PRODUCT GRID **/ #product_list_grid li h3 span.new { display:none!important; } #product_list_grid .minilist-badges {display:none;} ul#product_list_grid { list-style-type: none; vertical-align:top; display:block; clear:both; } #product_list_grid li { overflow:hidden; margin-bottom: 14px; padding: 10px; border: 1px solid #eee; -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; display:inline-block; width:153px; height:270px; } #product_list_grid li a { color: #374853; text-decoration: none } #product_list_grid .left_block { display:block; clear:both; overflow:hidden; height:20px; text-align:center; margin-top:10px; } #product_list_grid li p.compare input { vertical-align: text-bottom } #product_list_grid li .center_block { width: 100%; display:block; text-align:center; } #product_list_grid a.product_img_link { overflow:hidden; display:block; border: 1px solid #ccc; margin:auto; display:block; width:126px; clear:both; position:relative; } #product_list_grid a.product_img_link img { display: block; vertical-align: bottom } #product_list_grid 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); background-color: #990000; transform: rotate(45deg); -ms-transform: rotate(45deg); /* Newer browsers */ } .ie8 #product_list_grid li span.new{top:111px;right:0;width:94%} .ie7 #product_list_grid li span.new {top:111px;right:0;width:94%} #product_list_grid li h3 { padding:5px; font-size:13px; color:#000; display:block; text-align:center; } #product_list_grid li a { color: #000; text-decoration: none; } #product_list_grid li p.product_desc { overflow: hidden; padding:0; line-height:16px; display:none; } #product_list_grid li p.product_desc, #product_list_grid li p.product_desc a { color:#666; } #product_list_grid li .right_block { width: 153px; text-align:center; margin-top:5px; margin-bottom:5px; } #product_list_grid li .discount , #product_list_grid li .discount, ul#product_list_grid li .on_sale, ul#product_list_grid li .online_only { display: block; font-weight: bold; color: #990000; text-transform: uppercase; position:absolute; background:red; color:#FFF; padding:2px 5px; bottom:0px; left:0px; } #product_list_grid li .online_only { margin:0 0 10px 0 } #product_list_grid li .content_price { } #product_list_grid li .price { display: block; margin-bottom: 15px; font-weight:bold; font-size: 18px; color:#990000 } #product_list_grid li span.availability { color: #488C40 } #product_list_grid 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; display:none; } #product_list_grid li .lnk_view { display: block; margin-top:15px; padding:0 10px; border:none; font-weight:bold; color:#0088CC; background:url(../img/arrow_right_1.png) no-repeat 100% 4px transparent; display:none; } #product_list_grid li .lnk_view:hover {text-decoration:underline} /** PRODUCT LIST MINI **/ #product_list_mini .minilist-badges { text-align: center; position: relative; float: left; margin-left: 10px; width: 120px; display: block; } ul#product_list_mini { list-style-type: none } #product_list_mini li { padding: 15px 8px; border: 1px solid #eee; -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; border-bottom:none!important; } #product_list_mini li a { color: #374853; text-decoration: none } #product_list_mini li .left_block { float:left; width:15px } #product_list_mini li .left_block .compare label {display:none;} #product_list_mini li p.compare input { vertical-align: text-bottom } #product_list_mini li .center_block { float: left; padding:0 7px; width: 202px;/* 356 */ } #product_list_mini a.product_img_link { overflow:hidden; position:relative; float: left; display:block; margin-right: 14px; border: 1px solid #ccc; display:none; } #product_list_mini a.product_img_link img { display: block; vertical-align: bottom } .ie8 #product_list_mini li span.new{top:111px;right:0;width:94%} .ie7 #product_list_mini li span.new {top:111px;right:0;width:94%} #product_list_mini li h3 { padding:0 0 10px 0; font-size:12px; color:#000; display:inline-block; float:left; position:relative; } #product_list_mini li h3 span.new { display:inline-block!important; position:relative!important; margin-right:1px; } #product_list_mini li a { color: #000; text-decoration: none; } #product_list_mini li p.product_desc { overflow: hidden; padding:0; line-height:16px; display:none; } #product_list_mini li p.product_desc, #product_list_mini li p.product_desc a { color:#666; } #product_list_mini li .right_block { position:relative; float: left; width: 285px; text-align: right } #product_list_mini li span.discount ,#product_list_mini li span.new , #product_list_mini li .discount, ul#product_list_mini li .on_sale, ul#product_list_mini li .online_only { display: block; font-weight: bold; text-transform: uppercase; position:absolute; left:0px; top:0px; background:red; color:white; padding: 2px 5px; font-size:10px; } #product_list_mini li .discount { margin-right: 20px; display: inline-block; font-weight: bold; padding: 1px 5px; font-size: 10px; color: #fff; text-transform: uppercase; background: none repeat scroll 0 0 #9B0000 } #product_list_mini li .online_only { margin:0 0 10px 0 } #product_list_mini li .content_price { display:inline-block; float:left; } #product_list_mini li .price { display: block; margin-bottom: 15px; font-weight:bold; font-size: 18px; color:#990000 } #product_list_mini li span.availability { color: #488C40 } #product_list_mini li .right_block .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; display:none; } #product_list_mini li .lnk_view { display: block; margin-top:15px; padding:0 10px; border:none; font-weight:bold; color:#0088CC; background:url(../img/arrow_right_1.png) no-repeat 100% 4px transparent; display:none; } #product_list_mini li .lnk_view:hover {text-decoration:underline} /** MYPRESTA.EU CODE FOR GRID/LIST/MINILIST SWITCHER **/ .buttons_switcher { position:relative; display:inline-block; float:right; margin-right:20px;} .button_grid { cursor:pointer; margin:auto; padding:0px; display:inline-block; width:19px; height:19px; background:url(../img/mypresta/button_grid.png) no-repeat top left;} .button_list { cursor:pointer; margin:auto; padding:0px; display:inline-block; width:19px; height:19px; background:url(../img/mypresta/button_list.png) no-repeat top left;} .button_minilist { cursor:pointer; margin:auto; padding:0px; display:inline-block; width:19px; height:19px; background:url(../img/mypresta/button_minilist.png) no-repeat top left;}
Step 4: Script for switcher
Now it's time to create javascript for our buttons created in product-sort.tpl file. Where to insert javascript? you can add script direct to your product-list.tpl file (remember about {literal} {/literal} tags!) or just for tools.js file located in directory: /js/tools.js. Just copy and paste code below:
/** MYPRESTA GRID/LIST/MINILIST SWITCHER **/ $(document).ready(function() { /*! * jQuery Cookie Plugin v1.4.0 * https://github.com/carhartl/jquery-cookie * * Copyright 2013 Klaus Hartl * Released under the MIT license */ (function (factory) { if (typeof define === 'function' && define.amd) { // AMD. Register as anonymous module. define(['jquery'], factory); } else { // Browser globals. factory(jQuery); } }(function ($) { var pluses = /\+/g; function encode(s) { return config.raw ? s : encodeURIComponent(s); } function decode(s) { return config.raw ? s : decodeURIComponent(s); } function stringifyCookieValue(value) { return encode(config.json ? JSON.stringify(value) : String(value)); } function parseCookieValue(s) { if (s.indexOf('"') === 0) { // This is a quoted cookie as according to RFC2068, unescape... s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\'); } try { // Replace server-side written pluses with spaces. // If we can't decode the cookie, ignore it, it's unusable. // If we can't parse the cookie, ignore it, it's unusable. s = decodeURIComponent(s.replace(pluses, ' ')); return config.json ? JSON.parse(s) : s; } catch(e) {} } function read(s, converter) { var value = config.raw ? s : parseCookieValue(s); return $.isFunction(converter) ? converter(value) : value; } var config = $.cookie = function (key, value, options) { // Write if (value !== undefined && !$.isFunction(value)) { options = $.extend({}, config.defaults, options); if (typeof options.expires === 'number') { var days = options.expires, t = options.expires = new Date(); t.setDate(t.getDate() + days); } return (document.cookie = [ encode(key), '=', stringifyCookieValue(value), options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE options.path ? '; path=' + options.path : '', options.domain ? '; domain=' + options.domain : '', options.secure ? '; secure' : '' ].join('')); } // Read var result = key ? undefined : {}; // To prevent the for loop in the first place assign an empty array // in case there are no cookies at all. Also prevents odd result when // calling $.cookie(). var cookies = document.cookie ? document.cookie.split('; ') : []; for (var i = 0, l = cookies.length; i < l; i++) { var parts = cookies[i].split('='); var name = decode(parts.shift()); var cookie = parts.join('='); if (key && key === name) { // If second argument (value) is a function it's a converter... result = read(cookie, value); break; } // Prevent storing a cookie that we couldn't decode. if (!key && (cookie = read(cookie)) !== undefined) { result[name] = cookie; } } return result; }; config.defaults = {}; $.removeCookie = function (key, options) { if ($.cookie(key) === undefined) { return false; } // Must not alter options, thus extending a fresh object... $.cookie(key, '', $.extend({}, options, { expires: -1 })); return !$.cookie(key); }; })); $(".button_grid").click(function() { $.cookie("switchercookie", "grid"); $(".prdlist").attr("id","product_list_grid"); }); $(".button_list").click(function() { $.cookie("switchercookie", "list"); $(".prdlist").attr("id","product_list"); }); $(".button_minilist").click(function() { $.cookie("switchercookie", "minilist"); $(".prdlist").attr("id","product_list_mini"); }); });
We are done
you can check demo of this list / grid switcher here: prestashop grid / list switcher