7

I'm trying to get 4 random products on the homepage using PHP within a TPL file I've created. I'd like to be able to format the products in a foreach loop as I'm using some formatting in the code seen below...

<div class="three columns">
  <div class="product_container no_border">
    <div class="product">
      <a href="product_page.html"><img src="<?php echo $this->getSkinUrl('images/products/place_holder.jpg'); ?>" alt=" "></a>
    </div>

    <div class="product_title">
      <a href="product_page.html">240 Serving Package</a>
    </div>

    <div class="price_hp">$454.99</div>

    <div class="free_shipping">
      <div class="fs"></div>
      Free shipping for this package
    </div>

    <div class="shop_btn">
      <a href="#">ADD TO CART</a>
    </div>
  </div>
</div>

I've tried a few things found on Google but no luck yet. Setting categories in an array would certainly work for what I'm trying to do but it'd also work if the categories were random.

Thanks!

3 Answers 3

9

Try this. I worked for me:

$products = Mage::getModel('catalog/product')->getCollection();
$products->addAttributeToSelect(array('name', 'thumbnail', 'price')); //feel free to add any other attribues you need.
Mage::getSingleton('catalog/product_status')->addVisibleFilterToCollection($products);
Mage::getSingleton('catalog/product_visibility')->addVisibleInCatalogFilterToCollection($products); 
$products->getSelect()->order('RAND()');
$products->getSelect()->limit(4);
foreach ($products as $product)  : ?>

<div class="three columns">
  <div class="product_container no_border">
    <div class="product">
      <a href="<?php echo $product->getProductUrl()?>"><img src="<?php echo Mage::helper('catalog/image')->init($product, 'thumbnail')->resize(100, 80)?>" alt=""></a>
    </div>

    <div class="product_title">
      <a href="<?php echo $product->getProductUrl()?>"><?php echo $product->getName()?></a>
    </div>

    <div class="price_hp"><?php echo Mage::app()->getStore()->getCurrentCurrency()->format($product->getFinalPrice());?></div>

    <div class="free_shipping">
      <div class="fs"></div>
      Free shipping for this package
    </div>

    <div class="shop_btn">
      <a href="<?php echo Mage::helper('checkout/cart')->getAddUrl($product)?>">ADD TO CART</a>
    </div>
  </div>
</div>
<?php 
endforeach;?>
5
  • Hey Marius! This worked -- thank you so much! Could you tell me (possibly) why the add to cart button isn't working though? The demo is available at dev.wisefoodsupply.com Commented May 2, 2013 at 19:12
  • actually nothing works except the home page. You have no execution rights on index.php. At least that's what the error message says.
    – Marius
    Commented May 2, 2013 at 19:18
  • 2
    Don't use ORDER BY RAND() on a large catalog, it has performance issues Commented Aug 14, 2015 at 8:37
  • I'm not going to edit your post, but can you pls check Mage::getSingleton('catalog/product_status')->addVisibleFilterToCollection($products);? Seems to do nothing.
    – sv3n
    Commented Feb 25, 2018 at 18:19
  • It used to do something 5 years ago.... I think.
    – Marius
    Commented Feb 25, 2018 at 21:36
4

Create Block For Random Products

You should create a custom module with a new block type. I'd recommend to extend Mage_Catalog_Block_Product_List, then if the default product list layout suffices for you, you don't even need to design your own template.

Then override _getProductCollection() or if you don't extend Mage_Catalog_Block_Product_list write a new public method getProductCollection().

How to prepare the product collection in this method:

Collection Filter

First, create the collection and apply the standard filter (visible in catalog and available in current store):

$productCollection = Mage::getModel('catalog/product')->getCollection();
$productCollection
    ->addStoreFilter()
    ->setVisibility(Mage::getSingleton('catalog/product_visibility')->getVisibleInCatalogIds());

Performant Random Selection

ORDER BY RAND() is unperformant on large tables because it results in a resource intensive temp table copy. It has to load all results into a temporary table, assign a random number to each row and then sort without any index. Instead we retrieve all ids (this is faster and the amount of data is managable even for large catalogs), pick some randomly and retrieve these rows directly.

To do so, insert this code after the filters for the collection have been applied:

$numberOfItems = 4;
$candidateIds = $productCollection->getAllIds();

$choosenIds = [];
$maxKey = count($candidateIds)-1;
while (count($choosenIds) < $numberOfItems)) {
  $randomKey = mt_rand(0, $maxKey);
  $choosenIds[$randomKey] = $candidateIds[$randomKey];
}

$productCollection->addIdFilter($choosenIds);

You can read about it in detail in my blog: http://www.schmengler-se.de/en/2015/09/show-random-products-in-magento-you-are-doing-it-wrong/

Retrieve Necessary Attributes

Then, we specify the attributes to be loaded and join price and URL indexes to be able to show the right price and product URL:

$productCollection
    ->addMinimalPrice()
    ->addFinalPrice()
    ->addTaxPercents()
    ->addAttributeToSelect(Mage::getSingleton('catalog/config')->getProductAttributes())
    ->addUrlRewrite();

Last but not least, return the collection:

return $productCollection;

This collection can now be used in Mage_Catalog_Block_Product_List blocks or in your own template with foreach ($this->getProductCollection() as $product) like in Marius' answer.


Insert Custom Block In CMS

Use this code to insert the block in your home page, with your/block being the alias for your block class:

{{block type="your/block" name="random_products" template="catalog/product/list.phtml" column_count="4"}}

Specify your own template if needed. column_count is used by Mage_Catalog_Block_Product_List.


Notes

  1. Alternatively you could put all the PHP code from above in your template but this is quite messy and violates Magento's coding standards and best practices.

  2. Apparently Magento comes with its own predefined block type catalog/product_list_random, but it uses order('rand()'), so I won't recommend it for the performance reasons explained above.

0

You could try to load the whole product collection in a custom Block and use array_rand to pick out the 5 IDs that are returned to the TPL file.

http://php.net/manual/en/function.array-rand.php

1
  • 3
    this is not a good idea. what if you have 30k products? Actually the listing of random products is not a good idea but if you have to do it, loading the full collection is not the way to go.
    – Marius
    Commented May 2, 2013 at 19:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.