You can do this job via standard event/observers:
<global>
<events>
<catalog_product_save_before>
<observers>
<some_module_detect_product_changes>
<type>singleton</type>
<class>some_module/observer</class>
<method>detectProductChanges</method>
</some_module_detect_product_changes>
</observers>
</catalog_product_save_before>
<catalog_product_attribute_update_before>
<observers>
<some_module_detect_product_attribute_changes>
<type>singleton</type>
<class>some_module/observer</class>
<method>detectProductAttributeChanges</method>
</some_module_detect_product_attribute_changes>
</observers>
</catalog_product_attribute_update_before>
</global>
And Observer.php:
class Some_Module_Model_Observer{
public function detectProductAttributeChanges($observer)
{
$attributesData = $observer->getEvent()->getAttributesData();
$productIds = $observer->getEvent()->getProductIds();
$user = Mage::getSingleton('admin/session')->getUser();
foreach ($productIds as $id) {
$change = Mage::getModel('some_module/changes');
$change->product_id = $id;
$change->new_values = print_r($attributesData, true);
$change->user_id = ($user) ? $user->getId() : NULL;
$change->created = now();
$change->save();
}
return $this;
}
public function detectProductChanges($observer)
{
/**
* @var $product Mage_Catalog_Model_Product
* @var $user Mage_Admin_Model_User
*/
$product = $observer->getEvent()->getProduct();
if ($product->hasDataChanges()) {
try {
$user = Mage::getSingleton('admin/session')->getUser();
$attributes = $this->getAttributes();
$new = array();
$org = array();
$changes = array();
foreach ($attributes as $attribute) {
if (!is_array($product->getData($attribute))) {
$new[$attribute] = ($product->getData($attribute)) ? $product->getData($attribute) : null;
if (!is_array($product->getOrigData($attribute))) {
$org[$attribute] = ($product->getOrigData($attribute)) ? $product->getOrigData($attribute) : null;
if (($new[$attribute] != $org[$attribute])) {
$changes[$attribute] = array('new'=> $new[$attribute],
'old'=> $org[$attribute]);
}
}
}
}
$stokAttributes = array(
'qty',
'manage_stock',
'is_in_stock',
'min_qty',
'min_sale_qty',
'max_sale_qty',
);
if ($product->getStockItem()) {
foreach ($stokAttributes as $attribute=> $value) {
$new[$attribute] = ($product->getStockItem()->getData($attribute)) ? $product->getStockItem()->getData($attribute) : null;
$org[$attribute] = ($product->getStockItem()->getOrigData($attribute)) ? $product->getStockItem()->getOrigData($attribute) : null;
if ($new[$attribute] != $org[$attribute]) {
$changes[$attribute] = array('new'=> $new[$attribute],
'old'=> $org[$attribute]);
}
}
}
$newValues = array_intersect_key($new, $changes);
if (count($newValues)) {
$oldValues = array_intersect_key($org, $changes);
$change = Mage::getModel('some_module/changes');
$change->product_id = $product->entity_id;
$change->sku = $product->sku;
$change->name = $product->name;
$change->new_values = print_r($newValues, true);
$change->old_values = print_r($oldValues, true);
$change->user_id = ($user) ? $user->getId() : NULL;
$change->created = now();
$change->save();
}
} catch (Exception $e) {
Mage::log($e->getTraceAsString(), null, 'product_changes_fault.log');
}
}
return $this;
}
}
Here is I used Changes model to save every changes to DB. And you may create admin grid to view tracked changes on dashboard.
I'm not sure if this is what you need, but here is a simple extension that allows you to get the product url.
The main idea is to rewrite the info
method in the product api model and make it return the url of the product also.
For this you will need the following files:
app/etc/modules/[Namespace]_[Module].xml
- the declaration file
<?xml version="1.0"?>
<config>
<modules>
<[Namespace]_[Module]>
<active>true</active>
<codePool>local</codePool>
<depends>
<Mage_Catalog />
<Mage_Api />
</depends>
</[Namespace]_[Module]>
</modules>
</config>
app/code/local/[Namespace]/[Module]/etc/config.xml
- the configuration file
<?xml version="1.0"?>
<config>
<modules>
<[Namespace]_[Module]>
<version>0.0.1</version>
</[Namespace]_[Module]>
</modules>
<global>
<models>
<catalog>
<rewrite>
<product_api>[Namespace]_[Module]_Model_Product_Api</product_api>
</rewrite>
</catalog>
</models>
</global>
</config>
app/code/local/[Namespace]/[Module]/Model/Product/Api.php
- your new class
<?php
class [Namespace]_[Module]_Model_Product_Api extends Mage_Catalog_Model_Product_Api {
public function info($productId, $store = null, $attributes = null, $identifierType = null){
$product = $this->_getProduct($productId, $store, $identifierType);
$result = parent::info($productId, $store = null, $attributes = null, $identifierType = null);
//add a new element in here called product_url. You can even wrap it in some condition to see if the product is assigned to the current website or if the product is enabled or visible. ($product->getWebsiteIds(), $product->getStatus(), $product->getVisibility()).
$result['product_url'] = $product->getUrlInStore($store);
return $result;
}
}
Note: This works only for API V1. In order to make it work for v2 you need to add a wsdl to your module. See how you can do it.
Best Answer
A product can only be saved for one store at a time. So when saving a product, you are always in the context of a single store. The store id can be retrieved from the
Varien_Event_Observer
observer argument as follows:Note that saving an attribute value for a product in one store can have an impact on attribute value of the corresponding attribute for the same product in another store.
For instance, consider saving a product with id
123
for store0
(the admin store), and in which the attributename
(with attribute id71
) has been changed. When loading product id123
again for store1
(the default frontend store), the value of attributename
might also be updated. You can check this as follows:In the admin, go to the product edit page, and switch to store
1
using the configuration scope box. If the "Use default" checkbox is not checked, the value from store1
is shown. Otherwise, the value from store0
is shown.In the database, you can see this in the corresponding product attribute table, in this case
catalog_product_entity_varchar
. If there is no value for the combination of store id1
, entity id123
and attribute id71
, then the value for the combination of store id0
, entity id123
and attribute id71
is taken.