Jump to content
Shutiri

HOW TO: different product.tpl (template) on a page per-product AND a per-category basis

Recommended Posts

Hello all,

 

I was looking for this one for a while, and wanted to contribute with the solution that worked for me.

 

This is a result of VEKIA's advices on different topics, so credits to him.

 

In controllers/front/ProductController.php, find: 

$this->setTemplate(_PS_THEME_DIR_.'product.tpl');

For SINGLE products, replace with:

		if (Tools::getValue('id_product')==3){  // For product number 3
			$this->setTemplate(_PS_THEME_DIR_.'productAlt1.tpl');
		} else {
			$this->setTemplate(_PS_THEME_DIR_.'product.tpl');
		}

To apply a template to a range of products within a given category or categories: 

		if ($this->category->id>=5 && $this->category->id<=7 || $this->category->id==11){
			$this->setTemplate(_PS_THEME_DIR_.'productStore.tpl'); // template file for caregories between 5 and 7, OR category 11
		} else {
			$this->setTemplate(_PS_THEME_DIR_.'product.tpl'); // DEFAULT template
		}

I hope this helps.

 

Cheers!!

  • Like 4

Share this post


Link to post
Share on other sites

Thanks, great idea! I was just about to ask if there were any suggestions how to accomplish this! :D

 

 

In fact I feel like it might be helpful to make a module, that does this as an override, but then also calls a custom hook, so that you can do your own logic in that hook, assign custom variables to your custom template file, etc.

 

I might work on that!

Edited by theillo (see edit history)

Share this post


Link to post
Share on other sites

BAM found a perfect solution!

 

I created a module that does that (so when I reinstall my store at a later point again, I can just reinstall the module). But you can also just hack your way through the process. I guess another advantage of making it a module is that you can require this module to be installed by all those modules that will now depend on this hook.

 

 

Here's what you need to do:

 

1.) Create a new Hook

 

When doing a module installation, you should be able to just call 

$this->registerHook('nameOfNewHook');

since the Hook class has a case for creating new, non existing hooks.

 

Otherwise, the code to create a new hook is this:

$hook = 'nameOfNewHook';
$new_hook = new Hook();
$new_hook->name = pSQL($hook);
$new_hook->title = pSQL($hook);
$new_hook->add();

So just run that code during installation of your module, or just run it once and then you're set.

 

No I actually gave my new hook the name 'actionLoadProductTemplate'.

 

2.) Create a new Product Controller class

 

Create a file called ProductController.php with the following contents:

<?php


class ProductController extends ProductControllerCore
{

	public function initContent()
	{
		parent::initContent();
		
		$template_file = Hook::exec('actionLoadProductTemplate', array('product' => $this->product, 'category'=> $this->category));
//you can pass along other properties of the product class by putting them in this array
		
		if($template_file && file_exists($template_file))
		{
			$tpl_path = $template_file;
		}
		else
		{
			$tpl_path = _PS_THEME_DIR_.'product.tpl';
		}
		$this->setTemplate($tpl_path);
	}
}

3.) Override the ProductConroller class

 

Once you created the class file, you'll need to make sure Prestashop uses it, by overriding it:

 

If you are installing a module, put it in the folder

'PS_ROOT/modules/NAMEOFYOURMODULE/override/controller/front/ProductController.php'

 

If you delete the file 'PS_ROOT/cache/class_index.php' JUST before the installation, it should even work properly from the start.

 

Of course alternatively you can just place your file in the override directory of the prestashop folder ( 'PS_ROOT/override/controller/front/ProductController.php')

 

If it doesn't work, make sure the class_index.php file has this written in it:

  'ProductController' => 
  array (
    'path' => 'override/controllers/front/ProductController.php',
    'type' => 'class',
    'override' => false,
  ),

or if you want to maintain the source code of your override file in the folder of your module, go like this:

  'ProductController' => 
  array (
    'path' => 'modules/NAMEOFYOURMODULE/override/controllers/front/ProductController.php',
    'type' => 'class',
    'override' => true,
  ),

Again, you just need to hack around in the cache file, if it didn't work from the beginning (which it never has for me though, so I've always had to do it :D )

 

4.) Start using your new hook in all your modules! :-D

 

So now you can use this great new hook to change the template file of a product.

 

Your hook function will need to RETURN the path to the new template you want to use, and your template file needs to exist. Otherwise it'll just show the default template file.

	public function hookActionLoadProductTemplate($params)
	{
		$this->product = $params['product']; 
                $this->category = $params['category']; 
                //the product and category arrays are passed along by the product controller.
		$this->customer = $this->context->customer;
		
		//do some custom logic
		$myrule = TRUE;
		//for example what type of product you have, and if you customer has purchased it, or what category it is in...

		//assign any custom variables to your custom template
		$this->context->smarty->assign('custom stuff', 'custom things go here');
		
		//return the path of your new template.
		if($myrule)
		{
			$this->context->smarty->assign('custom_variable', 'custom value!');
			
			return _PS_MODULE_DIR_.'YOURMODULENAME/views/templates/product_custom_no1.tpl';
		}
		else
		{
			$this->context->smarty->assign('another_variable', 'different value!');
			
			return _PS_THEME_DIR_.'product_custom_no2.tpl';
		}
	}		

 

