Module : Les clients ayant acheté cet article ont également acheté

  • Par Magentix le 03/07/2010
  • Difficulté : 3/4

Module : Les clients ayant acheté cet article ont également acheté Plutôt courant sur les sites e-commerce, cette extension Magento développé par Magentix permet de favoriser l'ajout de produits complémentaires au panier. Selon les produits acquis par les internautes, elle se chargera de récupérer et d'afficher l'ensemble produits achetés en complément du produit consulté.

L'objectif de cette extension est de proposer aux internautes des produits complémentaires générés automatiquement selon les produits acquis précédemment au sein d'un même panier. Cette technique de recoupement a pour avantage de fonctionner en totale autonomie, les produits apparaîtront au fur à mesure des achats sur le site (à condition que les paniers comportent plus d'un produit).

Produits complémentaires acquis par les internautes

L'enjeu principale pour réaliser ce module est d'établir la bonne requête. L'extension est disponible en téléchargement sur la page de cet article (colonne de droite), voici quelques explications complémentaires.

Architecture du module

  • app/code/local/Magentix/AlsoBought
  • Block
  • Bought.php
  • etc
  • config.xml
  • Model
  • Mysql4
  • Bought.php
  • Bought.php
  • app/design/frontend/base/default
  • layout
  • alsobought.xml
  • template
  • alsobought
  • bought.phtml
  • app/etc/modules
  • Magentix_AlsoBought.xml

Développement du module

Avant de se lancer dans le développement du module, il est primordiale de déterminer la requête à exécuter pour l'acquisition de l'identifiant des produits achetés en même temps que le produit consulté.

L'ensemble des produits achetés se situent dans la table sales_flat_order_item. Les conditions doivent être les suivantes :

  • J'isole les commandes comportant le produit spécifique
  • Je supprime les commandes dont le statut est annulé
  • J'isole les produits contenus dans ces commandes
  • Je supprime le produit spécifique des résultats
  • Je regroupe les produits par identifiant afin d'éviter les doublons

Ce qui nous amène finalement à la requête suivante (où X représente l'identifiant du produit consulté) :

Requête

SELECT `s2`.`product_id` AS `id`
FROM `sales_flat_order_item` AS `s1`
INNER JOIN `sales_flat_order_item` AS `s2` ON s1.order_id = s2.order_id
WHERE (s1.product_id = 'X') AND (s2.product_id != 'X') AND (s1.qty_canceled = 0)
GROUP BY `s2`.`product_id`

Nous pouvons maintenant construire la requête à l'aide des méthodes proposés par Zend. Le méthode getProductsIds de la classe Magentix_AlsoBought_Model_Mysql4_Bought permet la construction puis l'exécution de la requête (l'adaptateur de lecture de la ressource est définie dans le fichier de configuration).

app/code/local/Magentix/AlsoBought/Model/Mysql4/Bought.php

<?php

class Magentix_AlsoBought_Model_Mysql4_Bought extends Mage_Core_Model_Mysql4_Abstract {

     protected function _construct() {
          $this->_init('alsobought/bought','id');
     }

     public function getProductsIds($product_id) {
          $connection = $this->_getReadAdapter();

          $select = $this->_getReadAdapter()->select()
               ->from(array('s1' => 'sales_flat_order_item'),array('id' => 's2.product_id'))
               ->join(array('s2' => 'sales_flat_order_item'),"s1.order_id = s2.order_id",array())
               ->where('s1.product_id = ?', $product_id)
               ->where('s2.product_id != ?', $product_id)
               ->where('s1.qty_canceled = ?', 0)
               ->group('s2.product_id');

          if(!$connection->fetchRow($select)) return 0;

          return $connection->fetchAll($select);
     }
}

En paramètre se trouve l'identifiant du produit actuellement consulté. Depuis le modèle Magentix_AlsoBought_Model_Bought il est alors possible de filtrer une collection de produits selon les identifiants de produits récupérés grâce à la méthode getProductsIds que nous venons d'établir.

app/code/local/Magentix/AlsoBought/Model/Bought.php

<?php

class Magentix_AlsoBought_Model_Bought extends Mage_Core_Model_Abstract {

     protected function _getResource() {
          if (is_null($this->_resource)) {
               $this->_resource = Mage::getResourceModel('alsobought/bought');
          }
          return $this->_resource;
     }

     public function getAlsoBoughtProductCollection($product_id) {
          $ids = $this->_getResource()->getProductsIds($product_id);
          $products = Mage::getResourceModel('catalog/product_collection')->addAttributeToFilter('entity_id',$ids);

          return $products;
     }

}

La suite du développement du module concerne la mise en place d'un bloc classique. Nous ne le détaillerons pas.

Affichage des produits

L'affichage des produits se gère depuis le fichier du template alsobought/bought.phtml. Il faudra prendre soin de le déplacer dans le template adéquat. Ce fichier est à peu de chose près identique au fichier du template de base utilisé pour l'affichage des produits en upsell (montée en gamme).

Le layout indique que le bloc est enfant du bloc product.info de la référence content. Il spécifie également le template à utiliser (alsobought/bought.phtml).

app/design/frontend/base/default/layout/alsobought.xml

<?xml version="1.0"?>
<layout version="0.1.0">
     <catalog_product_view>
          <reference name="content">
               <block name="product.info">
                    <block type="alsobought/bought" name="product.info.alsobought" as="alsobought_products" template="alsobought/bought.phtml">
                         <action method="setColumnCount"><columns>4</columns></action>
                         <action method="setItemLimit"><type>alsobought</type><limit>4</limit></action>
                    </block>
               </block>
          </reference>
     </catalog_product_view>
</layout>

De la même manière que pour les produits en upsell, on indique ici le nombre de colonne par ligne, et le nombre de produits total à afficher.

il ne reste plus qu'à éditer le fichier du template utilisé pour la fiche produit, et à ajouter le bloc alsobought à l'endroit souhaité :

app/design/frontend/base/default/template/catalog/product/view.phtml

<!-- ... -->
<div class="product-collateral">
     <?php echo $this->getChildHtml('description') ?>
     <?php echo $this->getChildHtml('additional') ?>
     <?php echo $this->getChildHtml('upsell_products') ?>

     <!-- Les clients ayant acheté cet article ont également acheté -->
     <?php echo $this->getChildHtml('alsobought_products') ?>

     <?php echo $this->getChildHtml('product_additional_data') ?>
</div>
<!-- ... -->

Notez que pour éviter l'exécution des requêtes à chaque visualisation d'une fiche produit j'ai opté pour une mise en cache de ces informations. La durée de vie définie dans le constructeur du bloc Magentix_AlsoBought_Block_Bought est de 3600 secondes.

Le module est compatible avec les versions 1.3.X et 1.4.X de Magento.

29

Commentez cet article Module : Les clients ayant acheté cet article ont également acheté

Gabriel Bouhatous Le 03/07/2010 à 19:34
Bonne conception. :)
#1
Magentips Le 05/07/2010 à 11:02
Module utile et très bonne approche. Joli travail !
#2
Nicolas Le 06/07/2010 à 21:12
C'est un petit probleme pour moi

Quand flat catalog product et flat catalog category est vrai.

erreur

SELECT 1 AS `status`, `e`.`entity_id`, `e`.`type_id`, `e`.`attribute_set_id`, `e`.`price`, `e`.`special_price`, `e`.`special_from_date`, `e`.`special_to_date`, `e`.`name`, `e`.`description`, `e`.`short_description`, `e`.`price`, `e`.`special_price`, `e`.`special_from_date`, `e`.`special_to_date`, `e`.`image`, `e`.`small_image`, `e`.`thumbnail`, `e`.`news_from_date`, `e`.`tax_class_id`, `e`.`url_key`, `e`.`required_options`, `e`.`price_type`, `e`.`weight_type`, `e`.`price_view`, `e`.`shipment_type`, `e`.`image_label`, `e`.`small_image_label`, `e`.`thumbnail_label`, `e`.`batch_qty`, `e`.`homeselection`, `e`.`is_serial_number`, `e`.`warranty`, `e`.`enablesalecount`, `e`.`display_price_group_0` AS `_rule_price` FROM `catalog_product_flat_1` AS `e`
INNER JOIN `catalog_product_enabled_index` AS `enabled_index` ON enabled_index.product_id=e.entity_id AND enabled_index.store_id='1' AND enabled_index.visibility IN (2, 4) WHERE (e.entity_id = '0') ORDER BY `position` asc LIMIT 4
#3
Magentix Le 06/07/2010 à 22:09
J'ai essayé mode flat activé, cela ne pose aucun problème... La requête générée semble correct. Lorsque vous exécutez cette requête en base quelle est l'erreur retournée ?

I tried when flat mode enabled, and no problem... The generated query looks fine. When you run this query in database what is the error returned ?
#4
Laurent Le 08/07/2010 à 14:53
Bonjour,

Petite question impertinente ;)
Je souhaite installer ce module sur un site en cours de développement...donc bien entendu aucune commande n'a été passée à l'heure actuelle ! Comment vérifier le fonctionnement et accessoirement travailler sur le gabarit ?

Merci
#5
Nicola Le 08/07/2010 à 16:00
I see my french is terrible :).

