Fragmented Thought

Setting Product Attributes From Text Descriptions in Magento



Lance Gliser

Heads up! This content is more than six months old. Take some time to verify everything still works as expected.

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:

/** * Loops through products finding attribute values * in titles and descriptions and setting that value in real attributes */ public function loadProductAttributesAction(){ print '<h1>loadProductAttributesAction</h1>'; set_time_limit(0); // Load products. Note this might hit a size limit $products = Mage::getModel('catalog/product')->getCollection(); $i = 0; $products_updated = array(); $products_not_updated = array(); foreach($products as $product_preview) { $i++; // Load the full product from the collection's shallow copy $product = Mage::getModel('catalog/product')->load($product_preview->getId()); // Store the text of the product into a data array $data = array(); $data['name'] = $product->getName(); $data['sku'] = $product->getSku(); $data['description'] = $product->getDescription(); $data['meta_keywords'] = $product->getMetaKeyword(); // Create a searchable data glob out of the data $string = implode(' ', $data); // Create a variable to store attribute value updates for tracking purposes $updates = array(); // Load the product's attributes $attributes = $product->getAttributes(); foreach( $attributes as $attribute_id => $attribute ){ switch( $attribute_id ){ // For our specific attributes case 'color': // Get the product options (ignore the 'please select') $options = $attribute->getSource()->getAllOptions(false, false); $matches = array(); foreach( $options as $option ){ if( stripos($string, $option['label']) !== FALSE ){ // Add this to the product update matches $updates[$attribute_id] = $option; // Break, we can only record single values into attributes anyway break; } } break; } } // Make the updates and add to reporting structures if( empty($updates) ){ $products_not_updated[] = array( 'sku' => $product->getSku(), 'name' => $product->getName(), ); } else { // Loop through the updates saving the product's attributes foreach($updates as $attribute_id => $option){ $product->setData($attribute_id, $option['value'])->getResource()->saveAttribute($product, $attribute_id); } $products_updated[] = array( 'sku' => $product->getSku(), 'name' => $product->getName(), 'updates' => $updates, ); } } print '<h2>' . $i . ' products processed.</h2>'; // Loop through the reporting structures for output print '<h3>Updated products</h3>'; $i = 0; foreach( $products_updated as $details ){ $i++; print '<h4>' . $i . ': ' . $details['name'] . ' (' . $details['sku'] . ')</h4>'; print '<p>Updates made:</p><ul>'; foreach( $details['updates'] as $attribute_id => $option ){ print '<li>"' . $attribute_id . '" set to ' . $option['label'] . '</li>'; } print '</ul>'; } print '<h3>Skipped products</h3><ol>'; foreach( $products_not_updated as $details ){ print '<li>' . $details['name'] . ' (' . $details['sku'] . ')</li>'; } print '</ol>'; }

Happy coding.