Blog

Real Tabs for Prestashop 1.6 with Custom Product Tabs

You enjoyed the real tabs available in Prestashop 1.5? Would you like to keep them in Prestashop 1.6? We thought you might, because as developers, we had exactly the same thoughts and needs. So, we decided to add the respective option in Custom Product Tabs module.

First, you have to go to the options page of Custom Product Tabs and switch to the real tabs display.

Then, you have to make the following changes in the default theme template files. We strongly advise you to keep a backup of all the files that you are going to edit, in case you need to switch back to the initial default layout!

 

Go to product.tpl file located in the default theme’s folder.

Locate the following code:

{if isset($features) && $features}
        <!-- Data sheet -->
        <section class="page-product-box">
            <h3 class="page-product-heading">{l s='Data sheet'}</h3>
            <table class="table-data-sheet">
                {foreach from=$features item=feature}
                <tr class="{cycle values="odd,even"}">
                    {if isset($feature.value)}
                    <td>{$feature.name|escape:'html':'UTF-8'}</td>
                    <td>{$feature.value|escape:'html':'UTF-8'}</td>
                    {/if}
                </tr>
                {/foreach}
            </table>
        </section>
        <!--end Data sheet -->
    {/if}
    {if isset($product) && $product->description}
        <!-- More info -->
        <section class="page-product-box">
            <h3 class="page-product-heading">{l s='More info'}</h3>
            <!-- full description -->
            <div  class="rte">{$product->description}</div>
        </section>
        <!--end  More info -->
    {/if}
    {if isset($packItems) && $packItems|@count > 0}
    <section id="blockpack">
        <h3 class="page-product-heading">{l s='Pack content'}</h3>
        {include file="$tpl_dir./product-list.tpl" products=$packItems}
    </section>
    {/if}
    <!--HOOK_PRODUCT_TAB -->
    <section class="page-product-box">
        {$HOOK_PRODUCT_TAB}
        {if isset($HOOK_PRODUCT_TAB_CONTENT) && $HOOK_PRODUCT_TAB_CONTENT}{$HOOK_PRODUCT_TAB_CONTENT}{/if}
    </section>
    <!--end HOOK_PRODUCT_TAB -->
    {if isset($accessories) && $accessories}
        <!--Accessories -->
        <section class="page-product-box">
            <h3 class="page-product-heading">{l s='Accessories'}</h3>
            <div class="block products_block accessories-block clearfix">
                <div class="block_content">
                    <ul id="bxslider" class="bxslider clearfix">
                        {foreach from=$accessories item=accessory name=accessories_list}
                            {if ($accessory.allow_oosp || $accessory.quantity_all_versions > 0 || $accessory.quantity > 0) && $accessory.available_for_order && !isset($restricted_country_mode)}
                                {assign var='accessoryLink' value=$link->getProductLink($accessory.id_product, $accessory.link_rewrite, $accessory.category)}
                                <li class="item product-box ajax_block_product{if $smarty.foreach.accessories_list.first} first_item{elseif $smarty.foreach.accessories_list.last} last_item{else} item{/if} product_accessories_description">
                                    <div class="product_desc">
                                        <a href="{$accessoryLink|escape:'html':'UTF-8'}" title="{$accessory.legend|escape:'html':'UTF-8'}" class="product-image product_image">
                                            <img class="lazyOwl" src="{$link->getImageLink($accessory.link_rewrite, $accessory.id_image, 'home_default')|escape:'html':'UTF-8'}" alt="{$accessory.legend|escape:'html':'UTF-8'}" width="{$homeSize.width}" height="{$homeSize.height}"/>
                                        </a>
                                        <div class="block_description">
                                            <a href="{$accessoryLink|escape:'html':'UTF-8'}" title="{l s='More'}" class="product_description">
                                                {$accessory.description_short|strip_tags|truncate:25:'...'}
                                            </a>
                                        </div>
                                    </div>
                                    <div class="s_title_block">
                                        <h5 itemprop="name" class="product-name">
                                            <a href="{$accessoryLink|escape:'html':'UTF-8'}">
                                                {$accessory.name|truncate:20:'...':true|escape:'html':'UTF-8'}
                                            </a>
                                        </h5>
                                        {if $accessory.show_price && !isset($restricted_country_mode) && !$PS_CATALOG_MODE}
                                        <span class="price">
                                            {if $priceDisplay != 1}
                                            {displayWtPrice p=$accessory.price}{else}{displayWtPrice p=$accessory.price_tax_exc}
                                            {/if}
                                        </span>
                                        {/if}
                                    </div>
                                    <div class="clearfix" style="margin-top:5px">
                                        {if !$PS_CATALOG_MODE && ($accessory.allow_oosp || $accessory.quantity > 0)}
                                            <div class="no-print">
                                                <a class="exclusive button ajax_add_to_cart_button" href="{$link->getPageLink('cart', true, NULL, "qty=1&amp;id_product={$accessory.id_product|intval}&amp;token={$static_token}&amp;add")|escape:'html':'UTF-8'}" data-id-product="{$accessory.id_product|intval}" title="{l s='Add to cart'}">
                                                    <span>{l s='Add to cart'}</span>
                                                </a>
                                            </div>
                                        {/if}
                                    </div>
                                </li>
                            {/if}
                        {/foreach}
                    </ul>
                </div>
            </div>
        </section>
        <!--end Accessories -->
    {/if}
    {if isset($HOOK_PRODUCT_FOOTER) && $HOOK_PRODUCT_FOOTER}{$HOOK_PRODUCT_FOOTER}{/if}
    <!-- description & features -->
    {if (isset($product) && $product->description) || (isset($features) && $features) || (isset($accessories) && $accessories) || (isset($HOOK_PRODUCT_TAB) && $HOOK_PRODUCT_TAB) || (isset($attachments) && $attachments) || isset($product) && $product->customizable}
        {if isset($attachments) && $attachments}
        <!--Download -->
        <section class="page-product-box">
            <h3 class="page-product-heading">{l s='Download'}</h3>
            {foreach from=$attachments item=attachment name=attachements}
                {if $smarty.foreach.attachements.iteration %3 == 1}<div class="row">{/if}
                    <div class="col-lg-4">
                        <h4><a href="{$link->getPageLink('attachment', true, NULL, "id_attachment={$attachment.id_attachment}")|escape:'html':'UTF-8'}">{$attachment.name|escape:'html':'UTF-8'}</a></h4>
                        <p class="text-muted">{$attachment.description|escape:'html':'UTF-8'}</p>
                        <a class="btn btn-default btn-block" href="{$link->getPageLink('attachment', true, NULL, "id_attachment={$attachment.id_attachment}")|escape:'html':'UTF-8'}">
                            <i class="icon-download"></i>
                            {l s="Download"} ({Tools::formatBytes($attachment.file_size, 2)})
                        </a>
                        <hr />
                    </div>
                {if $smarty.foreach.attachements.iteration %3 == 0 || $smarty.foreach.attachements.last}</div>{/if}
            {/foreach}
        </section>
        <!--end Download -->
        {/if}
        {if isset($product) && $product->customizable}
        <!--Customization -->
        <section class="page-product-box">
            <h3 class="page-product-heading">{l s='Product customization'}</h3>
            <!-- Customizable products -->
            <form method="post" action="{$customizationFormTarget}" enctype="multipart/form-data" id="customizationForm" class="clearfix">
                <p class="infoCustomizable">
                    {l s='After saving your customized product, remember to add it to your cart.'}
                    {if $product->uploadable_files}
                    <br />
                    {l s='Allowed file formats are: GIF, JPG, PNG'}{/if}
                </p>
                {if $product->uploadable_files|intval}
                    <div class="customizableProductsFile">
                        <h5 class="product-heading-h5">{l s='Pictures'}</h5>
                        <ul id="uploadable_files" class="clearfix">
                            {counter start=0 assign='customizationField'}
                            {foreach from=$customizationFields item='field' name='customizationFields'}
                                {if $field.type == 0}
                                    <li class="customizationUploadLine{if $field.required} required{/if}">{assign var='key' value='pictures_'|cat:$product->id|cat:'_'|cat:$field.id_customization_field}
                                        {if isset($pictures.$key)}
                                            <div class="customizationUploadBrowse">
                                                <img src="{$pic_dir}{$pictures.$key}_small" alt="" />
                                                    <a href="{$link->getProductDeletePictureLink($product, $field.id_customization_field)|escape:'html':'UTF-8'}" title="{l s='Delete'}" >
                                                        <img src="{$img_dir}icon/delete.gif" alt="{l s='Delete'}" class="customization_delete_icon" width="11" height="13" />
                                                    </a>
                                            </div>
                                        {/if}
                                        <div class="customizationUploadBrowse form-group">
                                            <label class="customizationUploadBrowseDescription">
                                                {if !empty($field.name)}
                                                    {$field.name}
                                                {else}
                                                    {l s='Please select an image file from your computer'}
                                                {/if}
                                                {if $field.required}<sup>*</sup>{/if}
                                            </label>
                                            <input type="file" name="file{$field.id_customization_field}" id="img{$customizationField}" class="form-control customization_block_input {if isset($pictures.$key)}filled{/if}" />
                                        </div>
                                    </li>
                                    {counter}
                                {/if}
                            {/foreach}
                        </ul>
                    </div>
                {/if}
                {if $product->text_fields|intval}
                    <div class="customizableProductsText">
                        <h5 class="product-heading-h5">{l s='Text'}</h5>
                        <ul id="text_fields">
                        {counter start=0 assign='customizationField'}
                        {foreach from=$customizationFields item='field' name='customizationFields'}
                            {if $field.type == 1}
                                <li class="customizationUploadLine{if $field.required} required{/if}">
                                    <label for ="textField{$customizationField}">
                                        {assign var='key' value='textFields_'|cat:$product->id|cat:'_'|cat:$field.id_customization_field}
                                        {if !empty($field.name)}
                                            {$field.name}
                                        {/if}
                                        {if $field.required}<sup>*</sup>{/if}
                                    </label>
                                    <textarea name="textField{$field.id_customization_field}" class="form-control customization_block_input" id="textField{$customizationField}" rows="3" cols="20">{strip}
                                        {if isset($textFields.$key)}
                                            {$textFields.$key|stripslashes}
                                        {/if}
                                    {/strip}</textarea>
                                </li>
                                {counter}
                            {/if}
                        {/foreach}
                        </ul>
                    </div>
                {/if}
                <p id="customizedDatas">
                    <input type="hidden" name="quantityBackup" id="quantityBackup" value="" />
                    <input type="hidden" name="submitCustomizedDatas" value="1" />
                    <button class="button btn btn-default button button-small" name="saveCustomization">
                        <span>{l s='Save'}</span>
                    </button>
                    <span id="ajax-loader" class="unvisible">
                        <img src="{$img_ps_dir}loader.gif" alt="loader" />
                    </span>
                </p>
            </form>
            <p class="clear required"><sup>*</sup> {l s='required fields'}</p>
        </section>
        <!--end Customization -->
        {/if}
    {/if}
{/if}

