Setting Product Attributes From Text Descriptions in Magento

A client of mine recently started wanting to improve her shopping experience with Magento. Her site was initially imported 100% description based, with attributes barely used at all. After walking her through layered navigation's filters, she immediately understood the value. It can help with SEO as well, as you can noindex the extra urls produced by filters more easily than discounting loads of categories. She's off happily categorizing her product data into attributes and options below them. It'll be my job to search the text of all her products and set the product's attributes based on them. Here's the start of that work.

Note that this is going to be widely simplistic, and includes only a single attribute code. There's a lot of use cases where this will fail, and I leave that up to the brave developer to sort out (or hire me). But here's the gist, taken from my local environment's scratch controller:

  1. /**
  2.    * Loops through products finding attribute values
  3.    * in titles and descriptions and setting that value in real attributes
  4.    */
  5.   public function loadProductAttributesAction(){
  6.     print '<h1>loadProductAttributesAction</h1>';
  7.     set_time_limit(0);
  8.     // Load products. Note this might hit a size limit
  9.     $products = Mage::getModel('catalog/product')->getCollection();
  10.     $i = 0;
  11.     $products_updated = array();
  12.     $products_not_updated = array();
  13.     foreach($products as $product_preview) {
  14.       $i++;
  15.       // Load the full product from the collection's shallow copy
  16.       $product = Mage::getModel('catalog/product')->load($product_preview->getId());
  17.       // Store the text of the product into a data array
  18.       $data = array();
  19.       $data['name'] = $product->getName();
  20.       $data['sku'] = $product->getSku();
  21.       $data['description'] = $product->getDescription();
  22.       $data['meta_keywords'] = $product->getMetaKeyword();
  23.       // Create a searchable data glob out of the data
  24.       $string = implode('  ', $data);
  25.  
  26.       // Create a variable to store attribute value updates for tracking purposes
  27.       $updates = array();
  28.      
  29.       // Load the product's attributes
  30.       $attributes = $product->getAttributes();
  31.       foreach( $attributes as $attribute_id => $attribute ){
  32.         switch( $attribute_id ){
  33.           // For our specific attributes
  34.           case 'color':
  35.             // Get the product options (ignore the 'please select')
  36.             $options = $attribute->getSource()->getAllOptions(false, false);
  37.             $matches = array();
  38.             foreach( $options as $option ){
  39.               if( stripos($string, $option['label']) !== FALSE ){
  40.                 // Add this to the product update matches
  41.                 $updates[$attribute_id] = $option;
  42.                 // Break, we can only record single values into attributes anyway
  43.                 break;
  44.               }              
  45.             }
  46.             break;
  47.         }
  48.       }
  49.      
  50.       // Make the updates and add to reporting structures
  51.       if( empty($updates) ){
  52.         $products_not_updated[] = array(
  53.           'sku' => $product->getSku(),
  54.           'name' => $product->getName(),
  55.         );
  56.       } else {
  57.         // Loop through the updates saving the product's attributes
  58.         foreach($updates as $attribute_id => $option){
  59.           $product->setData($attribute_id, $option['value'])->getResource()->saveAttribute($product, $attribute_id);
  60.         }
  61.         $products_updated[] = array(
  62.           'sku' => $product->getSku(),
  63.           'name' => $product->getName(),
  64.           'updates' => $updates,
  65.         );
  66.       }
  67.     }
  68.     print '<h2>' . $i . ' products processed.</h2>';
  69.     // Loop through the reporting structures for output
  70.     print '<h3>Updated products</h3>';
  71.     $i = 0;
  72.     foreach( $products_updated as $details ){
  73.       $i++;
  74.       print '<h4>' . $i . ': ' . $details['name'] . ' (' . $details['sku'] . ')</h4>';
  75.       print '<p>Updates made:</p><ul>';
  76.       foreach( $details['updates'] as $attribute_id => $option ){
  77.         print '<li>"' . $attribute_id . '" set to ' . $option['label'] . '</li>';
  78.       }
  79.       print '</ul>';
  80.     }
  81.     print '<h3>Skipped products</h3><ol>';
  82.     foreach( $products_not_updated as $details ){
  83.       print '<li>' . $details['name'] . ' (' . $details['sku'] . ')</li>';
  84.     }
  85.     print '</ol>';
  86.   }

Happy coding.

Tags: 

Add new comment

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
By submitting this form, you accept the Mollom privacy policy.