Based on what you've said I'm making the following assumptions
- The tasks requirements prevent you from editting or replacing templates.
- You aren't limited to just using observers and you can override existing classes as long as it is unlikely to require code changes after the module is installed.
Given that these requirements restrict you (more or less) to using the regex approach that you've already set up. We'll need to find some unique value in the product's list item to key off of in order to get product specific information. Normally the item id would be available in the add to cart url, but that isn't the case when a product has required options.
So if you look at the add to cart button that the user will be clicking, you can see that there are only two methods used. One is translate function which is not at all exclusive to the add cart button. The other is getAddToCartUrl()
(documentation here: http://docs.magentocommerce.com/Mage_Catalog/Mage_Catalog_Block_Product_Abstract.html#methodgetAddToCartUrl). I'm not completely certain that this is exclusive to the add to cart buttons, so testing it thoroughly is a good idea.
Now that we've found the getAddToCartUrl
method in the button we want to conditionally remove, and (bonus) it already receives the product object as one of its parameters.
Now we'll want to create a module that rewrites that method. We don't need to change the entire class, so setting up the proper config values and extending the existing class should allow us to have a minimal impact.
Since the change we're looking for only needs to happen on the search pages, I'd suggest wrapping the change in an if block that is specific that controller/action. (how to get those values: http://blog.chapagain.com.np/magento-how-to-get-controller-action-and-module-name-in-template-file/)
Now that we have access to the product object as a parameter of the getAddToCartUrl
and it's wrapped in a condition that only applies the change to the search results page, we just need to write logic to see what category that product belongs to and check if the add to cart button should be visible.
If the result of our logic says that the button should be hidden, we just need to make the method return a unique string that we can easily find with regex and hide the button when that string is found.
TL;DR
Try editing the getAddToCartUrl
method to output something that tells the regex function that's already in place to remove the button.
I tried some thing and it is working fine for me, i am sharing code hope this might be useful for someone else or one can suggest me the better approach.
In mage\app\design\frontend\your-design-package\default\template\catalog\product\list.phtml
Replace the following code
<?php if($_product->isSaleable()): ?>
<button type="button" title="<?php echo $this->__('Add to Cart') ?>" class="button btn-cart" onclick="setLocation('<?php echo $this->getAddToCartUrl($_product) ?>')"><span><span><?php echo $this->__('Add to Cart') ?></span></span></button>
<?php else: ?>
with
<?php if($_product->isSaleable()): ?>
<form class="product_addtocart_form" action="<?php echo $this->getSubmitUrl($_product) ?>" method="post" id="product_addtocart_form_<?php echo $counter; ?>"<?php if($_product->getOptions()): ?> enctype="multipart/form-data"<?php endif; ?>>
<?php echo $this->getBlockHtml('formkey') ?>
<div class="no-display">
<input type="hidden" name="product" value="<?php echo $_product->getId() ?>" />
<input type="hidden" name="related_product" id="related-products-field" value="" />
</div>
<?php $buttonTitle = $this->__('Add to Cart'); ?>
<div class="add-to-cart">
<?php if(!$_product->isGrouped() && !$_product->isconfigurable()): ?>
<label for="qty"><?php echo $this->__('Qty:') ?></label>
<input type="text" name="qty" id="qty_<?php echo $counter; ?>" maxlength="12" value="<?php echo '1'; //echo $this->getProductDefaultQty() * 1 ?>" title="<?php echo $this->__('Qty') ?>" class="input-text qty" />
<?php endif; ?>
<button type="button" title="<?php echo $buttonTitle ?>" class="button btn-cart" data-count="<?php echo $counter; ?>" data-ptype="<?php echo $_product->getTypeID(); ?>"><span><span><?php echo $buttonTitle ?></span></span></button>
<?php echo $this->getChildHtml('', true, true) ?>
</div>
</form>
<?php else: ?>
Remember i am generating form id and quantity field id with loop and as there are two display modes in magento category listing page List Mode and Grid Mode so you have to replace the above code in both areas.
id="product_addtocart_form_<?php echo $counter; ?>"
Also for button i have used two HTML5 data attributes data-count and data-ptype. In data-count i am just storing the value of $counter variable and in the data-ptype i am storing product type (i.e simple, grouped etc)
data-count="<?php echo $counter; ?>" data-ptype="<?php echo $_product->getTypeID(); ?>"
finally the javascript code
<script type="text/javascript">
//<![CDATA[
// console.log(<?php //echo $counter; ?>);
document.observe("dom:loaded", function() {
var productAddToCartForm = new Array();
for (var i = 0; i < <?php echo $counter; ?>; i++) {
productAddToCartForm[i] = new VarienForm('product_addtocart_form_'+i);
productAddToCartForm[i].submit = ajx_form_submit.bind(productAddToCartForm[i]);
productAddToCartForm[i].submitLight = ajx_form_submitLight.bind(productAddToCartForm[i]);
};
$$('.btn-cart').each( function(item) {
// console.log($(item).up('form').action);
item.observe('click', function(event) {
if (item.dataset.ptype == 'simple') {
ajaxcart.ajaxCartSubmit(productAddToCartForm[item.dataset.count]);
} else if (item.dataset.ptype == 'grouped') {
formurl = $(item).up('form').action;
ajaxcart.ajaxCartSubmit(formurl);
} else if (item.dataset.ptype == 'configurable') {
formurl = $(item).up('form').action + '?options=cart&ajax=true';
ajaxcart.getConfigurableOptions(formurl);
}
// productAddToCartForm[item.dataset.count].submit(item);
});
});
});
var ajx_form_submit = function(button, url) {
if (this.validator.validate()) {
var form = this.form;
var oldUrl = form.action;
if (url) {
form.action = url;
}
var e = null;
try {
this.form.submit();
} catch (e) {
}
this.form.action = oldUrl;
if (e) {
throw e;
}
if (button && button != 'undefined') {
button.disabled = true;
}
}
};
var ajx_form_submitLight = function(button, url){
if(this.validator) {
var nv = Validation.methods;
delete Validation.methods['required-entry'];
delete Validation.methods['validate-one-required'];
delete Validation.methods['validate-one-required-by-name'];
// Remove custom datetime validators
for (var methodName in Validation.methods) {
if (methodName.match(/^validate-datetime-.*/i)) {
delete Validation.methods[methodName];
}
}
if (this.validator.validate()) {
if (url) {
this.form.action = url;
}
this.form.submit();
}
Object.extend(Validation.methods, nv);
}
};
$$('.product_addtocart_form input.qty').each(function(el) {
el.observe('blur', function(e){
if( el.value <= 0 || isNaN(el.value) === true) {
el.value = 1;
}
});
});
//]]>
</script>
Best Answer
Your definition of dirty is a bit much, since each block registers an event that allows you to modify it's HTML after it's processed it itself. And then there's JavaScript as well.
In fact, I'd say the clean way is to use this core_block_abstract_to_html_after event, because rewriting the template to include another template for this button, causes much more overhead. Instead in
core_block_abstract_to_html_after
you can do a singlepreg_replace
pass, or a maybe somewhat cleaner DOM replacement.