Edited by theillo (see edit history)
  • Like 2
  • Thanks 1

Share this post


Link to post
Share on other sites

Lol thank you so much Theillo, this is great. This post should be pinned to correct section or something like this. Nice exemple of new hook and override

Edited by LauraPresta (see edit history)
  • Like 1

Share this post


Link to post
Share on other sites

did you found a better/cleaner solution for this ? 

"If you delete the file 'PS_ROOT/cache/class_index.php' JUST before the installation, it should even work properly from the start."

Share this post


Link to post
Share on other sites
On 6/6/2018 at 9:12 AM, LauraPresta said:

did you found a better/cleaner solution for this ? 

"If you delete the file 'PS_ROOT/cache/class_index.php' JUST before the installation, it should even work properly from the start."

 

 

Seems to me that deleting it right before install is the cleanest, otherwise I used to do this:

$this->original_string = "'ProductController' => 
  array (
    'path' => '',
    'type' => 'class',
    'override' => false,
  ),";
  
$this->replacement_string = "'ProductController' => 
  array (
    'path' => 'modules/customproducttpl/override/controllers/front/ProductController.php',
    'type' => 'class',
    'override' => true,
  ),";

		$this->rewriteClassCache($this->original_string, $this->replacement_string);
		

	public function rewriteClassCache($original,$replacement){		
	
		$file = dirname(dirname(dirname(__FILE__))).'/cache/class_index.php';
		
		$filecontent=file_get_contents($file);
		
		$pos=strpos($filecontent, $original);
		if($pos === false)
		{
			//p('couldnt find original.');
			$pos=strpos($filecontent, $replacement);
			//d('found replacement at '.$pos);
			return;
		}
		
		$filecontent=substr($filecontent, 0, $pos)."\r\n".$replacement."\r\n".substr($filecontent, $pos+strlen($original));
		//d($filecontent);
		
		if( !file_put_contents($file, $filecontent) )
		{
			d('rewriting the class index file failed!');	
			return;
		}
		else{
			//p('did the replacement');	
			return;
		}
		
	}

 

Share this post


Link to post
Share on other sites

Thank you theillo for this answer ;) 

I'll test your solution.

 

About deleting the file, do you think it could be done during the install part of the module ? i mean, do we have the rights to do this  - is it a legit use ?

Share this post


Link to post
Share on other sites

Hi,

Is it possible to achieve this in Prestashop 1.7.4.2 ?

Kind regards,

Share this post


Link to post
Share on other sites

Hello! I'd like to know if it works for 1.7.5.1 thanks

Share this post


Link to post
Share on other sites

Hi,

See link below, it's actually very simple to do ...

https://devdocs.prestashop.com/1.7/themes/reference/templates/templates-layouts/

Specific templates

If you’re working on a big store in many languages you may need to change the layout of the page depending on the language.

For example you want a different product page for american customers and japanese ones. In this case you simply have to create new template product.tpl and place it in the right folder.

When searching for a template, PrestaShop will check many location to determine which file should be used. It make it very easy to have different template for a given locale or a specific entity id.

With the product page, the core will check the following locations (in order) and return the first template found:

Example with a product with ID = 3 and locale = en-US

  1. en-US/catalog/product-3.tpl
  2. catalog/product-3.tpl
  3. en/US/catalog/listing/product.tpl
  4. catalog/listing/product.tpl

Another example with category template for the category with ID = 9 and locale = en-US.

  1. en-US/catalog/listing/category-9.tpl
  2. catalog/listing/category-9.tpl
  3. en/US/catalog/listing/category.tpl
  4. catalog/listing/category.tpl
  5. en-US/catalog/listing/product-list.tpl
  6. catalog/listing/product-list.tpl

Kind regards,

Edited by Takuya (see edit history)

Share this post


Link to post
Share on other sites
23 minutes ago, Takuya said:

Hi,

See link below, it's actually very simple to do ...

https://devdocs.prestashop.com/1.7/themes/reference/templates/templates-layouts/

Specific templates

If you’re working on a big store in many languages you may need to change the layout of the page depending on the language.

For example you want a different product page for american customers and japanese ones. In this case you simply have to create new template product.tpl and place it in the right folder.

When searching for a template, PrestaShop will check many location to determine which file should be used. It make it very easy to have different template for a given locale or a specific entity id.

