Seleccionar página

Buenos días,

Prestashop está mejorando mucho en optimización SEO, pero todavía está un poco verde en algunos aspectos y, a pesar de no ser un experto en SEO, se me ha dado la necesidad de redirigir productos que están descatalogados a su categoría y no a un producto en específico, dado que pueden darse casos en los que un artículo puede no ser lo suficientemente parecido a otro para «suplantarlo» y, creo más conveniente que sea el propio cliente el que elija otro artículo dentro de la misma categoría que el artículo descatalogado.

Pues bien, aquí tenéis un pequeño aporte que puede servirle a algunos.

En el archivo /controllers/front/ProductController.php, sobre la línea 108 hay que comentar o eliminar esta línea para los casos en los que no tenga un artículo asociado no establezca la redirección 404 y quede la redirección 301

if (!$this->product->id_product_redirected || $this->product->id_product_redirected == $this->product->id)
	$this->product->redirect_type = '404';

y cambiadla por este código para que cuando no tenga redirección 301 ni 302 sea 404

if ($this->product->redirect_type != '301' && $this->product->redirect_type != '302')
	$this->product->redirect_type = '404';

Con esto hecho, vamos a la línea 112, donde tenemos este código en la función «public function init()»:

switch ($this->product->redirect_type)
{
	case '301':
		header('HTTP/1.1 301 Moved Permanently');
		header('Location: '.$this->context->link->getProductLink($this->product->id_product_redirected));
		exit;
	break;
	case '302':
		header('HTTP/1.1 302 Moved Temporarily');
		header('Cache-Control: no-cache');
		header('Location: '.$this->context->link->getProductLink($this->product->id_product_redirected));
		exit;
	break;
	case '404':
	default:
		header('HTTP/1.1 404 Not Found');
		header('Status: 404 Not Found');
		$this->errors[] = Tools::displayError('This product is no longer available.');
	break;
}

Cambiamos el caso 301 para que quede de la siguiente forma:

case '301':
	if ($this->product->id_product_redirected){
		header('HTTP/1.1 301 Moved Permanently');
		header('Location: '.$this->context->link->getProductLink($this->product->id_product_redirected));
	} else {
		header('HTTP/1.1 301 Moved Permanently');
		header('Location: '.$this->context->link->getCategoryLink($this->product->id_category_default));
	}
	exit;
break;

Comprobamos si tenemos producto relacionado («id_product_redirected»). Si no tenemos producto relacionado, lo redirigimos a la categoría del producto obteniendo el link con «getCategoryLink» y especificando el Id de la categoría del producto con «id_category_default».

Es muy sencillo pero como buen novato tardé bastante en realizarlo. Se puede hacer lo mismo en el 302 si se necesita. Aún así me falta perfeccionarlo para que incluya un mensaje que informe al cliente de que el producto está descatalogado y que se le muestra una serie de artículos de su misma categoría. Cuando lo tenga os lo pondré también, aunque si hay alguien que dé con la solución antes que yo y lo pone, agradecido.

Espero os sirva. Un saludo,

Iván Ros

 

EDITO: Como bien me han corregido en el foro de Prestashop, para este tipo de cambios lo mejor es hacer un override, con lo que copiad la función init() y extended la clase ProductControllerCore. Os pongo el código completo de cómo quedaríai el archivo /override/controllers/front/ProductController.php

<?php
 