For Prestashop 1.6.1.1 the above code is located in lines 463-666. For other Prestashop versions the line numbers might be slightly different.

Replace the selection with the following code:

<!-- description and features -->
{if (isset($product) && $product->description) || (isset($features) && $features) || (isset($accessories) && $accessories) || (isset($HOOK_PRODUCT_TAB) && $HOOK_PRODUCT_TAB) || (isset($attachments) && $attachments) || isset($product) && $product->customizable}
    <div id="info-tabs" class="clear ">
        
        <ul class="nav nav-tabs clearfix">
            {if $product->description}<li  class="active"><a data-toggle="tab" href="#tab-description">{l s='More info'}</a></li>{/if}
            {if $features}<li><a data-toggle="tab" href="#tab-sheet">{l s='Data sheet'}</a></li>{/if}
            {if $attachments}<li><a data-toggle="tab" href="#tab-attachments">{l s='Download'}</a></li>{/if}
            {if isset($accessories) AND $accessories}<li><a data-toggle="tab" href="#tab-accessories">{l s='Accessories'}</a></li>{/if}
            {if isset($product) && $product->customizable}<li><a data-toggle="tab" href="#tab-customization">{l s='Product customization'}</a></li>{/if}
            {$HOOK_PRODUCT_TAB}
        </ul>

        <div class="tab-content">

            {if isset($product) && $product->description}
                <!-- full description -->
                <div id="tab-description" class="tab-pane fade rte in active">{$product->description}</div>
            {/if}


            {if isset($features) && $features}
                <!-- products features -->	
                <table id="tab-sheet" class="tab-pane fade table-data-sheet">
                    {foreach from=$features item=feature}
                    <tr class="{cycle values="odd,even"}">
                        {if isset($feature.value)}
                        <td>{$feature.name|escape:'html':'UTF-8'}</td>
                        <td>{$feature.value|escape:'html':'UTF-8'}</td>
                        {/if}
                    </tr>
                    {/foreach}
                </table>

            {/if}


            {if isset($attachments) && $attachments}
                <div id="tab-attachments" class="tab-pane fade">
                    {foreach from=$attachments item=attachment name=attachements}
                        {if $smarty.foreach.attachements.iteration %3 == 1}<div class="row">{/if}
                            <div class="col-lg-4">
                                <h4><a href="{$link->getPageLink('attachment', true, NULL, "id_attachment={$attachment.id_attachment}")|escape:'html':'UTF-8'}">{$attachment.name|escape:'html':'UTF-8'}</a></h4>
                                <p class="text-muted">{$attachment.description|escape:'html':'UTF-8'}</p>
                                <a class="btn btn-default btn-block" href="{$link->getPageLink('attachment', true, NULL, "id_attachment={$attachment.id_attachment}")|escape:'html':'UTF-8'}">
                                    <i class="icon-download"></i>
                                    {l s="Download"} ({Tools::formatBytes($attachment.file_size, 2)})
                                </a>
                                <hr />
                            </div>
                        {if $smarty.foreach.attachements.iteration %3 == 0 || $smarty.foreach.attachements.last}</div>{/if}
                    {/foreach}	
                </div>	        
            {/if}

            {if isset($accessories) AND $accessories}
                <!-- accessories -->
                <div id="tab-accessories" class="tab-pane fade bullet">
                    <div class="block products_block accessories-block clearfix">
                        <div class="block_content">
                            <ul class="block_content products-block clearfix" id="accessories-list">
                                {foreach from=$accessories item=accessory name=accessories_list}
                                    {if ($accessory.allow_oosp || $accessory.quantity_all_versions > 0 || $accessory.quantity > 0) && $accessory.available_for_order && !isset($restricted_country_mode)}
                                        {assign var='accessoryLink' value=$link->getProductLink($accessory.id_product, $accessory.link_rewrite, $accessory.category)}
                                        <li class="item product-box ajax_block_product{if $smarty.foreach.accessories_list.first} first_item{elseif $smarty.foreach.accessories_list.last} last_item{else} item{/if} product_accessories_description">
                                            <div class="product_desc">
                                                <a href="{$accessoryLink|escape:'html':'UTF-8'}" title="{$accessory.legend|escape:'html':'UTF-8'}" class="product-image product_image">
                                                    <img class="lazyOwl" src="{$link->getImageLink($accessory.link_rewrite, $accessory.id_image, 'home_default')|escape:'html':'UTF-8'}" alt="{$accessory.legend|escape:'html':'UTF-8'}" width="{$homeSize.width}" height="{$homeSize.height}"/>
                                                </a>
                                                <div class="block_description">
                                                    <a href="{$accessoryLink|escape:'html':'UTF-8'}" title="{l s='More'}" class="product_description">
                                                        {$accessory.description_short|strip_tags|truncate:25:'...'}
                                                    </a>
                                                </div>
                                            </div>
                                            <div class="s_title_block">
                                                <h5 itemprop="name" class="product-name">
                                                    <a href="{$accessoryLink|escape:'html':'UTF-8'}">
                                                        {$accessory.name|truncate:20:'...':true|escape:'html':'UTF-8'}
                                                    </a>
                                                </h5>
                                                {if $accessory.show_price && !isset($restricted_country_mode) && !$PS_CATALOG_MODE}
                                                <span class="price">
                                                    {if $priceDisplay != 1}
                                                    {displayWtPrice p=$accessory.price}{else}{displayWtPrice p=$accessory.price_tax_exc}
                                                    {/if}
                                                </span>
                                                {/if}
                                            </div>
                                            <div class="clearfix" style="margin-top:5px">
                                                {if !$PS_CATALOG_MODE && ($accessory.allow_oosp || $accessory.quantity > 0)}
                                                    <div class="no-print">
                                                        <a class="exclusive button ajax_add_to_cart_button" href="{$link->getPageLink('cart', true, NULL, "qty=1&amp;id_product={$accessory.id_product|intval}&amp;token={$static_token}&amp;add")|escape:'html':'UTF-8'}" data-id-product="{$accessory.id_product|intval}" title="{l s='Add to cart'}">
                                                            <span>{l s='Add to cart'}</span>
                                                        </a>
                                                    </div>
                                                {/if}
                                            </div>
                                        </li>
                                    {/if}
                                {/foreach}
                            </ul>
                        </div>
                    </div>
                </div>
                <script type="Text/javascript">
                    $(document).ready(function(){
                     	if (!$('#accessories-list li').length){
                            $('.accessories-block').parent().remove();
                        }
                    });
                </script>
            {/if}

            <!-- Customizable products -->
            {if isset($product) && $product->customizable}
                <div id="tab-customization" class="tab-pane fade bullet customization_block">
                    <!-- Customizable products -->
                    <form method="post" action="{$customizationFormTarget}" enctype="multipart/form-data" id="customizationForm" class="clearfix">
                        <p class="infoCustomizable">
                            {l s='After saving your customized product, remember to add it to your cart.'}
                            {if $product->uploadable_files}
                            <br />
                            {l s='Allowed file formats are: GIF, JPG, PNG'}{/if}
                        </p>
                        {if $product->uploadable_files|intval}
                            <div class="customizableProductsFile">
                                <h5 class="product-heading-h5">{l s='Pictures'}</h5>
                                <ul id="uploadable_files" class="clearfix">
                                    {counter start=0 assign='customizationField'}
                                    {foreach from=$customizationFields item='field' name='customizationFields'}
                                        {if $field.type == 0}
                                            <li class="customizationUploadLine{if $field.required} required{/if}">{assign var='key' value='pictures_'|cat:$product->id|cat:'_'|cat:$field.id_customization_field}
                                                {if isset($pictures.$key)}
                                                    <div class="customizationUploadBrowse">
                                                        <img src="{$pic_dir}{$pictures.$key}_small" alt="" />
                                                            <a href="{$link->getProductDeletePictureLink($product, $field.id_customization_field)|escape:'html':'UTF-8'}" title="{l s='Delete'}" >
                                                                <img src="{$img_dir}icon/delete.gif" alt="{l s='Delete'}" class="customization_delete_icon" width="11" height="13" />
                                                            </a>
                                                    </div>
                                                {/if}
                                                <div class="customizationUploadBrowse form-group">
                                                    <label class="customizationUploadBrowseDescription">
                                                        {if !empty($field.name)}
                                                            {$field.name}
                                                        {else}
                                                            {l s='Please select an image file from your computer'}
                                                        {/if}
                                                        {if $field.required}<sup>*</sup>{/if}
                                                    </label>
                                                    <input type="file" name="file{$field.id_customization_field}" id="img{$customizationField}" class="form-control customization_block_input {if isset($pictures.$key)}filled{/if}" />
                                                </div>
                                            </li>
                                            {counter}
                                        {/if}
                                    {/foreach}
                                </ul>
                            </div>
                        {/if}
                        {if $product->text_fields|intval}
                            <div class="customizableProductsText">
                                <h5 class="product-heading-h5">{l s='Text'}</h5>
                                <ul id="text_fields">
                                {counter start=0 assign='customizationField'}
                                {foreach from=$customizationFields item='field' name='customizationFields'}
                                    {if $field.type == 1}
                                        <li class="customizationUploadLine{if $field.required} required{/if}">
                                            <label for ="textField{$customizationField}">
                                                {assign var='key' value='textFields_'|cat:$product->id|cat:'_'|cat:$field.id_customization_field}
                                                {if !empty($field.name)}
                                                    {$field.name}
                                                {/if}
                                                {if $field.required}<sup>*</sup>{/if}
                                            </label>
                                            <textarea name="textField{$field.id_customization_field}" class="form-control customization_block_input" id="textField{$customizationField}" rows="3" cols="20">{strip}
                                                {if isset($textFields.$key)}
                                                    {$textFields.$key|stripslashes}
                                                {/if}
                                            {/strip}</textarea>
                                        </li>
                                        {counter}
                                    {/if}
                                {/foreach}
                                </ul>
                            </div>
                        {/if}
                        <p id="customizedDatas">
                            <input type="hidden" name="quantityBackup" id="quantityBackup" value="" />
                            <input type="hidden" name="submitCustomizedDatas" value="1" />
                            <button class="button btn btn-default button button-small" name="saveCustomization">
                                <span>{l s='Save'}</span>
                            </button>
                            <span id="ajax-loader" class="unvisible">
                                <img src="{$img_ps_dir}loader.gif" alt="loader" />
                            </span>
                        </p>
                    </form>
                    <p class="clear required"><sup>*</sup> {l s='required fields'}</p>
                </div>
            {/if}	  
            {if isset($HOOK_PRODUCT_TAB_CONTENT) && $HOOK_PRODUCT_TAB_CONTENT}{$HOOK_PRODUCT_TAB_CONTENT}{/if}
        </div>
    </div>
    {/if}
    {if isset($packItems) && $packItems|@count > 0}
    <section id="blockpack">
        <h3 class="page-product-heading">{l s='Pack content'}</h3>
        {include file="$tpl_dir./product-list.tpl" products=$packItems}
    </section>
    {/if}	 
    {if isset($HOOK_PRODUCT_FOOTER) && $HOOK_PRODUCT_FOOTER}{$HOOK_PRODUCT_FOOTER}{/if}
{/if}

 

 

Go to product.js in the js folder of the default theme and remove the following lines:

if (!$('#bxslider li').length) $('.accessories-block').parent().remove();

For Prestashop 1.6.1.1 the above code is located in lines 194-195. For other Prestashop versions the line numbers might be slightly different.

 

Last but not least, we need to make some changes in the the template files of the reviews section. Reviews are implemented in Prestashop through the module Product Comments.

In Prestashop 1.6.1.1 you will need to go to default theme > modules > productcomments folder.

First, open up the template file tab.tpl in your editor. Replace the line:

<h3 id="#idTab5" class="idTabHrefShort page-product-heading">{l s='Reviews' mod='productcomments'}</h3>

With the following code:

<li><a href="#tab-comments" data-toggle="tab" >{l s='Reviews' mod='productcomments'}</a></li>

Then, open up the template file productcomments.tpl in your editor. Here, we need to wrap the whole content of the file with a wrapper.

So, add the following code just after the initial comments:

<div id="tab-comments" class="tab-pane fade">

and don’t forget to close the wrapper up by adding the following line of code at the end of the file:

</div>