With the product page, the core will check the following locations (in order) and return the first template found:

Example with a product with ID = 3 and locale = en-US

  1. en-US/catalog/product-3.tpl
  2. catalog/product-3.tpl
  3. en/US/catalog/listing/product.tpl
  4. catalog/listing/product.tpl

Another example with category template for the category with ID = 9 and locale = en-US.

  1. en-US/catalog/listing/category-9.tpl
  2. catalog/listing/category-9.tpl
  3. en/US/catalog/listing/category.tpl
  4. catalog/listing/category.tpl
  5. en-US/catalog/listing/product-list.tpl
  6. catalog/listing/product-list.tpl

Kind regards,

Thank you!!! :)

Share this post


Link to post
Share on other sites
Posted (edited)
On 2/25/2015 at 2:02 PM, theillo said:

BAM found a perfect solution!

 

I created a module that does that (so when I reinstall my store at a later point again, I can just reinstall the module). But you can also just hack your way through the process. I guess another advantage of making it a module is that you can require this module to be installed by all those modules that will now depend on this hook.

 

 

Here's what you need to do:

 

1.) Create a new Hook

 

When doing a module installation, you should be able to just call 


$this->registerHook('nameOfNewHook');

since the Hook class has a case for creating new, non existing hooks.

 

Otherwise, the code to create a new hook is this:


$hook = 'nameOfNewHook';
$new_hook = new Hook();
$new_hook->name = pSQL($hook);
$new_hook->title = pSQL($hook);
$new_hook->add();

So just run that code during installation of your module, or just run it once and then you're set.

 

No I actually gave my new hook the name 'actionLoadProductTemplate'.

 

2.) Create a new Product Controller class

 

Create a file called ProductController.php with the following contents:


<?php


class ProductController extends ProductControllerCore
{

	public function initContent()
	{
		parent::initContent();
		
		$template_file = Hook::exec('actionLoadProductTemplate', array('product' => $this->product, 'category'=> $this->category));
//you can pass along other properties of the product class by putting them in this array
		
		if($template_file && file_exists($template_file))
		{
			$tpl_path = $template_file;
		}
		else
		{
			$tpl_path = _PS_THEME_DIR_.'product.tpl';
		}
		$this->setTemplate($tpl_path);
	}
}

3.) Override the ProductConroller class

 

Once you created the class file, you'll need to make sure Prestashop uses it, by overriding it:

 

If you are installing a module, put it in the folder

'PS_ROOT/modules/NAMEOFYOURMODULE/override/controller/front/ProductController.php'

 

If you delete the file 'PS_ROOT/cache/class_index.php' JUST before the installation, it should even work properly from the start.

 

Of course alternatively you can just place your file in the override directory of the prestashop folder ( 'PS_ROOT/override/controller/front/ProductController.php')

 

If it doesn't work, make sure the class_index.php file has this written in it:


  'ProductController' => 
  array (
    'path' => 'override/controllers/front/ProductController.php',
    'type' => 'class',
    'override' => false,
  ),

or if you want to maintain the source code of your override file in the folder of your module, go like this:


  'ProductController' => 
  array (
    'path' => 'modules/NAMEOFYOURMODULE/override/controllers/front/ProductController.php',
    'type' => 'class',
    'override' => true,
  ),

Again, you just need to hack around in the cache file, if it didn't work from the beginning (which it never has for me though, so I've always had to do it :D )

 

4.) Start using your new hook in all your modules! 😄

 

So now you can use this great new hook to change the template file of a product.

 

Your hook function will need to RETURN the path to the new template you want to use, and your template file needs to exist. Otherwise it'll just show the default template file.


	public function hookActionLoadProductTemplate($params)
	{
		$this->product = $params['product']; 
                $this->category = $params['category']; 
                //the product and category arrays are passed along by the product controller.
		$this->customer = $this->context->customer;
		
		//do some custom logic
		$myrule = TRUE;
		//for example what type of product you have, and if you customer has purchased it, or what category it is in...

		//assign any custom variables to your custom template
		$this->context->smarty->assign('custom stuff', 'custom things go here');
		
		//return the path of your new template.
		if($myrule)
		{
			$this->context->smarty->assign('custom_variable', 'custom value!');
			
			return _PS_MODULE_DIR_.'YOURMODULENAME/views/templates/product_custom_no1.tpl';
		}
		else
		{
			$this->context->smarty->assign('another_variable', 'different value!');
			
			return _PS_THEME_DIR_.'product_custom_no2.tpl';
		}
	}		

 

Where do we place hookActionLoadProductTemplate( ) ?
Inside mymodule.php or inside the ProductController.php?

Thanks a lot for your help!

Edited by limitcracker (see edit history)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...

Important Information

Cookies ensure the smooth running of our services. Using these, you accept the use of cookies. Learn More