The problem is magento 1.3.1. I fixed the problem by updating Catalog and CatalogIndex in the core files to 1.3.2.4.

Great solution.

Thanks
#6
Magentix Le 08/07/2010 à 16:05
@Laurent : Vous pouvez modifier les filtres sur la collection de produits dans le fichier "app/code/local/Magentix/AlsoBought/Model/Bought.php"

Par exemple :
$products = Mage::getResourceModel('catalog/product_collection')->addAttributeToFilter('entity_id',array(1));

Cela récupérera le produit dont l'Identifiant (ID) est 1
#7
Laurent Le 08/07/2010 à 18:07
Merci bcp pour votre rapidité et l'astuce, c'est super :)
#8
Laurent Le 08/07/2010 à 18:28
@Magentix

Merci !
#9
Nicolas Le 13/07/2010 à 23:56
C'est possible pour un autre filtre? Parce que j'ai les magasins de multple. Vente en gros est une grande probleme pour moi.

Par exemple:
->addStoreFilter($storeId) ;

Merci

Nicholas
#10
Magentix Le 28/09/2010 à 11:38
Petit bug détecté par Dn'D sur le module ;)
L'extension posera problème sur un site dont les tables de la base comporte un préfixe. Je corrige çà prochainement.
#11
Nicolas Le 25/10/2010 à 23:47
Old new.... to fix the multiple store prombleme

