本文介绍了如何在Magento 2中删除重复的产品属性选项。
我为此使用了独立脚本。您也可以在自定义模块中使用此代码。
初始化对象管理器并设置区号
以下代码完成了以下操作:
–初始化对象管理器。
–在编辑产品时,将区号设置为adminhtml。
<?php
error_reporting(1);
set_time_limit(0);
ini_set('memory_limit', '2048M');
use Magento\Framework\App\Bootstrap;
/**
* If your external file is in root folder
*/
require __DIR__ . '/app/bootstrap.php';
/**
* If your external file is NOT in root folder
* Let's suppose, your file is inside a folder named 'xyz'
*
* And, let's suppose, your root directory path is
* /var/www/html/magento2
*/
// $rootDirectoryPath = '/var/www/html/magento2';
// require $rootDirectoryPath . '/app/bootstrap.php';
$params = $_SERVER;
$bootstrap = Bootstrap::create(BP, $params);
$obj = $bootstrap->getObjectManager();
$state = $obj->get('Magento\Framework\App\State');
$state->setAreaCode('adminhtml');
获取所有属性
$allAttributes = $obj->get('Magento\Catalog\Model\ResourceModel\Product\Attribute\Collection')
->getItems();
foreach ($allAttributes as $attribute) {
var_dump($attribute->getData());
//echo $attribute->getFrontendLabel() . ' - ' . $attribute->getAttributeCode() . '<br />';
}
通过属性代码加载产品属性
$attributeCode = 'color';
$attribute = $obj->get('Magento\Eav\Model\Config')
->getAttribute('catalog_product', $attributeCode);
var_dump($attribute->getData());
输出:
array (size=41)
'attribute_id' => string '93' (length=2)
'entity_type_id' => string '4' (length=1)
'attribute_code' => string 'color' (length=5)
'attribute_model' => null
'backend_model' => null
'backend_type' => string 'int' (length=3)
'backend_table' => null
'frontend_model' => null
'frontend_input' => string 'select' (length=6)
'frontend_label' => string 'Color' (length=5)
'frontend_class' => null
'source_model' => null
'is_required' => string '0' (length=1)
'is_user_defined' => string '1' (length=1)
'default_value' => null
'is_unique' => string '0' (length=1)
'note' => null
'frontend_input_renderer' => null
'is_global' => string '1' (length=1)
'is_visible' => string '1' (length=1)
'is_searchable' => string '1' (length=1)
'is_filterable' => string '0' (length=1)
'is_comparable' => string '1' (length=1)
'is_visible_on_front' => string '0' (length=1)
'is_html_allowed_on_front' => string '0' (length=1)
'is_used_for_price_rules' => string '0' (length=1)
'is_filterable_in_search' => string '0' (length=1)
'used_in_product_listing' => string '0' (length=1)
'used_for_sort_by' => string '0' (length=1)
'apply_to' => null
'is_visible_in_advanced_search' => string '1' (length=1)
'position' => string '0' (length=1)
'is_wysiwyg_enabled' => string '0' (length=1)
'is_used_for_promo_rules' => string '1' (length=1)
'is_required_in_admin_store' => string '0' (length=1)
'is_used_in_grid' => string '1' (length=1)
'is_visible_in_grid' => string '0' (length=1)
'is_filterable_in_grid' => string '1' (length=1)
'search_weight' => string '1' (length=1)
'additional_data' => null
...
...
...
获取已加载属性的所有选项
$options = $attribute->getSource()->getAllOptions();
var_dump($options);
输出:
Array
(
[0] => Array
(
[label] =>
[value] =>
)
[1] => Array
(
[value] => 557
[label] => Berry
)
[2] => Array
(
[value] => 517
[label] => Black
)
[3] => Array
(
[value] => 573
[label] => Blue
)
...
...
...
获取与每个属性选项关联的所有产品
在这里,我们遍历上面代码中加载的属性的所有选项。然后,我们获取与每个属性选项关联的产品。
foreach ($options as $option) {
$products = $obj->get('Magento\Catalog\Model\Product')
->getCollection()
->addAttributeToFilter($attributeCode, $option['value']);
$productIds = [];
foreach ($products as $prod) {
$productIds[] = $prod->getId();
}
echo 'Option ID: ' . $option['value'] . '<br />';
echo 'Option Label: ' . $option['label'] . '<br />';
echo 'Total Products: ' . $products->count() . '<br />';
echo 'Product IDs: ' . implode(', ', $productIds) . '<br />';
echo '<br />';
}
输出:
Option ID: 71
Option Label: Berry
Total Products: 1
Product IDs: 566
Option ID: 61
Option Label: Black
Total Products: 4
Product IDs: 269, 276, 864, 868
Option ID: 52
Option Label: Blue
Total Products: 8
Product IDs: 626, 637, 649, 659, 672, 690, 701, 861
...
...
...
创建一个数组以找出重复的属性选项
在这里,我们遍历上面代码中加载的属性的所有选项。然后,我们创建一个包含属性标签作为键的新数组,该键包含另一个数组,该数组具有属性选项的ID和与该属性选项ID关联的产品总数。
该数组将如下所示:
Array
(
[AttributeLabel] => Array
(
[AttributeID] => ProductCount
)
)
这是代码:
$duplicateOptions = [];
foreach ($options as $option) {
// because the first option can be blank
if(!empty(trim($option['label']))) {
$products = $obj->get('Magento\Catalog\Model\Product')
->getCollection()
->addAttributeToFilter($attributeCode, $option['value']);
if ($products->count()) {
$productsCount = $products->count();
} else {
$productsCount = 0;
}
$duplicateOptions[$option['label']][$option['value']] = $productsCount;
}
}
echo '<pre>'; print_r($duplicateOptions);
输出:
Array
(
[Berry] => Array
(
[53] => 1
[247] => 0
)
[Black] => Array
(
[13] => 42
)
[Blue] => Array
(
[61] => 4
)
[White] => Array
(
[16] => 0
[246] => 0
)
...
...
...
在上面的输出中,您可以在数组键Berry中看到两项。这表明属性选项“ Berry”具有重复的条目,即有两个条目与Berry具有相同的标签。
删除重复属性选项
到目前为止,我们已经找到了重复的属性选项。现在,在删除重复属性选项时,您需要确定需要删除的选项。
有可能:
–新添加的属性选项,即具有较高ID的重复属性选项
–旧的属性选项,即具有较低ID的
重复属性选项–产品计数为零的重复属性选项
对于此示例,我将尝试删除重复的最新/新添加的属性选项,即,我假设某些属性选项最近已添加到该属性,但是那些属性选项之前已存在于该属性中。
首先,
–我们将在deleteOptions数组中创建一个名为delete的新键条目。 –它将包含要删除的属性选项ID的值。 –包含零产品计数的属性选项ID被视为要删除的那个。
foreach ($duplicateOptions as $key => $value) {
if (count($value) > 1) {
foreach ($value as $k => $v) {
if ($v == 0) {
$duplicateOptions[$key]['delete'][] = $k;
}
}
}
}
echo '<pre>'; print_r($duplicateOptions);
输出:
Array
(
[Berry] => Array
(
[53] => 1
[247] => 0
[delete] => Array
(
[0] => 247
)
)
[Black] => Array
(
[13] => 42
)
[White] => Array
(
[16] => 0
[246] => 0
[delete] => Array
(
[0] => 16
[1] => 246
)
)
...
...
...
在上面的输出中,对于属性选项White,两个选项ID均被视为要删除的选项ID。这是因为两个选项ID的关联产品均为零。
在这种情况下,我们将从“删除”键数组中删除我们不想删除的属性选项ID。
如上所述,对于此示例,我将新添加/最新添加的选项视为重复的选项。因此,我将删除具有较高ID的选项,而不是删除具有较低ID值的选项。
foreach ($duplicateOptions as $key => $value) {
if (count($value) > 1) {
foreach ($value as $k => $v) {
if ($v == 0) {
$duplicateOptions[$key]['delete'][] = $k;
}
}
if (isset($duplicateOptions[$key]['delete'])) {
/**
* if multiple options are in delete array,
* i.e. multiple option ids have zero product count
*/
if (count($duplicateOptions[$key]['delete']) > 1) {
sort($duplicateOptions[$key]['delete']); // sort the array
array_shift($duplicateOptions[$key]['delete']); // remove the first item of the array
/**
* if you assume that the older option id is the duplicate one
* then, you keep the older option id in the delete list
* and remove the latest/newly-added attribute option from the delete list
*/
// rsort($duplicateOptions[$key]['delete']); // reverse sort the array
// array_shift($duplicateOptions[$key]['delete']); // remove the first item of the array
}
}
}
}
echo '<pre>'; print_r($duplicateOptions);
输出:
Array
(
[Berry] => Array
(
[53] => 1
[247] => 0
[delete] => Array
(
[0] => 247
)
)
[Black] => Array
(
[13] => 42
)
[White] => Array
(
[16] => 0
[246] => 0
[delete] => Array
(
[0] => 246
)
)
...
...
...
现在,我们实际上删除了重复属性选项。
foreach ($duplicateOptions as $key => $value) {
if (count($value) > 1) {
foreach ($value as $k => $v) {
if ($v == 0) {
$duplicateOptions[$key]['delete'][] = $k;
}
}
if (isset($duplicateOptions[$key]['delete'])) {
/**
* if multiple options are in delete array,
* i.e. multiple option ids have zero product count
*/
if (count($duplicateOptions[$key]['delete']) > 1) {
sort($duplicateOptions[$key]['delete']); // sort the array
array_shift($duplicateOptions[$key]['delete']); // remove the first item of the array
/**
* if you assume that the older option id is the duplicate one
* then, you keep the older option id in the delete list
* and remove the latest/newly-added attribute option from the delete list
*/
// rsort($duplicateOptions[$key]['delete']); // reverse sort the array
// array_shift($duplicateOptions[$key]['delete']); // remove the first item of the array
// DELETE DUPLICATE ATTRIBUTE OPTIONS
foreach ($duplicateOptions[$key]['delete'] as $optionId) {
$optionModel = $obj->get('Magento\Eav\Model\Entity\Attribute\Option')->load($optionId);
try {
$optionModel->delete();
echo '<font color="green">"'.$key.' ('.$optionId.')" Option Deleted!</font><br />';
}
catch(Exception $e) {
echo '<font color="red">'. $e->getMessage() .'</font><br />';
}
}
}
}
}
}
输出:
"Berry (247)" duplicate option deleted!
"White (246)" duplicate option deleted!
删除重复的属性选项并将操作保存在日志文件中
删除代码与上述相同。我们刚刚添加了将删除的消息保存在日志文件中的代码。日志文件将保存在var / log文件夹中。
$file = 'var/log/delete_duplicate_attribute_options.log';
$handle = fopen($file, 'a') or die('Cannot open file: '.$file); //implicitly creates file
$data = date('Y-m-d H:i:s');
$data .= "\n";
$data .= 'Attribute Code: ' . $attributeCode;
$data .= "\n\n";
foreach ($duplicateOptions as $key => $value) {
if (count($value) > 1) {
foreach ($value as $k => $v) {
if ($v == 0) {
$duplicateOptions[$key]['delete'][] = $k;
}
}
if (isset($duplicateOptions[$key]['delete'])) {
/**
* if multiple options are in delete array,
* i.e. multiple option ids have zero product count
*/
if (count($duplicateOptions[$key]['delete']) > 1) {
sort($duplicateOptions[$key]['delete']); // sort the array
array_shift($duplicateOptions[$key]['delete']); // remove the first item of the array
/**
* if you assume that the older option id is the duplicate one
* then, you keep the older option id in the delete list
* and remove the latest/newly-added attribute option from the delete list
*/
// rsort($duplicateOptions[$key]['delete']); // reverse sort the array
// array_shift($duplicateOptions[$key]['delete']); // remove the first item of the array
}
// DELETE DUPLICATE ATTRIBUTE OPTIONS
foreach ($duplicateOptions[$key]['delete'] as $optionId) {
$optionModel = $obj->get('Magento\Eav\Model\Entity\Attribute\Option')->load($optionId);
try {
$optionModel->delete();
echo '<font color="green">"'.$key.' ('.$optionId.')" duplicate option deleted!</font><br />';
$data .= 'Option Value: ' . $key . ', ' . 'Option ID: ' . $optionId;
$data .= "\n";
} catch(Exception $e) {
echo '<font color="red">'. $e->getMessage() .'</font><br />';
$data .= $e->getMessage();
}
}
}
}
}
$data .= "\n\n";
fwrite($handle, $data);
fclose($handle);
日志文件的输出:
2018-11-08 07:54:49
Attribute Code: color
Option Value: Berry, Option ID: 247
Option Value: White, Option ID: 248
希望这可以帮助。谢谢。