Magento read-only and hidden product attributes - magento

I would like to have some Magento product attributes that are not editable from the admin interface and some that are not visible at all in that interface (as a method of storing some persistent information about a product that should not be viewed by human users.. it's the only way of doing this that i can think of, any other suggestions are welcome).
So my question is: Do all Magento attributes have to be visible and editable from the admin interface? If not, how can they be made read-only or hidden?
I noticed that in the admin interface there are some read-only fields, so it must be possible to do this one way or another. After searching stackoverflow for this I found a possible solution involving JavaScript, but I would like to not go down that path if it's at all possible.

OK, it looks like it can be done after all. After adding an observer for the catalog_product_load_after event, the lockAttribute method of the Mage_Catalog_Model_Abstract class may be used to make a product attribute read-only. Here is the code for the observer method:
public function lockAttributes($observer) {
$event = $observer->getEvent();
$product = $event->getProduct();
$product->lockAttribute('attribute_code');
}

Since the catalog_product_load_after event is dispatched for every product load, the attributes supplied in the lock_attributes method are locked after every product load. This could have unexpected results: it is not possible to change the value of the attributes in the lock_attributes method without explicitly unlocking them.
Instead of using the catalog_product_load_after event, it suffices to add an observer for the catalog_product_edit_action event: this event is dispatched only when editing a product in the admin interface.

I think Aad Mathijssen and Epicurus combined have the best answer to the question, with a little clarification. As Aad points out, catalog_product_load_after is called after every product load and that means on the FrontEnd as well!
If we are looking to protect attribute fields only in the admin panels, catalog_product_edit_action is the more appropriate choice.
Your etc/config.xml will then be something like this:
<catalog_product_edit_action>
<observers>
<lock_attributes>
<class>yourmodule/observers</class>
<method>lockAttributes</method>
</lock_attributes>
</observers>
</catalog_product_edit_action>

No i guess its not possible from the attribute manager.
A easy quick and dirty solution would be to use css to hide the input and label.

I have developed exactly such extension that works for products, categories and CMS pages. You just have to define some rules and choose which attributes you want to show as read-only.
Extension URL: https://www.bubbleshop.net/magento-admin-readonly.html

Using this thread and some more digging around; the lockAttribute method is from an abstract class which means that it's possible to also be used on category attributes as well. I caught the 'catalog_category_load_after' observer and used it to lock my desired category attributes:
public function lockCategoryAttributes($observer) {
$event = $observer->getEvent();
$c = $event->getCategory();
$c->lockAttribute('attribute_code');
}
I'm not sure if that's the right observer to use but it works.
So yes it is possible to lock category attributes or make them readonly.

etc\adminhtml\events.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="catalog_product_load_after">
<observer name="product_lock_attributes" instance="Vendor\Module\Observer\Lock"/>
</event>
</config>
Observer\Lock.php
namespace Vendor\Module\Observer;
class Lock implements \Magento\Framework\Event\ObserverInterface
{
public function execute(\Magento\Framework\Event\Observer $observer)
{
$event = $observer->getEvent();
$product = $event->getProduct();
$product->lockAttribute('attribute_code');
}
}

Related

matrix component association issue

Background:
I have a running magnto application. I have created a new module inside app/code/locale. Inside this folder I have controller called SyncController.
Inside this controller I am calling a method in model Like below;
<?php
class Connect_SyncController extends Mage_Core_Controller_Front_Action {
function IndexAction() {
}
function ProductAction() {
Mage::getModel('connect/product')->sync();
}
}
?>
Product action in model receives a json input and the json input will contain matrix item and matrix component item.
Problem:
So for it was working fine. Whenever I sent matrix item and component items, those all were added and associated properly. Suddenly there is an problem in associating components to its matrix item. Matrix items and components are being saved successfully no issues with that. But, components are not associating to its parent. Even there is no error throwing. Surprise is, once in a while it works.
I referred below suggestion also;
Cannot associate Simple Products in a Configurable
But there is no up gradation or change in configuration exists in recent past.
Can anyone suggest what may be the issue?
Try to increase max_input_time from php.ini. And restart the apache server.

Magento 1.7+: How to use the page layout handle

After trying to debug for hours I'm out of ideas and hope for some clarification (I guess I missunderstood a concept at some point).
The backstory: Some base categories need an "overview page" which should be generated automatically from child categories and products. So my approach was to add a sub category to every base category and create a custom page layout which is being used from all these sub categories. For my client this would be very easy to manage in the Magento backend since he would only need to change the value in one drop down. So I created a simple module defining the new page layout. Within the backend I was able to select this one as well.
The module config:
<?xml version="1.0"?>
<config>
<modules>
<Company_Layouts>
<version>0.1.0</version>
</Company_Layouts>
</modules>
<global>
<page>
<layouts>
<company_category_overview module="page" translate="label">
<label>Kategorie-Übersicht</label>
<template>page/1column.phtml</template>
<layout_handle>company_category_overview</layout_handle>
</company_category_overview>
</layouts>
</page>
</global>
<frontend>
<layout>
<updates>
<company_layouts>
<file>company_layouts.xml</file>
</company_layouts>
</updates>
</layout>
</frontend>
</config>
Since these special overview pages require some layout changes I was hoping to reference the layout in a specific layout file (company_layouts.xml)... and here my logic is leaving me:
With <layout_handle>company_category_overview</layout_handle> I was hoping to define a handle which I can use to change the layout only when this specific page template is being used. Exactly this is not the case. My layout updates which are inside the handle company_category_overview are just being ignored.
After digging deeper I realized, it doesn't seem to be my code but more like a general issue. In an old Magento 1.4 installation the page layout handle is being carried to all sites, like page_one_column. In Magento 1.7 and (what I'm using now) 1.8 this is only on the home page the case. I'm using Commerce Bug for debugging. I just tried this with a fresh 1.7 and a freh 1.8 installation.
Is this some concept I don't understand or just a plain bug?
Also, I'm aware that layout updates can be achieved within the backend but this would only be my last option since I feel it's much cleaner having this in a seperate file without the need of copy/pasting such stuff.
Is this some concept I don't understand or just a plain bug?
Both? Neither? The information in the <page><layout>...</layout></page> node is used by both the category pages and CMS pages, but each system uses the the information differently, and neither system uses it in a way you'd expect. Here's a rundown on how category pages use this information.
The category page is rendered by the following controller action
#File: app/code/core/Mage/Catalog/controllers/CategoryController.php
public function viewAction()
{
...
}
This controller action doesn't have the standard loadLayout and renderLayout method calls. Instead, there's a lot of extra code in this method for adding layout handles and doing things between generating the blocks and rendering the final layout. The section we're interested in is this
$design = Mage::getSingleton('catalog/design');
$settings = $design->getDesignSettings($category);
#...other stuff we don't care about...
if ($settings->getPageLayout()) {
$this->getLayout()->helper('page/layout')->applyTemplate($settings->getPageLayout());
}
When you save a category with your "Page Layout" in the Custom Design tab, the getPageLayout method call above should return company_category_overview. On category pages, Magento doesn't use this to apply a handle, instead it passes the values to the applyTemplate method. Here's that method in full.
#File: app/code/core/Mage/Page/Helper/Layout.php
public function applyTemplate($pageLayout = null)
{
if ($pageLayout === null) {
$pageLayout = $this->getCurrentPageLayout();
} else {
$pageLayout = $this->_getConfig()->getPageLayout($pageLayout);
}
if (!$pageLayout) {
return $this;
}
if ($this->getLayout()->getBlock('root') &&
!$this->getLayout()->getBlock('root')->getIsHandle()) {
// If not applied handle
$this->getLayout()
->getBlock('root')
->setTemplate($pageLayout->getTemplate());
}
return $this;
}
The pertinent parts are this line,
$pageLayout = $this->_getConfig()->getPageLayout($pageLayout);
which will load the information from your configuration
<label>Kategorie-Übersicht</label>
<template>page/1column.phtml</template>
<layout_handle>company_category_overview</layout_handle>
as a Varien_Object. Then, it will use this information to apply a template to the root block.
$this->getLayout()
->getBlock('root')
>setTemplate($pageLayout->getTemplate());
So, for category pages, the information in the <layout_handle/> node is never used. That's why your layout updates aren't being applied — Magento actually applies your handle.