$storeId = Mage::app()->getStore()->getId();

$this->_itemCollection->addAttributeToSort('position','asc')->addStoreFilter($storeId);
#12
Nicolas Le 28/10/2010 à 16:44
Actually, the above code only works 88% of the time.

$storeId = $this->helper('core')->getStoreId();

This now works all the time and stops the URLS from mixing between stores.
#13
Magentix Le 28/10/2010 à 16:47
Nicolas, thank you for the contribution, I had forgotten to manage multiple stores
#14
Stéphane Le 15/12/2010 à 11:18
Bonjour,

il semble que cette extension soit buguée. Voici le message d'erreur généré :

exception 'Mage_Core_Exception' with message 'Invalid block type: ' in /chroot/home/glow/glow/html/app/Mage.php:550
Stack trace:
#0 /chroot/home/glow/glow/html/app/code/core/Mage/Core/Model/Layout.php(469): Mage::throwException('Invalid block t...')
#1 /chroot/home/glow/glow/html/app/code/core/Mage/Core/Model/Layout.php(411): Mage_Core_Model_Layout->_getBlockInstance('', Array)
#2 /chroot/home/glow/glow/html/app/code/core/Mage/Core/Model/Layout.php(446): Mage_Core_Model_Layout->createBlock('', 'product.info')
#3 /chroot/home/glow/glow/html/app/code/core/Mage/Core/Model/Layout.php(238): Mage_Core_Model_Layout->addBlock('', 'product.info')
#4 /chroot/home/glow/glow/html/app/code/core/Mage/Core/Model/Layout.php(204): Mage_Core_Model_Layout->_generateBlock(Object(Mage_Core_Model_Layout_Element), Object(Mage_Core_Model_Layout_Element))
#5 /chroot/home/glow/glow/html/app/code/core/Mage/Core/Model/Layout.php(209): Mage_Core_Model_Layout->generateBlocks(Object(Mage_Core_Model_Layout_Element))
#6 /chroot/home/glow/glow/html/app/code/core/Mage/Core/Controller/Varien/Action.php(343): Mage_Core_Model_Layout->generateBlocks()
#7 /chroot/home/glow/glow/html/app/code/core/Mage/Catalog/controllers/ProductController.php(115): Mage_Core_Controller_Varien_Action->generateLayoutBlocks()
#8 /chroot/home/glow/glow/html/app/code/core/Mage/Catalog/controllers/ProductController.php(149): Mage_Catalog_ProductController->_initProductLayout(Object(Mage_Catalog_Model_Product))
#9 /chroot/home/glow/glow/html/app/code/core/Mage/Core/Controller/Varien/Action.php(418): Mage_Catalog_ProductController->viewAction()
#10 /chroot/home/glow/glow/html/app/code/core/Mage/Core/Controller/Varien/Router/Standard.php(254): Mage_Core_Controller_Varien_Action->dispatch('view')
#11 /chroot/home/glow/glow/html/app/code/community/ArtsOnIT/OfflineMaintenance/Controller/Router/Standard.php(46): Mage_Core_Controller_Varien_Router_Standard->match(Object(Mage_Core_Controller_Request_Http))
#12 /chroot/home/glow/glow/html/app/code/core/Mage/Core/Controller/Varien/Front.php(177): ArtsOnIT_OfflineMaintenance_Controller_Router_Standard->match(Object(Mage_Core_Controller_Request_Http))
#13 /chroot/home/glow/glow/html/app/code/core/Mage/Core/Model/App.php(304): Mage_Core_Controller_Varien_Front->dispatch()
#14 /chroot/home/glow/glow/html/app/Mage.php(596): Mage_Core_Model_App->run(Array)
#15 /chroot/home/glow/glow/html/index.php(78): Mage::run('', 'website')
#16 {main}


