This is actually a feature. If you want to avoid this you should set the flag 'Is anchor' to 'No' on the parent category. In your example 'Clothing'. This way, in the parent category you will see only products directly assigned to it.
After you do the changes you should re-index everything.
Hi I Know it is a late reply but it may help some other magento api developers.
protected function _create($data){
$typeid = $data['categoryId'];
$userid = $data['userId'];
$pagesize = $data['limit'];
$pageno = $data['page'];
Mage::app()->setCurrentStore(1);
Mage::app('default');
Mage::getSingleton("core/session", array("name" => "frontend"));
$websiteId = Mage::app()->getWebsite()->getId();
$store = Mage::app()->getStore();
try
{
$layer = Mage::getModel("catalog/layer");
$category = Mage::getModel('catalog/category')->load($typeid);
Mage::register('current_category', $category);
Mage::register('current_entity_key', $category->getPath());
$layer->setCurrentCategory($category);
$products = $layer->getProductCollection()->addAttributeToSelect('*');
if($pageno==1){
$filter=array();
$attributes = $layer->getFilterableAttributes();
$min_price = $layer->getProductCollection()->getMinPrice();
$max_price = $layer->getProductCollection()->getMaxPrice();
$price['minPrice']=$min_price;
$price['maxPrice']=$max_price;
$json['priceRange']=$price;
$json['priceRangeApplied']=$price;
$json['attributes'] = array();
foreach ($attributes as $attribute) {
if ($attribute->getAttributeCode() == 'price') {
$filterBlockName = 'catalog/layer_filter_attribute';
} elseif ($attribute->getBackendType() == 'decimal') {
$filterBlockName = 'catalog/layer_filter_decimal';
} else {
$filterBlockName = 'catalog/layer_filter_attribute';
}
$result = Mage::app()->getLayout()->createBlock($filterBlockName)->setLayer($layer)->setAttributeModel($attribute)->init();
if(array_key_exists($attribute->getAttributeCode(),$data['filters'])){
foreach($result->getItems() as $option) {
if(in_array($option->getValue(),explode(',',$data['filters'][$attribute->getAttributeCode()]))){
$count[] = array('optionId' => $option->getValue(), 'optionLabel' => $option->getLabel(),'selected'=>true);
}else {
$count[] = array('optionId' => $option->getValue(), 'optionLabel' => $option->getLabel(),'selected'=>false);
}
}
}else{
foreach($result->getItems() as $option) {
$count[] = array('optionId' => $option->getValue(),'optionLabel' => $option->getLabel(),'selected'=>false);
}
}
if(count($count)>=1){
$json['attributes'][] = array('attributeCode'=>$attribute->getAttributeCode(),'attributeLabel'=>ucfirst($attribute->getFrontend_label()),'attributeValues'=>$count);
}
unset($count);
}
}
$minprice=0;
$maxprice=0;
if(array_key_exists('filters',$data)){
foreach ($data['filters'] as $key=>$item) {
$itemss=array();
if($key=='price'){
$priceRanges =explode(',',$item);
foreach($priceRanges as $priceRange) {
$pricelimit = explode('-',$priceRange);
$minprice = $pricelimit[0];
$maxprice = $pricelimit[1];
}
}
else{
$itemss=explode(',',$item);
$attribute = Mage::getModel('eav/entity_attribute')->loadByCode('catalog_product', $key);
$connection = Mage::getSingleton('core/resource')->getConnection('core_read');
$tableAlias = $attribute->getAttributeCode() . '_idx';
$conditions = array(
"{$tableAlias}.entity_id = e.entity_id",
$connection->quoteInto("{$tableAlias}.attribute_id = ?",
$attribute->getAttributeId()),
$connection->quoteInto("{$tableAlias}.store_id = ?", 1),
$connection->quoteInto("{$tableAlias}.value IN (?)", $itemss)
);
$products->getSelect()->join(
array($tableAlias => Mage::getResourceModel('catalog/layer_filter_attribute')->getMainTable()),
implode(' AND ', $conditions),
array()
);
}
}
$products->addFinalPrice();
if($minprice!=0&&$maxprice!=0) {
$products->getSelect()
->where('price_index.final_price <= ' . $maxprice)->where('price_index.final_price >= ' . $minprice);
$price['minPrice']=(int)$minprice;
$price['maxPrice']=(int)$maxprice;
$json['priceRangeApplied']=$price;
}
}
$totalproducts=$products->getSize();
if($pagesize&&$pageno){
$products->setPageSize($pagesize)
->setCurPage($pageno);
}
$i=0;
$flag=0;
$response = array();
foreach($products as $result3){
$response[$i] = array('productId'=>$result3->getId(),'productName'=>$result3->getName(),'productPrice'=>$result3->getPrice());//give what ever values you need.
$i++;
}
$bestprodts = $response;
$noofpages = $totalproducts/$pagesize;
$result = array();
$result['status'] = 1;
if(!$totalproducts){
if($min_price==0&&$max_price==0){
$result['message']='No products available in this category.';
}else{
$result['message']='No products found. Please check the filter.';
}
}else{
$result['message']='Success';
}
$result['noofpages']=ceil($noofpages);
$result['totalProducts']=$totalproducts;
$result['data']['productList']=$bestprodts;
if($pageno==1){
$result['data']['filters']=$json;
}
}
catch(Exception $e)
{
$result = array();
$result['status'] = 2;
$result['message'] = "Product Listing failed";
}
echo json_encode($result);
return json_encode($result);
}
Request Format {
"categoryId":"",
"limit":"",
"page":"",
"filters":{
"price":"from-to",
"attribute_code":"values "
}
}
Best Answer
About a year later, Magento naturally has evolved and the
Magento\Catalog\Api\CategoryListInterface
can now be used.It works great, I can do stuff like this:
mpw's answer is useful as well and is supported by Magento, but my question was aiming for a service contract method.