Magento – Products from a category plus any children and get category ID for conditions from collection

collection;magento-1.9product-collection

I'm building a collection for a CSV generator and I need to be able to only get products from a category and any children of it (or if I really have to, just all category ID's in an array) but from that collection, I need to then output specific names based on the category (for CSV category mapping to a 3rd party system).

I've tried countless variations but not successfully managed to achieve what I am after (so I've stripped it right back to start afresh as it was getting pretty confusing).

An example of category structure is:-

Parent Category (Ladies) - id 3
    Child Category (Trousers) - id 10
    Child Category (Shoes & Accessories) - id 11
    Child Category (Jewellery) - id 12
    Child Category (Coats & Jackets) - id 6
    Child Category (Knitwear) - id 7
    Child Category (Tops) - id 8
    Child Category (Skirts & Dresses) - id 9

So in this example, all products in any of these child categories are also in the parent category 'Ladies'.

Here is the product collection:-

// get all configurable products that are enabled and visible in search and/or catalog
$collection = Mage::getModel('catalog/product')
    ->getCollection()
    ->joinField('category_id', 'catalog/category_product', 'category_id', 'product_id = entity_id', null, 'left')
    ->addAttributeToSelect('*')
    ->distinct(true)
    //->addIdFilter($category->getChildren())
    ->addAttributeToFilter('type_id', array('eq' => 'configurable'))
    ->addAttributeToFilter('visibility', array('in' => array(Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH, Mage_Catalog_Model_Product_Visibility::VISIBILITY_IN_SEARCH, Mage_Catalog_Model_Product_Visibility::VISIBILITY_IN_CATALOG)))
    ->addAttributeToFilter('status', array('eq' => Mage_Catalog_Model_Product_Status::STATUS_ENABLED))
    ->addStoreFilter($storeId);
$collection->getSelect()->group('e.entity_id'); //prevents duplicate products in collection

If I load the product collection from the parent category ID however like so…

$category = Mage::getModel('catalog/category')->load(3); // 3 is category id

… then when I try to fetch category data from the collection, everything just returns information from the parent category.

What I need to do is not only build the collection from products in any of these child categories but also get the child category data that the product belongs to so I can conditionally output specific labels/names for mapping, for example:-

// build the category names for mapping
if ($category->getId()==10) {
    $cmap = 'Clothing > Trousers';
}

Which returns NULL of course if I load the collection by parent category (id 3).

Should I be trying to build the collection of products from the child categories and then getting the child category data or actually building a separate collection for the categories?

If I try to filter by category_id using the below for example, this doesn't seem to make any difference at all (and loads products from any categories still):-

->addAttributeToFilter('category_id', array('in' => array('6','7')))

Later in the script we loop through the products and also get the associated products so we can fetch sizes/colours etc:-

foreach ($collection as $product) {
    //get associated products (different sizes etc)
    $associatedProducts = Mage::getModel('catalog/product_type_configurable')->getUsedProducts(null,$product);

    foreach ($associatedProducts as $simple) {
        //load product
        $simple_product = Mage::getModel('catalog/product')->load($simple->getId());

        //output to CSV
        //etc etc

    }
}

So to summarise, I just need to be able to load products from specific categories and then extract the child category ID (it is only the ID I require) from the collection.

Best Answer

Okay, so I'm actually getting somewhere by building a completely different collection...

$category_id = 3;
$collection = Mage::getModel('catalog/category')->load($category_id)
    ->getProductCollection()
    ->addAttributeToSelect('*') // add all attributes - optional
    ->addAttributeToFilter('type_id', array('eq' => 'configurable'))
    ->addAttributeToFilter('visibility', array('in' => array(Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH, Mage_Catalog_Model_Product_Visibility::VISIBILITY_IN_SEARCH, Mage_Catalog_Model_Product_Visibility::VISIBILITY_IN_CATALOG)))
    ->addAttributeToFilter('status', array('eq' => Mage_Catalog_Model_Product_Status::STATUS_ENABLED))
    ->addStoreFilter($storeId);

And then fetch the category ID's from the loaded products:-

$cats = $product->getCategoryIds();

And loop through (as @paj suggested in the comments) to get the category data for each:-

foreach ($cats as $category_id) {
        $category = Mage::getModel('catalog/category')->setStoreId(Mage::app()->getStore()->getId())->load($category_id);             
    }

I'm then able to get what I want for each product like:-

$category->getId()
$category->getName()

Meaning my required mapping works well:-

if ($category->getId()==10) {
    $cmap = 'Clothing > Trousers';
}