Pas encore trouvé le moyen de fixer çà de mon côté.
#15
Leslee Le 18/12/2010 à 09:35
Sorry my French is terrible so I'm not even going to try. :)

Magento says this costs $1 but I don't see a buy button?

Does this app not come with an extension key?? I am not very technical and would not have the first idea of how to install it without one.

Please help!

regards
Leslee
#16
Magentix Le 18/12/2010 à 11:43
The extension is free ;). You can download it by clicking on "Extension AlsoBought" link (top right).
#17
Leslee Le 19/12/2010 à 21:42
Thank you for the quick reply I did see that and downloaded it but I am still confused - where do I find the Extension key so I can install it?

Sorry to be a pain.

Merci
Leslee
#18
tnntwister Le 21/12/2010 à 17:51
Superbe extensiontuto ! merci beaucoup !

apparemment la table sales_flat_order_item n'existe pas encore sur mon magento de développement : SQLSTATE[42S02]: Base table or view not found...

Il n'y a pas encore de commandes... faut il que je crée des commandes pour que ca marche ?
#19
Magentix Le 21/12/2010 à 17:56
Oui, essayez de passer au moins une commande, bien que normalement cela ne doit pas poser de problème. Si vous avez des extensions sur les noms des tables (ex : ms_sales_flat_order_item) cette erreur peut apparaître. Je n'ai pas utilisé "getTable" dans le code...
#20
tnntwister Le 22/12/2010 à 08:39
j'ai rajouté mon préfixe et effectivement l'erreur a disparu... super ! :)
#21
Florian Le 22/01/2011 à 02:21
Hi Magentix-Team and thank you very much for this great extention!

I would like to suggest a change, to make the choice of the related products a little better. Instead of having an "X" showing the relation, why dont we use a number, that is increased every time, the combination is bought? Then we can select the product-combination with the highest number an get the best results, right?

I dont know, how to do it, but if anybody knows a way, please let me know!

Thanks a lot,
Florian
#22
Steven Le 07/04/2011 à 09:43
Hi Magentix-Team,

I'm sorry fo my terrible French.

Thank you very much for this great extention!

I have installed it and it appears in the System/Configuration/Adanced. But I don't know where to set it to appear in the Products' Page. I have placed several orders with the different products, but the 'Also Bought' doesn't show anymore.

So could you please help me about it?

Thanks!
#23
loewenstark.de Le 20/04/2011 à 12:45
Works great on Magento 1.5.0.1 :) but i have to change the "layout/alsobought.xml", because the block "product.info" exists.

So i have changed the reference to "<reference name="product.info">" and added "<?php echo $this->getChildHtml('alsobought_products') ?>" to "template/catalog/product/view.phtml" and it works great :)
#24
tobias barthel Le 29/04/2011 à 13:32
Merci bien c'est extension!!!

Nous avons installer l' extension dans notre shop en Allemagne mais nous savon pas comme un peut activer?

My french is not that good to read an IT instruction. Do you have anything in english for us you to activate the module?

Thanks and greetings from Germany
#25
tobias barthel Le 11/05/2011 à 09:59
Hi, I really need support to activate the installed modul in our shop...

Any body an idea why it does not activate?

Greets
#26
Nicolas Le 31/05/2011 à 15:13
After a year of using this product, it works great.

The only problem there is now is the Cache.

When changing store views, changing currencies. The cached information is retrieved and therefore no update on price or store is updated and so it produces some strange results.
#27
Andreas von Studnitz Le 14/06/2011 à 22:19
The module works perfectly in Magento Enterprise 1.9 too. Merci beaucoup!
#28
Nicolas Le 15/06/2011 à 01:36
To fix the above problem, uupdate the following with caching currency, use the following in block.php

protected function _construct() {
$product = Mage::registry('product');

$this->addData(array(
'cache_lifetime' => 900,
'cache_tags' => array(Mage_Catalog_Model_Product::CACHE_TAG),
'cache_key' => $this->getCacheKey()
));
}

public function getCacheKey()
{
return $this->getRequest()->getRequestUri().$this->getCacheCurrencyCode();
}

//retreive current currency code
public function getCacheCurrencyCode()
{
return Mage::app()->getStore()->getCurrentCurrencyCode();
}
#29
Rédiger un commentaire

Cliquez pour générer un nouveau code

* champs obligatoires