
Adding Previous and Next navigation buttons to the Prestashop product page
To allow an easier navigation through categories, let’s add Previous and Next product navigation buttons to each product page in Prestashop
- Prestashop version: 1.5, 1.6
Please notice project files are from 1.6.0.9
Introduction
Although I only tested this code on Prestashop 1.6, it should equally work on 1.5 as the database structure didn’t change. That said, we need to edit/extend the following files:
- classes/Product.php (to grab previous and next products)
- controllers/front/ProductController.php (to assign links to the template)
- themes/default-bootstrap/product.tpl (to add the buttons)
As always, I recommend overriding whenever possible; therefore, we will extend the first 2 files and directly modify the template one.
Additionally, given that a product can belong to different categories, we will only navigate through the default one, to make things easier.
Step 1 – Retrieving the previous and next product
First off, we need some data to work with. Neither previous nor next product are assigned to the product page, so we need to get them first. As mentioned above, to simplify we will only retrieve the ones that come before and after in the default product category. It is indeed possible to use the previously visited category, but things can get quite complicated and overly troublesome (it might be a good subject for another tutorial though!).
Create a new file inside override/classes and call it Product.php, and paste the following inside php tags:
class Product extends ProductCore { }
Then, let’s create the method we need, and start by grabbing the current product’s position in its default category:
public function getAdjacentProducts() { $position = Db::getInstance()->getValue('SELECT position FROM '._DB_PREFIX_.'category_product WHERE id_product = ' . (int)$this->id . ' AND id_category = ' . (int)$this->id_category_default); }
Once we get that, we can retrieve previous and next products:
public function getAdjacentProducts() { $position = Db::getInstance()->getValue('SELECT position FROM '._DB_PREFIX_.'category_product WHERE id_product = ' . (int)$this->id . ' AND id_category = ' . (int)$this->id_category_default); // get products that are before and after $previous = Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow(' SELECT cp.id_product, pl.link_rewrite, cp.position, pl.name FROM '._DB_PREFIX_.'category_product cp LEFT JOIN '._DB_PREFIX_.'product_lang pl ON (cp.id_product = pl.id_product) LEFT JOIN '._DB_PREFIX_.'product p ON (cp.id_product = p.id_product) WHERE p.id_category_default = '.(int)$this->id_category_default.' AND (cp.position < '. (int)($position ) .' ) AND cp.id_category = ' . (int)$this->id_category_default .' AND pl.id_lang = '.(Context::getContext()->language->id).' ORDER BY cp.position DESC'); $next = Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow(' SELECT cp.id_product, pl.link_rewrite, cp.position, pl.name FROM '._DB_PREFIX_.'category_product cp LEFT JOIN '._DB_PREFIX_.'product_lang pl ON (cp.id_product = pl.id_product) LEFT JOIN '._DB_PREFIX_.'product p ON (cp.id_product = p.id_product) WHERE p.id_category_default = '.(int)$this->id_category_default.' AND (cp.position > '. (int)($position ) .' ) AND cp.id_category = ' . (int)$this->id_category_default .' AND pl.id_lang = '.(Context::getContext()->language->id).' ORDER BY cp.position ASC'); return array('previous' => $previous, 'next' => $next); }
Explanation: We are using basically the same qurery for both the previous and next product. For the previous, we get the very first product that has a lower position, given the conditions. For the next, the one that has the immediately higher one. Notice we only grab products from the same default category, and that is why we can’t simply use position + 1 and position – 1 in a single query (we would have gaps)
Step 2 – Assigning products to the Product page
It’s time to assign the variables we got to the product page. Create a new override, this time inside override/controllers/front and call it ProductController.php. Then, as always, initialize the class override:
Class ProductController extends ProductControllerCore { public function initContent() { parent::initContent(); } }
We are going to extend the initContent() method, as you can see. Therefore, inside it, and before calling the parent’s initContent(), paste the following:
$adjacent_products = $this->product->getAdjacentProducts(); $this->context->smarty->assign(array( 'prev_product'=> $adjacent_products['previous'], 'next_product'=> $adjacent_products['next'] ));
Explanation: Nothing special here, we simply use the previously created method, and then assign previous and next products
Our final override should look like this:
Class ProductController extends ProductControllerCore { public function initContent() { $adjacent_products = $this->product->getAdjacentProducts(); $this->context->smarty->assign(array( 'prev_product'=> $adjacent_products['previous'], 'next_product'=> $adjacent_products['next'] )); parent::initContent(); } }
Time to add our buttons! Before that, though, open the cache/ folder and erase class_index.php so that our overrides can take place!
Step 3 – Adding the new buttons to product.tpl
In this last stepm I will use the default template (as always), so your code might differ from mine, especially if you are using Prestashop 1.5, as I am using 1.6.
We first need to decide where the two buttons are going to sit. Ideally, I recommend adding them at the very top of the product page, so that they are easily and immediately accessible. Of course, any place is fine. Once you decide on position, open up product.tpl located in your theme’s folder.
For my position, the right spot is immediately before the following code, at the very beginning of the file:
<div class="primary_block row">
Paste the following in:
<!-- Navigation --> <div class="product-navigation clearfix" style="margin-bottom:20px"> {if $prev_product} <a title="{$prev_product.name}" class="btn btn-default" href="{$link->getProductLink($prev_product.id_product, $prev_product.link_rewrite)}">{l s='Previous Product'}</a> {/if} {if $next_product} <a title="{$next_product.name}" class="btn btn-default" style="float:right"href="{$link->getProductLink($next_product.id_product, $next_product.link_rewrite)}">{l s='Next Product'}</a> {/if} </div>
And we are done!