Magento: Empty Payment Html in Methods.phtml

I’ve got a problem with the payment methods for my checkout. When I reach the Checkout Step for the Payment Methods, the several options are displayed but I am getting no further Information to the Methods “Bank Payment” and “Cash on Delivery” when I click on the radio button.
It seems to me that getPaymentMethodFormHtml (checkout/onepage/payment/methods.phtml) is empty for these Methods. As a result of this issue, I am getting no information in the Order Confirmation Mail (like Bank Name, Cash on Delivery Fee).
Can anyone help me?
Your error should be in
/app/design/adminhtml/default/default/template/payment/form/[cc.phtml]
/app/design/frontend/default/default/template/payment/form/[cc.phtml]
You may need to take a look at each payment method to see the path for their template
e.g
<?php
class MagePal_CimPaymentPro_Block_Form_Payment extends Mage_Payment_Block_Form_Cc
{
protected function _construct()
{
parent::_construct();
$this->setTemplate('magepal/cimpaymentpro/payment/form/cc.phtml');
}
Also, you may want to check to make sure you don't have any javascript error on that page.
You could also use Inspect Element in chrome/Firefox (or firebug) to see if the html is hidden by css

Magento How can i change request parameters on the fly?

I tried to write an Observer like controller_action_predispatch and like for the default sort in Magento: store.com/category.html?dir=asc&order=name
in the observer i tried to manipulate the parameters but no succes. I tried for examples always for DESC order so i did like this: Mage::app()->getRequest()->setParam('dir', 'desc');
But after render the pruduct list it dont work... I sense i have no power on request parameters or is there a way to change them before loading a page and using a Magento event?
if you have an issue in product sorting then i will suggest to use Observer "catalog_block_product_list_collection" on this event and then observer class you can use
$observer->getEvent()->getCollection()->addAttributeToSort('price', 'ASC');
Thanks

Can't modify response in a Magento event observer, even though observer is firing

I'm attempting to use an observer to modify the response of the add to cart controller action, but only in the context of an AJAX request.
My observer is called and my JS is retrieving data fine, I have verified this by putting a die() in my observer function cartAdd() and verifying the response developer console, which I am using to see the result of my response from Magento. So JS isn't the issue here.
My primary problem is that I can't seem to modify the response through the normal functions. I get the request by using $observer->getEvent()->getControllerAction()->getResponse() and then make changes to it by setHeader(), or setBody(), or any other function that modifies the response, but there is absolutely no effect to the response!
Does anybody have any clue as to why I'm not able to modify the response in my observer?
In /app/code/local/mynamespace/mymodule/etc/config.xml:
<frontend>
....
<events>
<controller_action_predispatch_checkout_cart_add>
<observers>
<mymodule_cart_add>
<type>singleton</type>
<class>mymodule/observer</class>
<method>cartAdd</method>
</mymodule_cart_add>
</observers>
</controller_action_predispatch_checkout_cart_add>
</events>
</frontend>
In /app/code/local/mynamespace/mymodule/Model/Observer.php:
public function cartAdd(Varien_Event_Observer $observer)
{
$controllerAction = $observer->getEvent()->getControllerAction();
if($controllerAction->getRequest()->isAjax()) {
$response = $controllerAction->getResponse();
// I've even tried using:
// $response = Mage::app()->getResponse();
$response->setHeader('HTTP/1.1','403 Forbidden'); //using this because i will need it in my final code and it will make it immediatly obvious the response has been changed
$response->setHeader('Content-type', 'application/json');
$response->setBody('hello world!!!!');
// this is to stop the product from being added to the cart
$controllerAction->setFlag('', Mage_Core_Controller_Varien_Action::FLAG_NO_DISPATCH, true);
}
}
Please note: I know this code isn't going to at all AJAXify adding to cart (which is my end goal). At the moment I am just trying to resolve this issue
I end up just getting the contents of the page that you would end up on as a result of running an add to cart action:
When a product is added to cart there is admin-configurable behavior to send a person to the cart page or to redirect them back to the product page. See the System > Configuration > Checkout > Shopping Cart: After Adding a Product Redirect to Shopping Cart field.
This redirect behavior is accomplished via a redirect which will displace any redirect set in the dynamic controller_action_predispatch_checkout_cart_add event; ref. the final bit of logic from the Mage_Checkout_CartController::addAction(). Have no fear, though! Magento core developers have the need to override this behavior as well, so it is possible to inform the Mage_Checkout cart controller's addAction() method to bypass the normal redirect behavior if a flag has been set on the checkout/session object. Not only is there a hook and supporting logic to make it work, but there is actually a working example from the core - always a good thing for developers.
Just prior to the final redirect logic in the addAction() method, the cart controller's addAction() method dispatches the checkout_cart_add_product_complete event. This event is observed by the Mage_Wishlist observer. A quick review of relevant final logic from the Mage_Wishlist_Model_Observer::processAddToCart() method shows how to prevent the cart controller's addAction() method from redirecting - namely by setting the no_cart_redirect flag on checkout/session object, which preserves the redirect set on the response object.
There is one more consideration in this case. It's likely that the Mage_Wishlist observers behavior should be preserved, namely: after adding a product to cart from the wishlist, a customer may be redirected to the next product in their wishlist. This is one of the instances when observer processing order matters. To make sure that the Mage_Wishlist module's add to cart behavior is preserved, other modules which consume the checkout_cart_add_product_complete event should fire before the Mage_Wishlist observer. In the declaration file for the custom module, the Mage_Wishlist module should be set as dependent on the custom module, which will ensure that the custom module's observer will fire before the Mage_Wishlist module:
<?xml version="1.0" encoding="UTF-8"?>
<config>
<modules>
<Custom_Module>
<active>true</active>
<codePool>local</codePool>
</Custom_Module>
<Mage_Wishlist>
<depends>
<Custom_Module />
</depends>
</Mage_Wishlist>
</modules>
</config>
If the Mage_Wishlist module were not a factor, the better targeted event to consume would be the dynamically-generated controller_action_postdispatch_checkout_cart_add event, which is the last targeted event before the generic controller_front_send_response_before event.

Resources