class ProductController extends ProductControllerCore
{
	/**
	 * Initialize product controller
	 * @see FrontController::init()
	 */
	public function init()
	{
		parent::init();
 
		if ($id_product = (int)Tools::getValue('id_product'))
			$this->product = new Product($id_product, true, $this->context->language->id, $this->context->shop->id);
 
		if (!Validate::isLoadedObject($this->product))
		{
			header('HTTP/1.1 404 Not Found');
			header('Status: 404 Not Found');
			$this->errors[] = Tools::displayError('Product not found');
		}
		else
		{
			$this->canonicalRedirection();
			/*
			 * If the product is associated to the shop
			 * and is active or not active but preview mode (need token + file_exists)
			 * allow showing the product
			 * In all the others cases => 404 "Product is no longer available"
			 */
			if (!$this->product->isAssociatedToShop() || !$this->product->active)
			{
				if (Tools::getValue('adtoken') == Tools::getAdminToken('AdminProducts'.(int)Tab::getIdFromClassName('AdminProducts').(int)Tools::getValue('id_employee')) && $this->product->isAssociatedToShop())
				{
					// If the product is not active, it's the admin preview mode
					$this->context->smarty->assign('adminActionDisplay', true);
				}
				else
				{
					$this->context->smarty->assign('adminActionDisplay', false);
					if ($this->product->redirect_type != '301' && $this->product->redirect_type != '302')
						$this->product->redirect_type = '404';
					
					switch ($this->product->redirect_type)
					{
						case '301':
							if ($this->product->id_product_redirected){
								header('HTTP/1.1 301 Moved Permanently');
								header('Location: '.$this->context->link->getProductLink($this->product->id_product_redirected));
							} else {
								header('HTTP/1.1 301 Moved Permanently');
								header('Location: '.$this->context->link->getCategoryLink($this->product->id_category_default));
							}
							exit;
						break;
						case '302':
							header('HTTP/1.1 302 Moved Temporarily');
							header('Cache-Control: no-cache');
							header('Location: '.$this->context->link->getProductLink($this->product->id_product_redirected));
							exit;
						break;
						case '404':
						default:
							header('HTTP/1.1 404 Not Found');
							header('Status: 404 Not Found');
							$this->errors[] = Tools::displayError('This product is no longer available.');
						break;
					}
				}
			}
			elseif (!$this->product->checkAccess(isset($this->context->customer->id) && $this->context->customer->id ? (int)$this->context->customer->id : 0))
			{
				header('HTTP/1.1 403 Forbidden');
				header('Status: 403 Forbidden');
				$this->errors[] = Tools::displayError('You do not have access to this product.');
			}
			else
			{
				// Load category
				$id_category = false;
				if (isset($_SERVER['HTTP_REFERER']) && $_SERVER['HTTP_REFERER'] == Tools::secureReferrer($_SERVER['HTTP_REFERER']) // Assure us the previous page was one of the shop
					&& preg_match('~^.*(?<!\/content)\/([0-9]+)\-(.*[^\.])|(.*)id_(category|product)=([0-9]+)(.*)$~', $_SERVER['HTTP_REFERER'], $regs))
				{
					// If the previous page was a category and is a parent category of the product use this category as parent category
					$id_object = false;
					if (isset($regs[1]) && is_numeric($regs[1]))
						$id_object = (int)$regs[1];
					elseif (isset($regs[5]) && is_numeric($regs[5]))
						$id_object = (int)$regs[5];
					if ($id_object)
					{
						$referers = array($_SERVER['HTTP_REFERER'],urldecode($_SERVER['HTTP_REFERER']));
						if (in_array($this->context->link->getCategoryLink($id_object), $referers))
							$id_category = (int)$id_object;
						elseif (isset($this->context->cookie->last_visited_category) && (int)$this->context->cookie->last_visited_category && in_array($this->context->link->getProductLink($id_object), $referers))
							$id_category = (int)$this->context->cookie->last_visited_category;
					}
 
				}
				if (!$id_category || !Category::inShopStatic($id_category, $this->context->shop) || !Product::idIsOnCategoryId((int)$this->product->id, array('0' => array('id_category' => $id_category))))
					$id_category = (int)$this->product->id_category_default;
				$this->category = new Category((int)$id_category, (int)$this->context->cookie->id_lang);
				if (isset($this->context->cookie) && isset($this->category->id_category) && !(Module::isInstalled('blockcategories') && Module::isEnabled('blockcategories')))
					$this->context->cookie->last_visited_category = (int)$this->category->id_category;
			}
		}
	}
}