Version Notes
Initial public release.
Download this release
Release Info
Developer | Matthias Kerstner |
Extension | BothInteract_CleanProductTexts |
Version | 1.0.0 |
Comparing to | |
See all releases |
Version 1.0.0
- app/code/community/BothInteract/CleanProductTexts/Model/Observer.php +124 -0
- app/code/community/BothInteract/CleanProductTexts/Model/System/Config/Source/View.php +34 -0
- app/code/community/BothInteract/CleanProductTexts/etc/adminhtml.xml +26 -0
- app/code/community/BothInteract/CleanProductTexts/etc/config.xml +42 -0
- app/code/community/BothInteract/CleanProductTexts/etc/system.xml +86 -0
- app/etc/modules/BothInteract_CleanProductTexts.xml +10 -0
- package.xml +32 -0
app/code/community/BothInteract/CleanProductTexts/Model/Observer.php
ADDED
@@ -0,0 +1,124 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Handles product cleaning based on configuration set in backend.
|
5 |
+
*
|
6 |
+
* This class writes log messages to a custom log file specified by
|
7 |
+
* @see self::$LOG_FILE.
|
8 |
+
*
|
9 |
+
* @author Matthias Kerstner <matthias@both-interact.com>
|
10 |
+
* @version 1.0.0
|
11 |
+
* @copyright (c) 2015, Both Interact GmbH
|
12 |
+
*/
|
13 |
+
class BothInteract_CleanProductTexts_Model_Observer {
|
14 |
+
|
15 |
+
/** @var boolean flag to avoid recursion when saving products in this observer */
|
16 |
+
private $_isProcessed = false;
|
17 |
+
|
18 |
+
/** @var string this module's namespace */
|
19 |
+
private static $_MODULE_NAMESPACE = 'bothinteract_cleanproducttexts';
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Logs $msg to logfile specified in configuration.
|
23 |
+
* @param string $msg
|
24 |
+
*/
|
25 |
+
private function logToFile($msg) {
|
26 |
+
Mage::log($msg, null, Mage::getStoreConfig(
|
27 |
+
self::$_MODULE_NAMESPACE
|
28 |
+
. '/general/log_file', Mage::app()->getStore()));
|
29 |
+
}
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Handles product based on $cleaningOptions specified.
|
33 |
+
* @param Mage_Catalog_Model_Product $product
|
34 |
+
* @var array $cleaningOptions
|
35 |
+
*/
|
36 |
+
private function handleProduct(Mage_Catalog_Model_Product $product, $cleaningOptions) {
|
37 |
+
$this->logToFile('Handling '
|
38 |
+
. mb_strtoupper($product->getTypeId())
|
39 |
+
. ' product ' . $product->getId());
|
40 |
+
|
41 |
+
foreach ($cleaningOptions as $cleaningOption) {
|
42 |
+
$this->logToFile('Checking option ' . $cleaningOption);
|
43 |
+
|
44 |
+
// remove control characters for description and short description
|
45 |
+
if ($cleaningOption == BothInteract_CleanProductTexts_Model_System_Config_Source_View::$VALUE_CLEANING_TYPE_CONTROL_CHARACTERS) {
|
46 |
+
// @see http://unicode-table.com/en/
|
47 |
+
$this->logToFile('Cleaning product ' . $product->getId());
|
48 |
+
|
49 |
+
$regexp = '/[^\PC\s]/u'; //i.e. /[\x00—\x1F\x80-\x9f]
|
50 |
+
$product->setDescription(preg_replace('/\x0b/', '', preg_replace($regexp, '', $product->getDescription())));
|
51 |
+
$product->setShortDescription(preg_replace('/\x0b/', '', preg_replace($regexp, '', $product->getShortDescription())));
|
52 |
+
}
|
53 |
+
}
|
54 |
+
|
55 |
+
if (Mage::getStoreConfig(self::$_MODULE_NAMESPACE
|
56 |
+
. '/general/is_simulation')) {
|
57 |
+
$this->logToFile('************************************');
|
58 |
+
$this->logToFile('SIMULATION: Not saving product '
|
59 |
+
. $product->getId());
|
60 |
+
$this->logToFile('************************************');
|
61 |
+
} else {
|
62 |
+
$this->logToFile('Saving product ' . $product->getId());
|
63 |
+
$product->save();
|
64 |
+
}
|
65 |
+
|
66 |
+
$this->logToFile('Successfully handled product ' . $product->getId());
|
67 |
+
}
|
68 |
+
|
69 |
+
/**
|
70 |
+
* Handles product save event calls by checking product type.
|
71 |
+
* @param Varien_Event_Observer $observer
|
72 |
+
*/
|
73 |
+
public function catalog_product_save_after(Varien_Event_Observer $observer) {
|
74 |
+
try {
|
75 |
+
if (!Mage::getStoreConfig(self::$_MODULE_NAMESPACE
|
76 |
+
. '/general/is_active', Mage::app()->getStore())) {
|
77 |
+
$this->logToFile('Extension INACTIVE - Quitting...');
|
78 |
+
return;
|
79 |
+
}
|
80 |
+
|
81 |
+
if (!$this->_isProcessed) {
|
82 |
+
$this->_isProcessed = true; // avoid recursion on save()
|
83 |
+
$this->processProduct($observer->getProduct());
|
84 |
+
} else {
|
85 |
+
$this->logToFile('Product already processed '
|
86 |
+
. $observer->getProduct()->getId());
|
87 |
+
}
|
88 |
+
} catch (Exception $e) {
|
89 |
+
$this->logToFile('ERROR: ' . $e->getMessage());
|
90 |
+
}
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Can be of any product type, e.g. configurable, grouped, simple,
|
95 |
+
* @param Mage_Catalog_Model_Product $product Can be of any valid product
|
96 |
+
* type, e.g. configurable, grouped, simple, ...
|
97 |
+
*/
|
98 |
+
public function processProduct(Mage_Catalog_Model_Product $product) {
|
99 |
+
try {
|
100 |
+
$this->logToFile('==================================================');
|
101 |
+
$this->logToFile('Checking product ' . $product->getId()
|
102 |
+
. ' of type ' . mb_strtoupper($product->getTypeId())
|
103 |
+
. '...');
|
104 |
+
|
105 |
+
/**
|
106 |
+
* @var array cleaning options selected in configuration.
|
107 |
+
*
|
108 |
+
* Options are taken from system config source view.
|
109 |
+
*/
|
110 |
+
$cleaningOptions = explode(',', Mage::getStoreConfig(self::$_MODULE_NAMESPACE
|
111 |
+
. '/general/cleaning_options', Mage::app()->getStore()));
|
112 |
+
|
113 |
+
$this->logToFile('Cleaning options: ['
|
114 |
+
. implode(',', $cleaningOptions) . ']');
|
115 |
+
|
116 |
+
$this->handleProduct($product, $cleaningOptions);
|
117 |
+
|
118 |
+
$this->logToFile('Done processing product ' . $product->getId() . '!');
|
119 |
+
} catch (Exception $e) {
|
120 |
+
$this->logToFile('ERROR: ' . $e->getMessage());
|
121 |
+
}
|
122 |
+
}
|
123 |
+
|
124 |
+
}
|
app/code/community/BothInteract/CleanProductTexts/Model/System/Config/Source/View.php
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* @author Matthias Kerstner <matthias@both-interact.com>
|
5 |
+
* @version 1.0.0
|
6 |
+
* @copyright (c) 2015, Both Interact GmbH
|
7 |
+
*/
|
8 |
+
class BothInteract_CleanProductTexts_Model_System_Config_Source_View {
|
9 |
+
|
10 |
+
public static $VALUE_CLEANING_TYPE_CONTROL_CHARACTERS = 0;
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Options getter
|
14 |
+
*
|
15 |
+
* @return array
|
16 |
+
*/
|
17 |
+
public function toOptionArray() {
|
18 |
+
return array(
|
19 |
+
array('value' => self::$VALUE_CLEANING_TYPE_CONTROL_CHARACTERS, 'label' => Mage::helper('adminhtml')->__('Control characters')),
|
20 |
+
);
|
21 |
+
}
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Get options in "key-value" format
|
25 |
+
*
|
26 |
+
* @return array
|
27 |
+
*/
|
28 |
+
public function toArray() {
|
29 |
+
return array(
|
30 |
+
self::$VALUE_CLEANING_TYPE_CONTROL_CHARACTERS => Mage::helper('adminhtml')->__('Control characters')
|
31 |
+
);
|
32 |
+
}
|
33 |
+
|
34 |
+
}
|
app/code/community/BothInteract/CleanProductTexts/etc/adminhtml.xml
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" ?>
|
2 |
+
<config>
|
3 |
+
<acl>
|
4 |
+
<resources>
|
5 |
+
<all>
|
6 |
+
<title>Allow Everything</title>
|
7 |
+
</all>
|
8 |
+
<admin>
|
9 |
+
<children>
|
10 |
+
<system>
|
11 |
+
<children>
|
12 |
+
<config>
|
13 |
+
<children>
|
14 |
+
<bothinteract_cleanproducttexts translate="title" module="bothinteract_cleanproducttexts">
|
15 |
+
<title>General</title>
|
16 |
+
<sort_order>100</sort_order>
|
17 |
+
</bothinteract_cleanproducttexts>
|
18 |
+
</children>
|
19 |
+
</config>
|
20 |
+
</children>
|
21 |
+
</system>
|
22 |
+
</children>
|
23 |
+
</admin>
|
24 |
+
</resources>
|
25 |
+
</acl>
|
26 |
+
</config>
|
app/code/community/BothInteract/CleanProductTexts/etc/config.xml
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
|
3 |
+
<config>
|
4 |
+
|
5 |
+
<modules>
|
6 |
+
<BothInteract_CleanProductTexts>
|
7 |
+
<version>1.0.0</version>
|
8 |
+
</BothInteract_CleanProductTexts>
|
9 |
+
</modules>
|
10 |
+
|
11 |
+
<global>
|
12 |
+
<!-- inform Magento of our new model class-->
|
13 |
+
<models>
|
14 |
+
<bothinteract_cleanproducttexts>
|
15 |
+
<class>BothInteract_CleanProductTexts_Model</class>
|
16 |
+
</bothinteract_cleanproducttexts>
|
17 |
+
</models>
|
18 |
+
<!-- attach our observer class to catalog_product_save_after event-->
|
19 |
+
<events>
|
20 |
+
<catalog_product_save_after>
|
21 |
+
<observers>
|
22 |
+
<bothinteract_cleanproducttexts_model_observer>
|
23 |
+
<type>singleton</type>
|
24 |
+
<class>BothInteract_CleanProductTexts_Model_Observer</class>
|
25 |
+
<method>catalog_product_save_after</method>
|
26 |
+
</bothinteract_cleanproducttexts_model_observer>
|
27 |
+
</observers>
|
28 |
+
</catalog_product_save_after>
|
29 |
+
</events>
|
30 |
+
</global>
|
31 |
+
|
32 |
+
<default>
|
33 |
+
<bothinteract_cleanproducttexts>
|
34 |
+
<general>
|
35 |
+
<is_active>0</is_active>
|
36 |
+
<is_simulation>1</is_simulation>
|
37 |
+
<required_image_types></required_image_types>
|
38 |
+
<log_file>cleanproducttexts.log</log_file>
|
39 |
+
</general>
|
40 |
+
</bothinteract_cleanproducttexts>
|
41 |
+
</default>
|
42 |
+
</config>
|
app/code/community/BothInteract/CleanProductTexts/etc/system.xml
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
|
3 |
+
<config>
|
4 |
+
|
5 |
+
<tabs>
|
6 |
+
<bothinteract translate="label">
|
7 |
+
<label>Both Interact GmbH</label>
|
8 |
+
<sort_order>100</sort_order>
|
9 |
+
</bothinteract>
|
10 |
+
</tabs>
|
11 |
+
|
12 |
+
<sections>
|
13 |
+
<bothinteract_cleanproducttexts translate="label" module="adminhtml">
|
14 |
+
<label>Clean Product Texts</label>
|
15 |
+
<tab>bothinteract</tab>
|
16 |
+
<frontend_type>text</frontend_type>
|
17 |
+
<sort_order>1000</sort_order>
|
18 |
+
<show_in_default>1</show_in_default>
|
19 |
+
<show_in_website>1</show_in_website>
|
20 |
+
<show_in_store>1</show_in_store>
|
21 |
+
|
22 |
+
<groups>
|
23 |
+
<general translate="label">
|
24 |
+
<label>General</label>
|
25 |
+
<frontend_type>text</frontend_type>
|
26 |
+
<sort_order>50</sort_order>
|
27 |
+
<show_in_default>1</show_in_default>
|
28 |
+
<show_in_website>1</show_in_website>
|
29 |
+
<show_in_store>1</show_in_store>
|
30 |
+
|
31 |
+
<fields>
|
32 |
+
<is_active translate="label">
|
33 |
+
<label>Active</label>
|
34 |
+
<comment>
|
35 |
+
<![CDATA[Check this box to <b>activate</b> automatic cleaning when adding/saving your products
|
36 |
+
and enable the shell script (optional).]]>
|
37 |
+
</comment>
|
38 |
+
<frontend_type>select</frontend_type>
|
39 |
+
<source_model>adminhtml/system_config_source_enabledisable</source_model>
|
40 |
+
<sort_order>1</sort_order>
|
41 |
+
<show_in_default>1</show_in_default>
|
42 |
+
<show_in_website>1</show_in_website>
|
43 |
+
<show_in_store>1</show_in_store>
|
44 |
+
</is_active>
|
45 |
+
<is_simulation translate="label">
|
46 |
+
<label>Simulate</label>
|
47 |
+
<comment>
|
48 |
+
<![CDATA[Check this box to <b>simulate</b> product cleaning. Your products will <b>not</b> be changed.
|
49 |
+
Please refer to log for more information.]]>
|
50 |
+
</comment>
|
51 |
+
<frontend_type>select</frontend_type>
|
52 |
+
<source_model>adminhtml/system_config_source_enabledisable</source_model>
|
53 |
+
<sort_order>2</sort_order>
|
54 |
+
<show_in_default>1</show_in_default>
|
55 |
+
<show_in_website>1</show_in_website>
|
56 |
+
<show_in_store>1</show_in_store>
|
57 |
+
</is_simulation>
|
58 |
+
<cleaning_options translate="label">
|
59 |
+
<label>Cleaning options</label>
|
60 |
+
<comment>
|
61 |
+
<![CDATA[Please select desired cleaning option(s) for your products.]]>
|
62 |
+
</comment>
|
63 |
+
<frontend_type>multiselect</frontend_type>
|
64 |
+
<source_model>BothInteract_CleanProductTexts_Model_System_Config_Source_View</source_model>
|
65 |
+
<sort_order>4</sort_order>
|
66 |
+
<show_in_default>1</show_in_default>
|
67 |
+
<show_in_website>1</show_in_website>
|
68 |
+
<show_in_store>1</show_in_store>
|
69 |
+
</cleaning_options>
|
70 |
+
<log_file translate="label">
|
71 |
+
<label>Log file</label>
|
72 |
+
<comment>
|
73 |
+
<![CDATA[Please specify a name for your custom <b>log file</b>.]]>
|
74 |
+
</comment>
|
75 |
+
<frontend_type>text</frontend_type>
|
76 |
+
<sort_order>5</sort_order>
|
77 |
+
<show_in_default>1</show_in_default>
|
78 |
+
<show_in_website>1</show_in_website>
|
79 |
+
<show_in_store>1</show_in_store>
|
80 |
+
</log_file>
|
81 |
+
</fields>
|
82 |
+
</general>
|
83 |
+
</groups>
|
84 |
+
</bothinteract_cleanproducttexts>
|
85 |
+
</sections>
|
86 |
+
</config>
|
app/etc/modules/BothInteract_CleanProductTexts.xml
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
|
3 |
+
<config>
|
4 |
+
<modules>
|
5 |
+
<BothInteract_CleanProductTexts>
|
6 |
+
<active>true</active>
|
7 |
+
<codePool>community</codePool>
|
8 |
+
</BothInteract_CleanProductTexts>
|
9 |
+
</modules>
|
10 |
+
</config>
|
package.xml
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0"?>
|
2 |
+
<package>
|
3 |
+
<name>BothInteract_CleanProductTexts</name>
|
4 |
+
<version>1.0.0</version>
|
5 |
+
<stability>stable</stability>
|
6 |
+
<license uri="http://www.opensource.org/licenses/mit-license.php">MIT License (MITL)</license>
|
7 |
+
<channel>community</channel>
|
8 |
+
<extends/>
|
9 |
+
<summary>This extension helps you to automatically clean product texts.</summary>
|
10 |
+
<description><p>This extension helps you to automatically clean your product texts (description and short description) by removing unwanted (invisible) control characters that might cause problems with other extensions or when exporting products.</p>
|
11 |
+

|
12 |
+
<p>Oftentimes, unwanted characters are copied into product descriptions when copying texts from PDF documents. Since these control characters are not displayed by browsers they cannot be removed manually from Magento's editor.</p>
|
13 |
+

|
14 |
+
<p>This extension will check your product texts and automatically removed unwanted characters.</p>
|
15 |
+

|
16 |
+
<p>Thus, your employees can still copy texts from e.g. PDFs directly into Magento - this extension will take care of removing unwanted characters when saving products.</p>
|
17 |
+

|
18 |
+
<h3>Simulate Product Cleaning</h3>
|
19 |
+
<p>Furthermore, you can also <b>simulate</b> the process of cleaning product texts by activating the corresponding option in the configuration under <i>General</i> / <i>Simulate</i>.</p>
|
20 |
+

|
21 |
+
<h3>Log File</h3>
|
22 |
+
<p>In addition this extension enabled you to logs messages to a custom log file that can be specified in the configuration options to your log directory under <i>General</i> / <i>Log File</i>.</p> 
|
23 |
+

|
24 |
+
<p>So you have the option to easily track events handled by this extension and check for possible problems.</p></description>
|
25 |
+
<notes>Initial public release.</notes>
|
26 |
+
<authors><author><name>Matthias Kerstner</name><user>mkbothinteract</user><email>matthias@both-interact.com</email></author></authors>
|
27 |
+
<date>2015-03-06</date>
|
28 |
+
<time>12:52:21</time>
|
29 |
+
<contents><target name="magecommunity"><dir name="BothInteract"><dir name="CleanProductTexts"><dir name="Model"><file name="Observer.php" hash="fa5e9b0483e429093f7ed413727f99bb"/><dir name="System"><dir name="Config"><dir name="Source"><file name="View.php" hash="06c8cab69af1427591ccd80a5ff84b85"/></dir></dir></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="09afe6511e6b0c1ee544c2ca87d59474"/><file name="config.xml" hash="8b3dceb0487024d8822a504af9c0241e"/><file name="system.xml" hash="9250f6bd8e3089b823c46138e1d6622f"/></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="BothInteract_CleanProductTexts.xml" hash="c685308779c1427921191dd9860627a1"/></dir></target></contents>
|
30 |
+
<compatible/>
|
31 |
+
<dependencies><required><php><min>5.3.0</min><max>5.6.6</max></php></required></dependencies>
|
32 |
+
</package>
|