Hinzufügen eines zweiten Produktrasters in der Kategorieverwaltung für „Ausgewählte Produkte“
-
12-12-2019 - |
Frage
Ich möchte auf der Kategorieverwaltungsseite eine neue Registerkarte „Kategorieprodukte“ mit einem Produktraster hinzufügen, das dem Standardproduktraster der Kategorie entspricht.
Der einzige Unterschied besteht darin, dass ich dieses Raster benötige, um ausgewählte Produkte in einer benutzerdefinierten Tabelle mit den folgenden Feldern zu speichern:
1.id
2.product_id
3.category_id
4.Position
Dies ermöglicht mir dann, „vorgestellte Produkte“ mit separater Produktbestellung zu haben, wie im folgenden Wireframe gezeigt:
Screenshot der Unterkategorie mit den „empfohlenen Produkten“.
Erste Gedanken
- Erstellen Sie eine benutzerdefinierte Registerkarte ähnlich wie
Mage_Adminhtml_Block_Catalog_Category_Tab_Product
- Erstellen Sie einen Beobachter, um die Kategoriebeziehung zu speichern
catalog_category_save_after
- Rufen Sie Produkt-IDs mit der aktuellen Kategorie-ID aus der benutzerdefinierten Tabelle ab und markieren Sie sie als ausgewählt
Lösung
Überblick
Nachdem ich mir den Kopf zerbrochen hatte, baute ich endlich ein Modul.
Modelle
Es wurde ein Modell erstellt, das das Kategoriemodell erweitert, um eine benutzerdefinierte Entität zu vermeiden.
Beobachter
addCategoryEssentialBlock
Dieser Beobachter fügt unsere Registerkarte „Neue Produkte“ und das serialisierte Raster auf der Kategorieverwaltungsseite hinzu und hört sich die an adminhtml_catalog_category_tabs
Ereignis.
saveCategoryEssentialData
Dieser Beobachter speichert die Kategorie-Essential-Produktbeziehung beim Speichern der Kategorie und hört sich die ancatalog_category_save_after
Ereignis.
Code
Block
app/code/local/Lg/Essentials/Block/Adminhtml/Catalog/Category/Tab/Essential.php
class Lg_Essentials_Block_Adminhtml_Catalog_Category_Tab_Essential extends Mage_Adminhtml_Block_Widget_Grid
{
/**
* Set grid params
*/
public function __construct()
{
parent::__construct();
$this->setId('catalog_category_essential');
$this->setDefaultSort('position');
$this->setDefaultDir('ASC');
$this->setUseAjax(true);
}
/**
* Get current category
* @return Mage_Catalog_Model_Category
*/
public function getCategory()
{
return Mage::registry('current_category');
}
/**
* Add filter
* @param $column
* @return $this
*/
protected function _addColumnFilterToCollection($column)
{
if ($column->getId() == 'in_essentials') {
$essentialIds = $this->_getSelectedEssentials();
if (empty($essentialIds)) {
$essentialIds = 0;
}
if ($column->getFilter()->getValue()) {
$this->getCollection()->addFieldToFilter('entity_id', array('in'=>$essentialIds));
} else {
if ($essentialIds) {
$this->getCollection()->addFieldToFilter('entity_id', array('nin'=>$essentialIds));
}
}
} else {
parent::_addColumnFilterToCollection($column);
}
return $this;
}
/**
* Prepare the collection
* @return Mage_Adminhtml_Block_Widget_Grid
* @throws Exception
*/
protected function _prepareCollection()
{
if ($this->getCategory()->getId()) {
$this->setDefaultFilter(array('in_essentials'=>1));
}
$collection = Mage::getModel('catalog/product')->getCollection()
->addAttributeToSelect('name')
->addAttributeToSelect('sku')
->addAttributeToSelect('price')
->addStoreFilter($this->getRequest()->getParam('store'))
->joinField(
'position',
'lg_essentials/category_essential',
'position',
'product_id=entity_id',
'category_id='.(int) $this->getRequest()->getParam('id', 0),
'left'
);
$this->setCollection($collection);
if ($this->getCategory()->getProductsReadonly()) {
$essentialIds = $this->_getSelectedEssentials();
if (empty($essentialIds)) {
$essentialIds = 0;
}
$this->getCollection()->addFieldToFilter('entity_id', array('in'=>$essentialIds));
}
return parent::_prepareCollection();
}
/**
* Prepare the columns
* @return $this
* @throws Exception
*/
protected function _prepareColumns()
{
if (!$this->getCategory()->getProductsReadonly()) {
$this->addColumn(
'in_essentials',
array(
'header_css_class' => 'a-center',
'type' => 'checkbox',
'name' => 'in_essentials',
'values' => $this->_getSelectedEssentials(),
'align' => 'center',
'index' => 'entity_id'
));
}
$this->addColumn(
'entity_id',
array(
'header' => Mage::helper('lg_essentials')->__('ID'),
'sortable' => true,
'width' => '60',
'index' => 'entity_id'
)
);
$this->addColumn('name', array(
'header' => Mage::helper('lg_essentials')->__('Name'),
'index' => 'name'
));
$this->addColumn('sku', array(
'header' => Mage::helper('lg_essentials')->__('SKU'),
'width' => '80',
'index' => 'sku'
));
$this->addColumn('price', array(
'header' => Mage::helper('lg_essentials')->__('Price'),
'type' => 'currency',
'width' => '1',
'currency_code' => (string) Mage::getStoreConfig(Mage_Directory_Model_Currency::XML_PATH_CURRENCY_BASE),
'index' => 'price'
));
$this->addColumn(
'position',
array(
'header' => Mage::helper('lg_essentials')->__('Position'),
'width' => '1',
'type' => 'number',
'index' => 'position',
'editable' => !$this->getCategory()->getProductsReadonly()
)
);
return parent::_prepareColumns();
}
/**
* Get grid url
* @return string
*/
public function getGridUrl()
{
return $this->getUrl(
'adminhtml/essentials_essential_catalog_category/essentialsgrid',
array(
'id'=>$this->getCategory()->getId()
)
);
}
/**
* Get list of selected Essential Ids
* @return array
*/
protected function _getSelectedEssentials()
{
$essential = Mage::getModel('lg_essentials/category');
$essentials = $this->getCategoryEssentials();
if (!is_array($essentials)) {
$essentials = $essential->getEssentialsPosition($this->getCategory());
return array_keys($essentials);
}
return $essentials;
}
/**
* Get list of selected Essential Id & positions
* @return array
*/
public function getSelectedEssentials()
{
$essentials = array();
$selected = Mage::getModel('lg_essentials/category')->getEssentialsPosition(Mage::registry('current_category'));
if (!is_array($selected)) {
$selected = array();
}
foreach ($selected as $essentialId => $position) {
$essentials[$essentialId] = array('position' => $position);
}
return $essentials;
}
}
app/code/local/Lg/Essentials/Block/Catalog/Category/List/Essential.php
class Lg_Essentials_Block_Catalog_Category_List_Essential extends Mage_Core_Block_Template
{
/**
* Get the list of Essentials
* @return Mage_Catalog_Model_Resource_Product_Collection
*/
public function getEssentialProductsCollection()
{
$category = Mage::registry('current_category');
$collection = Mage::getModel('catalog/product')->getCollection()
->addAttributeToSelect('name')
->addAttributeToSelect('sku')
->addAttributeToSelect('price')
->joinField(
'position',
'lg_essentials/category_essential',
'position',
'product_id=entity_id',
'at_position.category_id='.(int) $category->getId(),
'right'
);
$collection->addOrder('position', 'asc');
return $collection;
}
}
Controller
app/code/local/Lg/Essentials/controllers/Adminhtml/Essentials/Essential/Catalog/CategoryController.php
require_once ("Mage/Adminhtml/controllers/Catalog/CategoryController.php");
class Lg_Essentials_Adminhtml_Essentials_Essential_Catalog_CategoryController
extends Mage_Adminhtml_Catalog_CategoryController
{
/**
* construct
*/
protected function _construct()
{
// Define module dependent translate
$this->setUsedModuleName('Lg_Essentials');
}
/**
* Essentials grid in category page
*/
public function essentialsgridAction()
{
$this->_initCategory();
$this->loadLayout();
$this->getLayout()->getBlock('category.edit.tab.essential')
->setCategoryEssentials($this->getRequest()->getPost('category_essentials', null));
$this->renderLayout();
}
}
usw
app/code/local/Lg/Essentials/etc/config.xml
<?xml version="1.0"?>
<config>
<modules>
<Lg_Essentials>
<version>0.1.0</version>
</Lg_Essentials>
</modules>
<global>
<resources>
<lg_essentials_setup>
<setup>
<module>Lg_Essentials</module>
<class>Lg_Essentials_Model_Resource_Setup</class>
</setup>
</lg_essentials_setup>
</resources>
<blocks>
<lg_essentials>
<class>Lg_Essentials_Block</class>
</lg_essentials>
</blocks>
<helpers>
<lg_essentials>
<class>Lg_Essentials_Helper</class>
</lg_essentials>
</helpers>
<models>
<lg_essentials>
<class>Lg_Essentials_Model</class>
<resourceModel>lg_essentials_resource</resourceModel>
</lg_essentials>
<lg_essentials_resource>
<class>Lg_Essentials_Model_Resource</class>
<entities>
<category_essential>
<table>lg_essentials_category_essential</table>
</category_essential>
</entities>
</lg_essentials_resource>
</models>
</global>
<adminhtml>
<layout>
<updates>
<lg_essentials>
<file>lg/essentials.xml</file>
</lg_essentials>
</updates>
</layout>
<events>
<adminhtml_catalog_category_tabs>
<observers>
<lg_essentials_essential_category>
<type>singleton</type>
<class>lg_essentials/adminhtml_observer</class>
<method>addCategoryEssentialBlock</method>
</lg_essentials_essential_category>
</observers>
</adminhtml_catalog_category_tabs>
<catalog_category_save_after>
<observers>
<lg_essentials_essential_category>
<type>singleton</type>
<class>lg_essentials/adminhtml_observer</class>
<method>saveCategoryEssentialData</method>
</lg_essentials_essential_category>
</observers>
</catalog_category_save_after>
</events>
</adminhtml>
<admin>
<routers>
<adminhtml>
<args>
<modules>
<Lg_Essentials before="Mage_Adminhtml">Lg_Essentials_Adminhtml</Lg_Essentials>
</modules>
</args>
</adminhtml>
</routers>
</admin>
<frontend>
<layout>
<updates>
<lg_essentials>
<file>lg/essentials.xml</file>
</lg_essentials>
</updates>
</layout>
</frontend>
</config>
Helfer
app/code/local/Lg/Essentials/Helper/Data.php
class Lg_Essentials_Helper_Data extends Mage_Core_Helper_Abstract
{
}
Modell
app/code/local/Lg/Essentials/Model/Adminhtml/Observer.php
class Lg_Essentials_Model_Adminhtml_Observer
{
/**
* Add the Essential tab to categories
* @param Varien_Event_Observer $observer
* @return Lg_Essentials_Model_Adminhtml_Observer $this
*/
public function addCategoryEssentialBlock($observer)
{
$tabs = $observer->getEvent()->getTabs();
$content = $tabs->getLayout()->createBlock(
'lg_essentials/adminhtml_catalog_category_tab_essential',
'category.essential.grid'
)->toHtml();
$serializer = $tabs->getLayout()->createBlock(
'adminhtml/widget_grid_serializer',
'category.essential.grid.serializer'
);
$serializer->initSerializerBlock(
'category.essential.grid',
'getSelectedEssentials',
'essentials',
'category_essentials'
);
$serializer->addColumnInputName('position');
$content .= $serializer->toHtml();
$tabs->addTab(
'essential',
array(
'label' => Mage::helper('lg_essentials')->__('Essentials'),
'content' => $content,
)
);
return $this;
}
/**
* Save category - essential relation
* @param Varien_Event_Observer $observer
* @return Lg_Essentials_Model_Adminhtml_Observer $this
*/
public function saveCategoryEssentialData($observer)
{
$post = Mage::app()->getRequest()->getPost('essentials', -1);
if ($post != '-1') {
$post = Mage::helper('adminhtml/js')->decodeGridSerializedInput($post);
$category = Mage::registry('category');
$category->setPostedEssentials($post);
$essentialResource = Mage::getResourceModel('lg_essentials/category');
$essentialResource->saveCategoryEssentials($category);
}
return $this;
}
}
app/code/local/Lg/Essentials/Model/Resource/Category.php
class Lg_Essentials_Model_Resource_Category extends Mage_Catalog_Model_Resource_Category
{
/**
* Save category essentials relation
* @param Mage_Catalog_Model_Category $category
* @return Mage_Catalog_Model_Resource_Category
*/
public function saveCategoryEssentials($category)
{
$categoryEssentialTable = $this->getTable('lg_essentials/category_essential');
$category->setIsChangedEssentialList(false);
$id = $category->getId();
/**
* new category-essential relationships
*/
$products = $category->getPostedEssentials();
/**
* Example re-save category
*/
if ($products === null) {
return $this;
}
/**
* old category-essential relationships
*/
$oldProducts = Mage::getModel('lg_essentials/category')->getEssentialsPosition($category);
$insert = array_diff_key($products, $oldProducts);
$delete = array_diff_key($oldProducts, $products);
/**
* Find product ids which are presented in both arrays
* and saved before (check $oldProducts array)
*/
$update = array_intersect_key($products, $oldProducts);
if ($update) {
$update = $this->cleanPositions($update);
}
$update = array_diff_assoc($update, $oldProducts);
$adapter = $this->_getWriteAdapter();
/**
* Delete essentials from category
*/
if (!empty($delete)) {
$cond = array(
'product_id IN(?)' => array_keys($delete),
'category_id=?' => $id
);
$adapter->delete($categoryEssentialTable, $cond);
}
/**
* Add essentials to category
*/
if (!empty($insert)) {
$data = array();
foreach ($insert as $productId => $position) {
$data[] = array(
'category_id' => (int)$id,
'product_id' => (int)$productId,
'position' => (int)$position['position']
);
}
$adapter->insertMultiple($categoryEssentialTable, $data);
}
/**
* Update essential positions in category
*/
if (!empty($update)) {
foreach ($update as $productId => $position) {
$where = array(
'category_id = ?'=> (int)$id,
'product_id = ?' => (int)$productId
);
$bind = array('position' => (int)$position);
$adapter->update($categoryEssentialTable, $bind, $where);
}
}
if (!empty($insert) || !empty($delete)) {
$productIds = array_unique(array_merge(array_keys($insert), array_keys($delete)));
Mage::dispatchEvent('catalog_category_change_essentials', array(
'category' => $category,
'product_ids' => $productIds
));
}
if (!empty($insert) || !empty($update) || !empty($delete)) {
$category->setIsChangedEssentialList(true);
/**
* Setting affected essentials to category for third party engine index refresh
*/
$productIds = array_keys($insert + $delete + $update);
$category->setAffectedEssentialIds($productIds);
}
return $this;
}
/**
* Get positions of associated to category essentials
* @param Mage_Catalog_Model_Category $category
* @return array
*/
public function getEssentialsPosition($category)
{
$categoryEssentialTable = $this->getTable('lg_essentials/category_essential');
$select = $this->_getWriteAdapter()->select()
->from($categoryEssentialTable, array('product_id', 'position'))
->where('category_id = :category_id');
$bind = array('category_id' => (int)$category->getId());
return $this->_getWriteAdapter()->fetchPairs($select, $bind);
}
/**
* Get Essential count in category
* @param Mage_Catalog_Model_Category $category
* @return int
*/
public function getEssentialCount($category)
{
$categoryEssentialTable = Mage::getSingleton('core/resource')->getTableName('lg_essentials/category_essential');
$select = $this->getReadConnection()->select()
->from(
array('main_table' => $categoryEssentialTable),
array(new Zend_Db_Expr('COUNT(main_table.product_id)'))
)
->where('main_table.category_id = :category_id');
$bind = array('category_id' => (int)$category->getId());
$counts = $this->getReadConnection()->fetchOne($select, $bind);
return intval($counts);
}
/**
* Clean Essentials positions
* @param $products
* @return array
*/
protected function cleanPositions($products)
{
$cleanPositions = array();
foreach ($products as $productid => $info) {
$cleanPositions[$productid] = $info['position'];
}
return $cleanPositions;
}
}
app/code/local/Lg/Essentials/Model/Resource/Setup.php
class Lg_Essentials_Model_Resource_Setup extends Mage_Catalog_Model_Resource_Setup
{
}
app/code/local/Lg/Essentials/Model/Category.php
class Lg_Essentials_Model_Category extends Mage_Catalog_Model_Category
{
/**
* Retrieve array of essential id's for category
* array($productId => $position)
* @param $category
* @return array
*/
public function getEssentialsPosition($category)
{
if (!$category->getId()) {
return array();
}
$array = $category->getData('essentials_position');
if (is_null($array)) {
$array = Mage::getResourceModel('lg_essentials/category')->getEssentialsPosition($category);
$category->setData('essentials_position', $array);
}
return $array;
}
/**
* Retrieve count essentials of category
* @param $category
* @return int
*/
public function getEssentialCount($category)
{
if (!$this->hasEssentialCount()) {
$count = Mage::getResourceModel('lg_essentials/category')->getEssentialCount($category);
$this->setData('essential_count', $count);
}
return $this->getData('essential_count');
}
}
sql
app/code/local/Lg/Essentials/sql/lg_essentials_setup/install-0.1.0.php
/* @var $installer Mage_Catalog_Model_Resource_Setup */
$installer = $this;
$installer->startSetup();
/**
* Create table 'lg_essentials/category_essential'
*/
$table = $installer->getConnection()
->newTable($installer->getTable('lg_essentials/category_essential'))
->addColumn(
'category_id',
Varien_Db_Ddl_Table::TYPE_INTEGER,
null,
array(
'unsigned' => true,
'nullable' => false,
'primary' => true,
'default' => '0',
),
'Category ID'
)
->addColumn(
'product_id',
Varien_Db_Ddl_Table::TYPE_INTEGER,
null,
array(
'unsigned' => true,
'nullable' => false,
'primary' => true,
'default' => '0',
),
'Product ID'
)
->addColumn(
'position',
Varien_Db_Ddl_Table::TYPE_INTEGER,
null,
array(
'nullable' => false,
'default' => '0',
),
'Position'
)
->addIndex(
$installer->getIdxName(
'lg_essentials/category_essential',
array('product_id')
),
array('product_id')
)
->addForeignKey(
$installer->getFkName(
'lg_essentials/category_essential',
'category_id',
'catalog/category',
'entity_id'
),
'category_id',
$installer->getTable('catalog/category'),
'entity_id',
Varien_Db_Ddl_Table::ACTION_CASCADE,
Varien_Db_Ddl_Table::ACTION_CASCADE
)
->addForeignKey(
$installer->getFkName(
'lg_essentials/category_essential',
'product_id',
'catalog/product',
'entity_id'
),
'product_id',
$installer->getTable('catalog/product'),
'entity_id',
Varien_Db_Ddl_Table::ACTION_CASCADE,
Varien_Db_Ddl_Table::ACTION_CASCADE
)
->addIndex(
$this->getIdxName(
'lg_essentials/category_essential',
array('product_id', 'category_id'),
Varien_Db_Adapter_Interface::INDEX_TYPE_UNIQUE
),
array('product_id', 'category_id'),
array('type' => Varien_Db_Adapter_Interface::INDEX_TYPE_UNIQUE)
)
->setComment('Essential To Category Linkage Table');
$installer->getConnection()->createTable($table);
$installer->endSetup();
adminthml
app/design/adminhtml/default/default/layout/lg/essentials.xml
<?xml version="1.0"?>
<layout>
<adminhtml_essentials_essential_catalog_category_essentialsgrid>
<block type="core/text_list" name="root" output="toHtml">
<block type="lg_essentials/adminhtml_catalog_category_tab_essential" name="category.edit.tab.essential"/>
</block>
</adminhtml_essentials_essential_catalog_category_essentialsgrid>
</layout>
Frontend
app/design/frontend/base/default/layout/lg/essentials.xml
<?xml version="1.0"?>
<layout>
<lg_essentials_category>
<reference name="category.products">
<block type="lg_essentials/catalog_category_list_essential" name="category.info.essentials"
as="category_essentials" template="lg/essentials/catalog/category/list/essential.phtml"/>
</reference>
</lg_essentials_category>
<catalog_category_default>
<update handle="lg_essentials_category" />
</catalog_category_default>
<catalog_category_layered>
<update handle="lg_essentials_category" />
</catalog_category_layered>
</layout>
app/design/frontend/base/default/template/lg/essentials/catalog/category/list/essential.phtml
<?php $essentials = $this->getEssentialProductsCollection();?>
<?php if ($essentials && $essentials->count() > 0) :?>
<div class="box-collateral box-essentials box-up-sell">
<h2>Essentials</h2>
<?php foreach ($essentials as $_essential) : ?>
<div class="item">
<?php echo $_essential->getName();?>
<br />
</div>
<?php endforeach; ?>
</div>
<?php endif;?>
app/etc/modules/Lg_Essentials.xml
<?xml version="1.0"?>
<config>
<modules>
<Lg_Essentials>
<active>true</active>
<codePool>local</codePool>
<depends>
<Mage_Catalog />
</depends>
</Lg_Essentials>
</modules>
</config>
Andere Tipps
Es ist nicht klar, wie Ihre benutzerdefinierte Registerkarte aussehen soll.Sieht es mit dem Category Products
identisch aus, dient nur einen anderen Zweck?
Wenn ja, können Ihre anfänglichen Gedanken gut klingen.Erstellen Sie eine neue Klasse für Ihre benutzerdefinierte Registerkarte.Mage_Adminhtml_Block_Catalog_Category_Tabs::_prepareLayout
zeigt Ihnen eine Möglichkeit, eine neue Registerkarte hinzuzufügen.Sie werden sehen, dass diese Methode GEFIRTACDICETAGCODE feuert, die ein Beobachter anschließen kann, um eine andere Registerkarte hinzuzufügen. '
Um die benutzerdefinierten Daten zu speichern, denke ich, dass es gut ist, die "Kategorieaktion speichern" umzuschreiben, sodass Sie die geposteten Daten für Ihre benutzerdefinierte Tabelle abfangen und sie entsprechend speichern können.Ich bin nicht sicher, wie Sie die benutzerdefinierten Daten von adminhtml_catalog_category_tabs
abrufen würden, wenn Sie sich dafür entscheiden, verschiedene Produkte unter Ihrer benutzerdefinierten Tab vs. catalog_category_save_after
-Registerkarte auszuwählen.
Category Products
Beobachter wird nur funktionieren, wenn Ihre benutzerdefinierte Registerkarte und der generationspflichtigen> immer die gleichen Produkte haben.