Set Visibility on Storeview Scope for 25k Products and 28 Storeviews

attributesperformancestore-view

I need to change the visibility of 25k products in 28 storeviews.

My first solution works, but is unbearably (10+ minutes for 50- products) slow because of the save()-call. The $brandsToStoreViewIds var is just a mapping of the brand to different storeviews (where it should be visible or not).

Mage::app()->setCurrentStore( Mage_Core_Model_App::ADMIN_STORE_ID );

$products = Mage::getModel('catalog/product')->getCollection()->addAttributeToSelect( 'brand');

foreach( $products as $product ) {
    foreach( $brandsToStoreViewIds as $brand => $storeViewIds ) {
        if( $brand != $product->getAttributeText( 'brand' ) ) {
            foreach( $storeViewIds as $storeViewId ) {
                $product->setStoreId( $storeViewId )->setVisibility( Mage_Catalog_Model_Product_Visibility::VISIBILITY_NOT_VISIBLE )->save();
            }
        }
    }
}

So i tried to do the same with $product->getResource()->saveAttribute( $product, 'store_id' ):

Mage::app()->setCurrentStore( Mage_Core_Model_App::ADMIN_STORE_ID );

$products = Mage::getModel('catalog/product')->getCollection()->addAttributeToSelect( 'brand');

foreach( $products as $product ) {
    foreach( $brandsToStoreViewIds as $brand => $storeViewIds ) {
        if( $brand != $product->getAttributeText( 'brand' ) ) {
            foreach( $storeViewIds as $storeViewId ) {
                $product->setStoreId( $storeViewId )->setVisibility( Mage_Catalog_Model_Product_Visibility::VISIBILITY_NOT_VISIBLE );
                $product->getResource()->saveAttribute( $product, 'store_id' );
                $product->getResource()->saveAttribute( $product, 'visibility' );
            }
        }
    }
}

This is supposed to be much faster, but i get the following fatal error:

Fatal error: Call to a member function getBackend() on a non-object in /app/code/core/Mage/Eav/Model/Entity/Abstract.php on line 1536

I think i need to prepare/manipulate the collection so that the store_id can be saved, but do not really know how to achieve this.

Maybe there is an even easier way to hide certain products from storeviews and i'm doing it completely wrong?

Best Answer

You can use the mass attribute update action for that.

// get the products using a collection
$collection = Mage::getResourceModel('catalog/product_collection');
$product_ids = $collection->getAllIds();

// mass update per store view
$action = Mage::getModel('catalog/resource_product_action');
$storeview_ids = array(1,2,3,...);

foreach ($storeview_ids as $storeid)
{
   $action->updateAttributes($product_ids, array(
      'visibility' => Mage_Catalog_Model_Product_Visibility::VISIBILITY_NOT_VISIBLE
   ), $storeid);
}
Related Topic