2f0ed0fddbc299a929e59604a51b5159 - Version 1.0.0

Version Notes

notes

Download this release

Release Info

Developer Marcin Klauza
Extension 2f0ed0fddbc299a929e59604a51b5159
Version 1.0.0
Comparing to
See all releases


Version 1.0.0

Files changed (20) hide show
  1. app/code/community/Mklauza/CustomProductUrls/Block/Adminhtml/Form/Abstract.php +129 -0
  2. app/code/community/Mklauza/CustomProductUrls/Block/Adminhtml/Form/Pattern.php +138 -0
  3. app/code/community/Mklauza/CustomProductUrls/Block/Adminhtml/MassActionForm.php +38 -0
  4. app/code/community/Mklauza/CustomProductUrls/Block/Adminhtml/SettingsForm.php +42 -0
  5. app/code/community/Mklauza/CustomProductUrls/Block/Adminhtml/Urlrewrite/Grid.php +138 -0
  6. app/code/community/Mklauza/CustomProductUrls/Helper/Data.php +161 -0
  7. app/code/community/Mklauza/CustomProductUrls/Model/Adminhtml/Observer.php +125 -0
  8. app/code/community/Mklauza/CustomProductUrls/Model/Catalog/Product/Url.php +41 -0
  9. app/code/community/Mklauza/CustomProductUrls/Model/Catalog/Resource/Product/Action.php +97 -0
  10. app/code/community/Mklauza/CustomProductUrls/Model/Catalog/Resource/Product/Attribute/Backend/_Urlkey.php +46 -0
  11. app/code/community/Mklauza/CustomProductUrls/controllers/Adminhtml/Catalog/Product/Action/ProductUrlsMassActionController.php +211 -0
  12. app/code/community/Mklauza/CustomProductUrls/controllers/Adminhtml/ProductUrlsController.php +57 -0
  13. app/code/community/Mklauza/CustomProductUrls/etc/adminhtml.xml +42 -0
  14. app/code/community/Mklauza/CustomProductUrls/etc/config.xml +98 -0
  15. app/code/community/Mklauza/CustomProductUrls/etc/system.xml +59 -0
  16. app/design/adminhtml/default/default/layout/mklauza/product_urls.xml +31 -0
  17. app/design/adminhtml/default/default/template/mklauza/customproducturls/massaction.phtml +363 -0
  18. app/design/adminhtml/default/default/template/mklauza/customproducturls/system/settings.phtml +356 -0
  19. app/etc/modules/Mklauza_CustomProductUrls.xml +15 -0
  20. package.xml +18 -0
app/code/community/Mklauza/CustomProductUrls/Block/Adminhtml/Form/Abstract.php ADDED
@@ -0,0 +1,129 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Marcin Klauza - Magento developer
4
+ * http://www.marcinklauza.com
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Open Software License (OSL 3.0)
9
+ * that is bundled with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://opensource.org/licenses/osl-3.0.php
12
+ * If you did not receive a copy of the license and are unable to
13
+ * obtain it through the world-wide-web, please send an email
14
+ * to marcinklauza@gmail.com so we can send you a copy immediately.
15
+ *
16
+ * @category Mklauza
17
+ * @package Mklauza_CustomProductUrls
18
+ * @author Marcin Klauza <marcinklauza@gmail.com>
19
+ * @copyright Copyright (c) 2015 (Marcin Klauza)
20
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
21
+ */
22
+
23
+ abstract class Mklauza_CustomProductUrls_Block_Adminhtml_Form_Abstract extends Mage_Adminhtml_Block_Template {
24
+
25
+ // private $_attributesCollection;
26
+ // private $_productAttributes;
27
+ private $_patternChunks;
28
+ private $_attributesChunks;
29
+ private $_patternStr;
30
+ private $_allowedFormats = array('price');//, 'date', 'price', 'wee');
31
+
32
+ public function getSubmitUrl() {
33
+ throw new Exception($this->_getHelper->__('Implemet ' . get_class($this) . '::getSubmitUrl() method.'));
34
+ }
35
+
36
+ public function getExampleUrl() {
37
+ return Mage::helper('adminhtml')->getUrl('adminhtml/ProductUrls/example');
38
+ }
39
+
40
+ public function setPatternStr($pattern) {
41
+ $this->_patternStr = $pattern;
42
+ }
43
+
44
+ public function getPatternStr() {
45
+ if($this->_patternStr === null) {
46
+ if(Mage::app()->getRequest()->getParam('pattern', null)) {
47
+ $this->_patternStr = Mage::app()->getRequest()->getParam('pattern');
48
+ } else {
49
+ $this->_patternStr = Mage::getStoreConfig('mklauza_customproducturls/general/pattern');
50
+ }
51
+ }
52
+ return $this->_patternStr;
53
+ }
54
+
55
+ private function chunkToHtmlElement(array $chunk = null) {
56
+ if(!$chunk || !isset($chunk['value']) || !isset($chunk['type'])) {
57
+ return '';
58
+ }
59
+
60
+ if($chunk['type'] === 'attribute') {
61
+ $attributes = $this->getProductAttributes();
62
+ $attrId = $chunk['value'];
63
+ return '<span class="inputTags-item blocked" data-value="' . $attrId . '">'
64
+ . '<span class="value">' . $attributes[$attrId] . '</span>'
65
+ .'</span>';
66
+ } elseif($chunk['type'] === 'text') {
67
+ return '<input type="text" class="inputTags-field" value="' . $chunk['value'] . '"/>';
68
+ }
69
+ }
70
+
71
+ public function getAttributesCollection() {
72
+ return $this->_getHelper()->getAttributesCollection();
73
+ }
74
+
75
+ public function getProductAttributes() {
76
+ return $this->_getHelper()->getProductAttributes();
77
+ }
78
+
79
+ public function getPatternChunks() {
80
+ if($this->_patternChunks === null) {
81
+ $urlPattern = $this->getPatternStr();
82
+ $this->_patternChunks = $this->_getHelper()->extractChunks($urlPattern);
83
+ }
84
+ return $this->_patternChunks;
85
+ }
86
+
87
+ public function getPatternHtml() {
88
+
89
+ $chunks = $this->getPatternChunks();
90
+ $html = '';
91
+ foreach ($chunks as $_chunk) {
92
+ $html .= $this->chunkToHtmlElement($_chunk);
93
+ }
94
+
95
+ return $html;
96
+ }
97
+
98
+ public function getAttributesChunks() {
99
+ if($this->_attributesChunks === null) {
100
+ $attributes = $this->getProductAttributes();
101
+ $patternChunks = $this->getPatternChunks();
102
+ foreach($patternChunks as $chunk) {
103
+ if($chunk['type'] === 'attribute') {
104
+ $attrId = $chunk['value'];
105
+ unset($attributes[$attrId]);
106
+ }
107
+ }
108
+ $this->_attributesChunks = array();
109
+ foreach($attributes as $id => $name) {
110
+ $this->_attributesChunks[] = array('value' => $id, 'type' => 'attribute');
111
+ }
112
+ }
113
+ return $this->_attributesChunks;
114
+ }
115
+
116
+ public function getAttributesCloudHtml() {
117
+ $chunks = $this->getAttributesChunks();
118
+ $html = '';
119
+ foreach ($chunks as $_chunk) {
120
+ $html .= $this->chunkToHtmlElement($_chunk);
121
+ }
122
+ return $html;
123
+ }
124
+
125
+ protected function _getHelper() {
126
+ return Mage::helper('mklauza_customproducturls');
127
+ }
128
+
129
+ }
app/code/community/Mklauza/CustomProductUrls/Block/Adminhtml/Form/Pattern.php ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Marcin Klauza - Magento developer
4
+ * http://www.marcinklauza.com
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Open Software License (OSL 3.0)
9
+ * that is bundled with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://opensource.org/licenses/osl-3.0.php
12
+ * If you did not receive a copy of the license and are unable to
13
+ * obtain it through the world-wide-web, please send an email
14
+ * to marcinklauza@gmail.com so we can send you a copy immediately.
15
+ *
16
+ * @category Mklauza
17
+ * @package Mklauza_CustomProductUrls
18
+ * @author Marcin Klauza <marcinklauza@gmail.com>
19
+ * @copyright Copyright (c) 2015 (Marcin Klauza)
20
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
21
+ */
22
+
23
+ class Mklauza_CustomProductUrls_Block_Adminhtml_Form_Pattern extends Mage_Adminhtml_Block_System_Config_Form_Field {
24
+
25
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
26
+ {
27
+ // $this->setElement($element);
28
+ $element->setType('hidden');
29
+ $html = $this->getLayout()->createBlock('mklauza_customproducturls/adminhtml_settingsform')
30
+ ->setElement($element)
31
+ ->toHtml();
32
+
33
+ return $html;
34
+ }
35
+
36
+ /**
37
+ * Enter description here...
38
+ *
39
+ * @param Varien_Data_Form_Element_Abstract $element
40
+ * @return string
41
+ */
42
+ public function render(Varien_Data_Form_Element_Abstract $element)
43
+ {
44
+ $id = $element->getHtmlId();
45
+
46
+ $html = '<td class="label"><label for="'.$id.'">'.$element->getLabel().'</label></td>';
47
+
48
+ //$isDefault = !$this->getRequest()->getParam('website') && !$this->getRequest()->getParam('store');
49
+ $isMultiple = $element->getExtType()==='multiple';
50
+
51
+ // replace [value] with [inherit]
52
+ $namePrefix = preg_replace('#\[value\](\[\])?$#', '', $element->getName());
53
+
54
+ $options = $element->getValues();
55
+
56
+ $addInheritCheckbox = false;
57
+ if ($element->getCanUseWebsiteValue()) {
58
+ $addInheritCheckbox = true;
59
+ $checkboxLabel = $this->__('Use Website');
60
+ }
61
+ elseif ($element->getCanUseDefaultValue()) {
62
+ $addInheritCheckbox = true;
63
+ $checkboxLabel = $this->__('Use Default');
64
+ }
65
+
66
+ if ($addInheritCheckbox) {
67
+ $inherit = $element->getInherit()==1 ? 'checked="checked"' : '';
68
+ if ($inherit) {
69
+ $element->setDisabled(true);
70
+ }
71
+ }
72
+
73
+ if ($element->getTooltip()) {
74
+ $html .= '<td class="value with-tooltip">';
75
+ $html .= $this->_getElementHtml($element);
76
+ $html .= '<div class="field-tooltip"><div>' . $element->getTooltip() . '</div></div>';
77
+ } else {
78
+ $html .= '<td class="value" colspan="2" style="width:auto;">';
79
+ $html .= $this->_getElementHtml($element);
80
+ };
81
+ if ($element->getComment()) {
82
+ $html.= '<p class="note"><span>'.$element->getComment().'</span></p>';
83
+ }
84
+ $html.= '</td>';
85
+
86
+ if ($addInheritCheckbox) {
87
+
88
+ $defText = $element->getDefaultValue();
89
+ if ($options) {
90
+ $defTextArr = array();
91
+ foreach ($options as $k=>$v) {
92
+ if ($isMultiple) {
93
+ if (is_array($v['value']) && in_array($k, $v['value'])) {
94
+ $defTextArr[] = $v['label'];
95
+ }
96
+ } elseif (isset($v['value'])) {
97
+ if ($v['value'] == $defText) {
98
+ $defTextArr[] = $v['label'];
99
+ break;
100
+ }
101
+ } elseif (!is_array($v)) {
102
+ if ($k == $defText) {
103
+ $defTextArr[] = $v;
104
+ break;
105
+ }
106
+ }
107
+ }
108
+ $defText = join(', ', $defTextArr);
109
+ }
110
+
111
+ // default value
112
+ $html.= '<td class="use-default">';
113
+ $html.= '<input id="' . $id . '_inherit" name="'
114
+ . $namePrefix . '[inherit]" type="checkbox" value="1" class="checkbox config-inherit" '
115
+ . $inherit . ' onclick="toggleValueElements(this, Element.previous(this.parentNode))" /> ';
116
+ $html.= '<label for="' . $id . '_inherit" class="inherit" title="'
117
+ . htmlspecialchars($defText) . '">' . $checkboxLabel . '</label>';
118
+ $html.= '</td>';
119
+ }
120
+
121
+ $html.= '<td class="scope-label">';
122
+ if ($element->getScope()) {
123
+ $html .= $element->getScopeLabel();
124
+ }
125
+ $html.= '</td>';
126
+
127
+ $html.= '<td class="">';
128
+ if ($element->getHint()) {
129
+ $html.= '<div class="hint" >';
130
+ $html.= '<div style="display: none;">' . $element->getHint() . '</div>';
131
+ $html.= '</div>';
132
+ }
133
+ $html.= '</td>';
134
+
135
+ return $this->_decorateRowHtml($element, $html);
136
+ }
137
+
138
+ }
app/code/community/Mklauza/CustomProductUrls/Block/Adminhtml/MassActionForm.php ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Marcin Klauza - Magento developer
4
+ * http://www.marcinklauza.com
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Open Software License (OSL 3.0)
9
+ * that is bundled with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://opensource.org/licenses/osl-3.0.php
12
+ * If you did not receive a copy of the license and are unable to
13
+ * obtain it through the world-wide-web, please send an email
14
+ * to marcinklauza@gmail.com so we can send you a copy immediately.
15
+ *
16
+ * @category Mklauza
17
+ * @package Mklauza_CustomProductUrls
18
+ * @author Marcin Klauza <marcinklauza@gmail.com>
19
+ * @copyright Copyright (c) 2015 (Marcin Klauza)
20
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
21
+ */
22
+
23
+ class Mklauza_CustomProductUrls_Block_Adminhtml_MassActionForm extends Mklauza_CustomProductUrls_Block_Adminhtml_Form_Abstract {
24
+
25
+ public function _construct() {
26
+ parent::_construct();
27
+ $this->setTemplate('mklauza/customproducturls/massaction.phtml');
28
+ }
29
+
30
+ public function getSubmitUrl() {
31
+ return Mage::helper('adminhtml')->getUrl('adminhtml/ProductUrlsMassAction/save');
32
+ }
33
+
34
+ public function getSaveRewritesHistory() {
35
+ return Mage::getStoreConfigFlag('catalog/seo/save_rewrites_history');
36
+ }
37
+
38
+ }
app/code/community/Mklauza/CustomProductUrls/Block/Adminhtml/SettingsForm.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Marcin Klauza - Magento developer
4
+ * http://www.marcinklauza.com
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Open Software License (OSL 3.0)
9
+ * that is bundled with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://opensource.org/licenses/osl-3.0.php
12
+ * If you did not receive a copy of the license and are unable to
13
+ * obtain it through the world-wide-web, please send an email
14
+ * to marcinklauza@gmail.com so we can send you a copy immediately.
15
+ *
16
+ * @category Mklauza
17
+ * @package Mklauza_CustomProductUrls
18
+ * @author Marcin Klauza <marcinklauza@gmail.com>
19
+ * @copyright Copyright (c) 2015 (Marcin Klauza)
20
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
21
+ */
22
+
23
+ class Mklauza_CustomProductUrls_Block_Adminhtml_SettingsForm extends Mklauza_CustomProductUrls_Block_Adminhtml_Form_Abstract {
24
+
25
+ public function _construct() {
26
+ parent::_construct();
27
+ $this->setTemplate('mklauza/customproducturls/system/settings.phtml');
28
+ }
29
+
30
+ public function getSubmitUrl() {
31
+ return Mage::helper('adminhtml')->getUrl('adminhtml/ProductUrls/save');
32
+ }
33
+
34
+ public function getIsEnabled() {
35
+ return $this->_getHelper()->getIsEnabled();
36
+ }
37
+
38
+ public function getApplyToNewFlag() {
39
+ return $this->_getHelper()->getApplyToNewFlag();
40
+ }
41
+
42
+ }
app/code/community/Mklauza/CustomProductUrls/Block/Adminhtml/Urlrewrite/Grid.php ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Open Software License (OSL 3.0)
8
+ * that is bundled with this package in the file LICENSE.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/osl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magento.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magento.com for more information.
20
+ *
21
+ * @category Mage
22
+ * @package Mage_Adminhtml
23
+ * @copyright Copyright (c) 2006-2015 X.commerce, Inc. (http://www.magento.com)
24
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
25
+ */
26
+
27
+ /**
28
+ * Adminhtml urlrewrite grid block
29
+ *
30
+ * @category Mage
31
+ * @package Mage_Adminhtml
32
+ * @author Magento Core Team <core@magentocommerce.com>
33
+ */
34
+ class Mklauza_CustomProductUrls_Adminhtml_Block_Urlrewrite_Grid extends Mage_Adminhtml_Block_Urlrewrite_Grid
35
+ {
36
+
37
+ protected function _prepareColumns()
38
+ {
39
+ $this->addColumn('url_rewrite_id', array(
40
+ 'header' => $this->__('ID'),
41
+ 'width' => '50px',
42
+ 'index' => 'url_rewrite_id'
43
+ ));
44
+
45
+ if (!Mage::app()->isSingleStoreMode()) {
46
+ $this->addColumn('store_id', array(
47
+ 'header' => $this->__('Store View'),
48
+ 'width' => '200px',
49
+ 'index' => 'store_id',
50
+ 'type' => 'store',
51
+ 'store_view' => true,
52
+ ));
53
+ }
54
+
55
+ $this->addColumn('is_system', array(
56
+ 'header' =>$this->__('Type'),
57
+ 'width' => '50px',
58
+ 'index' => 'is_system',
59
+ 'type' => 'options',
60
+ 'options' => array(
61
+ 1 => $this->__('System'),
62
+ 0 => $this->__('Custom')
63
+ ),
64
+ ));
65
+
66
+ $this->addColumn('id_path', array(
67
+ 'header' => $this->__('ID Path'),
68
+ 'width' => '50px',
69
+ 'index' => 'id_path'
70
+ ));
71
+ $this->addColumn('request_path', array(
72
+ 'header' => $this->__('Request Path'),
73
+ 'width' => '50px',
74
+ 'index' => 'request_path'
75
+ ));
76
+ $this->addColumn('target_path', array(
77
+ 'header' => $this->__('Target Path'),
78
+ 'width' => '50px',
79
+ 'index' => 'target_path'
80
+ ));
81
+ $this->addColumn('options', array(
82
+ 'header' => $this->__('Options'),
83
+ 'width' => '50px',
84
+ 'index' => 'options'
85
+ ));
86
+ $this->addColumn('actions', array(
87
+ 'header' => $this->__('Action'),
88
+ 'width' => '15px',
89
+ 'sortable' => false,
90
+ 'filter' => false,
91
+ 'type' => 'action',
92
+ 'actions' => array(
93
+ array(
94
+ 'url' => $this->getUrl('*/*/edit') . 'id/$url_rewrite_id',
95
+ 'caption' => $this->__('Edit'),
96
+ ),
97
+ )
98
+ ));
99
+ $this->addExportType('*/*/exportCsv', $this->__('CSV'));
100
+ $this->addExportType('*/*/exportXml', $this->__('XML'));
101
+ return parent::_prepareColumns();
102
+ }
103
+
104
+
105
+ protected function _prepareMassaction()
106
+ {
107
+ $this->setMassactionIdField('entity_id');
108
+ $this->getMassactionBlock()->setFormFieldName('product');
109
+
110
+ $this->getMassactionBlock()->addItem('delete', array(
111
+ 'label'=> Mage::helper('catalog')->__('Delete'),
112
+ 'url' => $this->getUrl('*/*/massDelete'),
113
+ 'confirm' => Mage::helper('catalog')->__('Are you sure?')
114
+ ));
115
+
116
+ // $statuses = Mage::getSingleton('catalog/product_status')->getOptionArray();
117
+ //
118
+ // array_unshift($statuses, array('label'=>'', 'value'=>''));
119
+ // $this->getMassactionBlock()->addItem('status', array(
120
+ // 'label'=> Mage::helper('catalog')->__('Change status'),
121
+ // 'url' => $this->getUrl('*/*/massStatus', array('_current'=>true)),
122
+ // 'additional' => array(
123
+ // 'visibility' => array(
124
+ // 'name' => 'status',
125
+ // 'type' => 'select',
126
+ // 'class' => 'required-entry',
127
+ // 'label' => Mage::helper('catalog')->__('Status'),
128
+ // 'values' => $statuses
129
+ // )
130
+ // )
131
+ // ));
132
+
133
+ Mage::dispatchEvent('adminhtml_catalog_product_grid_prepare_massaction', array('block' => $this));
134
+ return $this;
135
+ }
136
+
137
+ }
138
+
app/code/community/Mklauza/CustomProductUrls/Helper/Data.php ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Marcin Klauza - Magento developer
4
+ * http://www.marcinklauza.com
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Open Software License (OSL 3.0)
9
+ * that is bundled with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://opensource.org/licenses/osl-3.0.php
12
+ * If you did not receive a copy of the license and are unable to
13
+ * obtain it through the world-wide-web, please send an email
14
+ * to marcinklauza@gmail.com so we can send you a copy immediately.
15
+ *
16
+ * @category Mklauza
17
+ * @package Mklauza_CustomProductUrls
18
+ * @author Marcin Klauza <marcinklauza@gmail.com>
19
+ * @copyright Copyright (c) 2015 (Marcin Klauza)
20
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
21
+ */
22
+
23
+ class Mklauza_CustomProductUrls_Helper_Data extends Mage_Core_Helper_Abstract {
24
+
25
+ private $_attributesCollection;
26
+ private $_productAttributes;
27
+ private $_patternChunks;
28
+
29
+ public function getIsEnabled() {
30
+ return Mage::getStoreConfigFlag('mklauza_customproducturls/general/is_active');
31
+ }
32
+
33
+ public function getApplyToNewFlag() {
34
+ return Mage::getStoreConfigFlag('mklauza_customproducturls/general/apply_to_new');
35
+ }
36
+
37
+ public function getConfigPattern() {
38
+ return Mage::getStoreConfig('mklauza_customproducturls/general/pattern');
39
+ }
40
+
41
+ public function getAttributesCollection() {
42
+ if($this->_attributesCollection === null) {
43
+ $this->_attributesCollection = Mage::getResourceModel('catalog/product_attribute_collection')
44
+ ->addVisibleFilter('is_visible_on_front', array('=' => '1'))
45
+ ->addFieldTofilter('attribute_code', array('neq' => 'url_key'));
46
+ }
47
+ return $this->_attributesCollection;
48
+ }
49
+
50
+ public function getProductAttributes() {
51
+ if($this->_productAttributes === null) {
52
+
53
+ $attributes = array();
54
+ foreach ($this->getAttributesCollection() as $productAttr) { /** @var Mage_Catalog_Model_Resource_Eav_Attribute $productAttr */
55
+ $attributes[$productAttr->getAttributeCode()] = $this->jsQuoteEscape($productAttr->getFrontendLabel());
56
+ }
57
+ $this->_productAttributes = $attributes;
58
+ }
59
+ return $this->_productAttributes;
60
+ }
61
+
62
+ public function extractChunks($urlPattern = '') {
63
+ $regex = '/(\{(\w+)\})?([^\{\}]+)?/';
64
+
65
+ $chunks = array();
66
+ $doesMatch = true;
67
+ while(strlen($urlPattern) && $doesMatch)
68
+ {
69
+ $matches = array();
70
+ $doesMatch = preg_match($regex, $urlPattern, $matches);
71
+ if(!empty($matches[2])) {
72
+ $chunks[] = array('value' => $matches[2], 'type' => 'attribute');
73
+ }
74
+ if(!empty($matches[3])) {
75
+ $chunks[] = array('value' => $matches[3], 'type' => 'text');
76
+ }
77
+
78
+ $urlPattern = str_replace($matches[0], '', $urlPattern);
79
+ }
80
+
81
+ return $chunks;
82
+ }
83
+
84
+ public function getPatternChunks($urlPattern) {
85
+ if($this->_patternChunks === null) {
86
+ $this->_patternChunks = $this->extractChunks($urlPattern);
87
+ }
88
+ return $this->_patternChunks;
89
+ }
90
+
91
+ private function _getPatternAttributes() {
92
+ $chunks = $this->getPatternChunks();
93
+ foreach($chunks as $chunk) {
94
+ if($chunk['type'] === 'attribute') {
95
+ $attributes[] = $chunk['value'];
96
+ }
97
+ }
98
+ $attributes = array_flip($attributes);
99
+ foreach($attributes as $_code => $val) {
100
+ $attribute = Mage::getSingleton('eav/config')
101
+ ->getAttribute(Mage_Catalog_Model_Product::ENTITY, $_code);
102
+ if ($attribute->usesSource()) {
103
+ $htmlOptions = $attribute->getSource()->getAllOptions(false);
104
+ if($htmlOptions && is_array($htmlOptions) && count($htmlOptions))
105
+ {
106
+ $options = array();
107
+ foreach($htmlOptions as $option) {
108
+ $options[$option['value']] = $option['label'];
109
+ }
110
+ $attributes[$_code]= $options;
111
+ }
112
+ }
113
+ }
114
+ return $attributes;
115
+ }
116
+
117
+ public function prepareUrlKey($productId, $urlPattern, $storeId) {
118
+ $chunks = $this->getPatternChunks($urlPattern);
119
+ $patternAttributes = $this->_getPatternAttributes();
120
+
121
+ foreach($patternAttributes as $code => &$value) {
122
+ $rawValue = Mage::getModel('catalog/product')->getResource()->getAttributeRawValue($productId, $code, $storeId);
123
+ // options
124
+ if(is_array($value)) {
125
+ $textOption = $value[$rawValue];
126
+ $value = $textOption;
127
+ } elseif($code === 'price') {
128
+ $value = number_format($rawValue, 2);
129
+ } else {
130
+ $value = $rawValue;
131
+ }
132
+ }
133
+
134
+ $url_str = '';
135
+ foreach($chunks as $chunk) {
136
+ if($chunk['type'] === 'attribute') {
137
+ $attrCode = $chunk['value'];
138
+ $url_str .= $patternAttributes[$attrCode];
139
+ } elseif($chunk['type'] === 'text') {
140
+ $url_str .= $chunk['value'];
141
+ }
142
+ }
143
+
144
+ return $url_str;
145
+ }
146
+
147
+ public function getRandomExample($pattern) {
148
+ $storeId = Mage::app()->getStore()->getStoreId();
149
+
150
+ // get random product Id
151
+ $collection = Mage::getResourceModel('catalog/product_collection')
152
+ ->addStoreFilter($storeId)
153
+ ->addFieldToFilter('visibility', array('neq' => Mage_Catalog_Model_Product_Visibility::VISIBILITY_NOT_VISIBLE));
154
+ $collection->getSelect()->reset(Zend_Db_Select::COLUMNS)->columns('entity_id')->order(new Zend_Db_Expr('RAND()'))->limit(1);
155
+ $productId = $collection->getFirstItem()->getId();
156
+ $url_key = $this->prepareUrlKey($productId, $pattern, $storeId);
157
+ $url_key = Mage::getModel('catalog/product_url')->formatUrlKey($url_key);
158
+ return Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB) . $url_key . Mage::getStoreConfig('catalog/seo/product_url_suffix');
159
+ }
160
+
161
+ }
app/code/community/Mklauza/CustomProductUrls/Model/Adminhtml/Observer.php ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Marcin Klauza - Magento developer
4
+ * http://www.marcinklauza.com
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Open Software License (OSL 3.0)
9
+ * that is bundled with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://opensource.org/licenses/osl-3.0.php
12
+ * If you did not receive a copy of the license and are unable to
13
+ * obtain it through the world-wide-web, please send an email
14
+ * to marcinklauza@gmail.com so we can send you a copy immediately.
15
+ *
16
+ * @category Mklauza
17
+ * @package Mklauza_CustomProductUrls
18
+ * @author Marcin Klauza <marcinklauza@gmail.com>
19
+ * @copyright Copyright (c) 2015 (Marcin Klauza)
20
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
21
+ */
22
+
23
+ class Mklauza_CustomProductUrls_Model_Adminhtml_Observer {
24
+
25
+ public function addCustomUrlsMassAction(Varien_Event_Observer $observer) { // adminhtml_block_html_before
26
+
27
+ $block = $observer->getEvent()->getBlock();
28
+ if (Mage::helper('mklauza_customproducturls')->getIsEnabled() && $block instanceof Mage_Adminhtml_Block_Catalog_Product_Grid) {
29
+ $block->setMassactionIdField('mklauza_customproducturls_massaction');
30
+ $block->getMassactionBlock()->setFormFieldName('product');
31
+ $block->getMassactionBlock()->setUseSelectAll(false);
32
+
33
+ $block->getMassactionBlock()->addItem('mklauza_customproducturls', array(
34
+ 'label' => 'Set custom URL',
35
+ // 'url' => $block->getUrl('*/productUrls'),
36
+ 'url' => $block->getUrl('*/productUrlsMassAction/edit'),
37
+ ));
38
+
39
+ // $columnId = 'massaction';
40
+ //
41
+ // $massactionColumn = array(
42
+ // 'index' => $block->getMassactionIdField(),
43
+ // 'filter_index' => $block->getMassactionIdFilter(),
44
+ // 'type' => 'massaction',
45
+ // 'name' => $block->getMassactionBlock()->getFormFieldName(),
46
+ // 'align' => 'center',
47
+ // 'is_system' => true
48
+ // );
49
+ //
50
+ // if ($block->getNoFilterMassactionColumn()) {
51
+ // $massactionColumn->setData('filter', false);
52
+ // }
53
+ //
54
+ // // rearrange the columns;
55
+ // $oldColumns = $block->getColumns();
56
+ // foreach($oldColumns as $column){
57
+ // $block->removeColumn($column->getId());
58
+ // }
59
+
60
+ // $block->addColumn($columnId, $massactionColumn);
61
+ // $block->addColumn('block_id', array(
62
+ // 'header' => Mage::helper('cms')->__('ID'),
63
+ // 'width' => '50px',
64
+ // 'type' => 'number',
65
+ // 'index' => 'block_id',
66
+ // ));
67
+
68
+ // put back the original columns
69
+ // foreach($oldColumns as $column){
70
+ // $block->addColumn($column->getId(),$column->getData());
71
+ // }
72
+
73
+ return $this;
74
+ }
75
+ }
76
+
77
+ public function addClearPermanentRedirectsButton(Varien_Event_Observer $observer) {
78
+ $block = $observer->getEvent()->getBlock();
79
+ if (Mage::helper('mklauza_customproducturls')->getIsEnabled() && $block instanceof Mage_Adminhtml_Block_Urlrewrite) {
80
+ $block->addButton('clear', array(
81
+ 'label' => Mage::helper('mklauza_customproducturls')->__('Clear Rewrite History'),
82
+ 'onclick' => 'setLocation(\'' . Mage::helper('adminhtml')->getUrl('adminhtml/ProductUrlsMassAction/clearRedirects') .'\')',
83
+ 'class' => 'delete',
84
+ ));
85
+ }
86
+ }
87
+
88
+ public function generateUrlKey(Varien_Event_Observer $observer) { // catalog_product_save_after
89
+ $product = $observer->getEvent()->getProduct();
90
+
91
+ if(Mage::registry('generate_url') && $product->getId()) { // in case we save product with empty url key
92
+ // && !($product->getTypeId() == 'simple' && $product->getAttributeSetId() == $this->getAttributeSetId('prenumerata'))
93
+
94
+ $urlPattern = Mage::helper('mklauza_customproducturls')->getConfigPattern();
95
+ $storeId = Mage::app()->getStore()->getId();
96
+
97
+ $url_key = Mage::helper('mklauza_customproducturls')->prepareUrlKey($product->getId(), $urlPattern, $storeId);
98
+ $product->setUrlKey($url_key)->getResource()->saveAttribute($product, 'url_key');
99
+ Mage::unregister('generate_url');
100
+ }
101
+
102
+ return $this;
103
+ }
104
+
105
+ /*
106
+ * Checks whether
107
+ */
108
+ public function checkUrl(Varien_Event_Observer $observer) { // catalog_product_prepare_save
109
+ $product = $observer->getEvent()->getProduct();
110
+
111
+ if(Mage::helper('mklauza_customproducturls')->getApplyToNewFlag()) {
112
+ $generate_url = Mage::registry('generate_url');
113
+ if(!$generate_url && $product && !$product->getUrlKey()) {
114
+ Mage::register('generate_url', true, $graceful=true); // we set up session flag to workaround default magento url generation in save after
115
+ }
116
+ }
117
+
118
+ return $this;
119
+ }
120
+
121
+
122
+
123
+
124
+
125
+ }
app/code/community/Mklauza/CustomProductUrls/Model/Catalog/Product/Url.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Marcin Klauza - Magento developer
4
+ * http://www.marcinklauza.com
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Open Software License (OSL 3.0)
9
+ * that is bundled with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://opensource.org/licenses/osl-3.0.php
12
+ * If you did not receive a copy of the license and are unable to
13
+ * obtain it through the world-wide-web, please send an email
14
+ * to marcinklauza@gmail.com so we can send you a copy immediately.
15
+ *
16
+ * @category Mklauza
17
+ * @package Mklauza_CustomProductUrls
18
+ * @author Marcin Klauza <marcinklauza@gmail.com>
19
+ * @copyright Copyright (c) 2015 (Marcin Klauza)
20
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
21
+ */
22
+
23
+ class Mklauza_CustomProductUrls_Model_Catalog_Product_Url extends Mage_Catalog_Model_Product_Url
24
+ {
25
+ /**
26
+ * Format Key for URL
27
+ *
28
+ * @param string $str
29
+ * @return string
30
+ */
31
+ public function formatUrlKey($str)
32
+ {
33
+ // added '/' sign
34
+ $urlKey = preg_replace('#[^0-9a-z\/.]+#i', '-', Mage::helper('catalog/product_url')->format($str));
35
+ $urlKey = strtolower($urlKey);
36
+ $urlKey = trim($urlKey, '-');
37
+
38
+ return $urlKey;
39
+ }
40
+
41
+ }
app/code/community/Mklauza/CustomProductUrls/Model/Catalog/Resource/Product/Action.php ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Marcin Klauza - Magento developer
4
+ * http://www.marcinklauza.com
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Open Software License (OSL 3.0)
9
+ * that is bundled with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://opensource.org/licenses/osl-3.0.php
12
+ * If you did not receive a copy of the license and are unable to
13
+ * obtain it through the world-wide-web, please send an email
14
+ * to marcinklauza@gmail.com so we can send you a copy immediately.
15
+ *
16
+ * @category Mklauza
17
+ * @package Mklauza_CustomProductUrls
18
+ * @author Marcin Klauza <marcinklauza@gmail.com>
19
+ * @copyright Copyright (c) 2015 (Marcin Klauza)
20
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
21
+ */
22
+
23
+ class Mklauza_CustomProductUrls_Model_Catalog_Resource_Product_Action extends Mage_Catalog_Model_Resource_Abstract
24
+ {
25
+ /**
26
+ * Intialize connection
27
+ *
28
+ */
29
+ protected function _construct()
30
+ {
31
+ $resource = Mage::getSingleton('core/resource');
32
+ $this->setType(Mage_Catalog_Model_Product::ENTITY)
33
+ ->setConnection(
34
+ $resource->getConnection('catalog_read'),
35
+ $resource->getConnection('catalog_write')
36
+ );
37
+ }
38
+
39
+ /**
40
+ * Update attribute values for entity list per store
41
+ *
42
+ * @param array $entityIds
43
+ * @param array $attrData
44
+ * @param int $storeId
45
+ * @return Mage_Catalog_Model_Resource_Product_Action
46
+ */
47
+ public function updateUrlKeyAttributes($entityIds, $urlPattern, $urlKeyCreateRedirect, $storeId)
48
+ {
49
+ $object = new Varien_Object();
50
+ $object->setIdFieldName('entity_id')
51
+ ->setStoreId($storeId);
52
+
53
+ // $origSaveHistory = Mage::getStoreConfigFlag('catalog/seo/save_rewrites_history');
54
+ // Mage::register('save_rewrite_history', $origSaveHistory);
55
+ Mage::getSingleton('core/config')->saveConfig('catalog/seo/save_rewrites_history', (bool) $urlKeyCreateRedirect);
56
+ Mage::app()->getConfig()->reinit();
57
+
58
+ $this->_getWriteAdapter()->beginTransaction();
59
+ try {
60
+ $attribute = $this->getAttribute('url_key');
61
+ if (!$attribute->getAttributeId()) {
62
+ return null;
63
+ }
64
+
65
+ $i = 0;
66
+ foreach ($entityIds as $entityId) {
67
+ $i++;
68
+ $object->setId($entityId);
69
+
70
+ // $object->setData('save_rewrites_history', $urlKeyCreateRedirect);
71
+ // $object->save();
72
+ // $rewriteAttribute = $this->getAttribute('save_rewrites_history');
73
+ // $this->_saveAttributeValue($object, $rewriteAttribute, $urlKeyCreateRedirect);
74
+
75
+ $value = $this->_getHelper()->prepareUrlKey($entityId, $urlPattern, $storeId);
76
+ // collect data for save
77
+ $this->_saveAttributeValue($object, $attribute, $value);
78
+ // save collected data every 1000 rows
79
+ if ($i % 1000 == 0) {
80
+ $this->_processAttributeValues();
81
+ }
82
+ }
83
+ $this->_processAttributeValues();
84
+ $this->_getWriteAdapter()->commit();
85
+ } catch (Exception $e) {
86
+ $this->_getWriteAdapter()->rollBack();
87
+ throw $e;
88
+ }
89
+
90
+ // Mage::getSingleton('core/config')->saveConfig('catalog/seo/save_rewrites_history', $origSaveHistory);
91
+ return $this;
92
+ }
93
+
94
+ private function _getHelper() {
95
+ return Mage::helper('mklauza_customproducturls');
96
+ }
97
+ }
app/code/community/Mklauza/CustomProductUrls/Model/Catalog/Resource/Product/Attribute/Backend/_Urlkey.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Marcin Klauza - Magento developer
4
+ * http://www.marcinklauza.com
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Open Software License (OSL 3.0)
9
+ * that is bundled with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://opensource.org/licenses/osl-3.0.php
12
+ * If you did not receive a copy of the license and are unable to
13
+ * obtain it through the world-wide-web, please send an email
14
+ * to marcinklauza@gmail.com so we can send you a copy immediately.
15
+ *
16
+ * @category Mklauza
17
+ * @package Mklauza_CustomProductUrls
18
+ * @author Marcin Klauza <marcinklauza@gmail.com>
19
+ * @copyright Copyright (c) 2015 (Marcin Klauza)
20
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
21
+ */
22
+
23
+ class Mklauza_CustomProductUrls_Model_Catalog_Resource_Product_Attribute_Backend_Urlkey
24
+ extends Mage_Catalog_Model_Product_Attribute_Backend_Urlkey
25
+ {
26
+ /**
27
+ * Before save
28
+ *
29
+ * @param Varien_Object $object
30
+ * @return Mage_Catalog_Model_Resource_Product_Attribute_Backend_Urlkey
31
+ * @overridden
32
+ */
33
+ public function beforeSave($object)
34
+ {
35
+ $attributeName = $this->getAttribute()->getName();
36
+
37
+ $urlKey = $object->getData($attributeName);
38
+ if ($urlKey == '') {
39
+ $urlKey = Mage::helper('mklauza_customproducturls')->prepareUrlKey($object);
40
+ }
41
+ $object->setData($attributeName, $object->formatUrlKey($urlKey));
42
+
43
+ return $this;
44
+ }
45
+
46
+ }
app/code/community/Mklauza/CustomProductUrls/controllers/Adminhtml/Catalog/Product/Action/ProductUrlsMassActionController.php ADDED
@@ -0,0 +1,211 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Marcin Klauza - Magento developer
4
+ * http://www.marcinklauza.com
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Open Software License (OSL 3.0)
9
+ * that is bundled with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://opensource.org/licenses/osl-3.0.php
12
+ * If you did not receive a copy of the license and are unable to
13
+ * obtain it through the world-wide-web, please send an email
14
+ * to marcinklauza@gmail.com so we can send you a copy immediately.
15
+ *
16
+ * @category Mklauza
17
+ * @package Mklauza_CustomProductUrls
18
+ * @author Marcin Klauza <marcinklauza@gmail.com>
19
+ * @copyright Copyright (c) 2015 (Marcin Klauza)
20
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
21
+ */
22
+
23
+ class Mklauza_CustomProductUrls_Adminhtml_Catalog_Product_Action_ProductUrlsMassActionController extends Mage_Adminhtml_Controller_Action {
24
+
25
+ // @overridden
26
+ public function preDispatch() {
27
+ parent::preDispatch();
28
+ if(!Mage::GetStoreConfigFlag('mklauza_customproducturls/general/is_active')) {
29
+ $this->_redirect('adminhtml/dashboard');
30
+ return;
31
+ }
32
+
33
+ }
34
+
35
+ // protected function _construct()
36
+ // {
37
+ // // Define module dependent translate
38
+ // $this->setUsedModuleName('Mage_Catalog');
39
+ // }
40
+
41
+ public function editAction()
42
+ {
43
+ if (!$this->_validateProducts()) {
44
+ return;
45
+ }
46
+
47
+ $this->loadLayout();
48
+ $this->_setActiveMenu('catalog/product');
49
+
50
+ $formBlock = $this->getLayout()->createBlock('mklauza_customproducturls/adminhtml_massactionform');
51
+
52
+ $this->_title('Custom Product Urls')->_addContent($formBlock);
53
+ $this->renderLayout();
54
+ }
55
+
56
+ /**
57
+ * Update product attributes
58
+ */
59
+ public function saveAction()
60
+ {
61
+ if (!$this->_validateProducts()) {
62
+ $this->_getSession()->addError($this->__('Validation failed.'));
63
+ return $this->_redirectReferer();
64
+ }
65
+
66
+ /* Collect Data */
67
+ $pattern = $this->getRequest()->getParam('pattern', '');
68
+ $urlKeyCreateRedirect = (int) $this->getRequest()->getParam('url_key_create_redirect');
69
+
70
+ try {
71
+ $storeId = $this->_getHelper()->getSelectedStoreId();
72
+
73
+ $attribute = Mage::getSingleton('eav/config')
74
+ ->getAttribute(Mage_Catalog_Model_Product::ENTITY, 'url_key');
75
+ if (!$attribute->getAttributeId()) {
76
+ throw new Exception($this->__('url_key attribute obj missing'));
77
+ }
78
+
79
+ Mage::getSingleton('mklauza_customproducturls/catalog_resource_product_action')
80
+ ->updateUrlKeyAttributes(
81
+ $this->_getHelper()->getProductIds(),
82
+ $pattern,
83
+ $urlKeyCreateRedirect,
84
+ $storeId
85
+ );
86
+ $process = Mage::getModel('index/indexer')->getProcessByCode('catalog_url');
87
+ $process->reindexAll();
88
+
89
+ $this->_getSession()->addSuccess(
90
+ $this->__('Total of %d record(s) were updated', count($this->_getHelper()->getProductIds()))
91
+ );
92
+ }
93
+ catch (Mage_Core_Exception $e) {
94
+ $this->_getSession()->addError($e->getMessage());
95
+ }
96
+ catch (Exception $e) {
97
+ $this->_getSession()->addException($e, $this->__('An error occurred while updating the product(s) attributes.'));
98
+ }
99
+
100
+ $this->_redirect('*/catalog_product/', array('store'=>$this->_getHelper()->getSelectedStoreId()));
101
+ // $this->loadLayout();
102
+ // $this->_setActiveMenu('catalog/product');
103
+ //
104
+ // $this->getLayout();
105
+ // $this->_title('Custom Product Urls - after save!');
106
+ // $this->renderLayout();
107
+ }
108
+
109
+ /**
110
+ * Validate selection of products for massupdate
111
+ *
112
+ * @return boolean
113
+ */
114
+ protected function _validateProducts()
115
+ {
116
+ $error = false;
117
+ $productIds = $this->_getHelper()->getProductIds();
118
+
119
+ if (!is_array($productIds)) {
120
+ $error = $this->__('Please select products for attributes update');
121
+ } else if (!Mage::getModel('catalog/product')->isProductsHasSku($productIds)) {
122
+ $error = $this->__('Some of the processed products have no SKU value defined. Please fill it prior to performing operations on these products.');
123
+ }
124
+
125
+ if ($error) {
126
+ $this->_getSession()->addError($error);
127
+ $this->_redirect('*/catalog_product/', array('_current'=>true));
128
+ }
129
+
130
+ return !$error;
131
+ }
132
+
133
+ /**
134
+ * Rertive data manipulation helper
135
+ *
136
+ * @return Mage_Adminhtml_Helper_Catalog_Product_Edit_Action_Attribute
137
+ */
138
+ protected function _getHelper()
139
+ {
140
+ return Mage::helper('adminhtml/catalog_product_edit_action_attribute');
141
+ }
142
+
143
+ protected function _isAllowed()
144
+ {
145
+ return Mage::getSingleton('admin/session')->isAllowed('catalog/update_attributes');
146
+ }
147
+
148
+ /**
149
+ * Attributes validation action
150
+ *
151
+ */
152
+ public function validateAction()
153
+ {
154
+ $response = new Varien_Object();
155
+ $response->setError(false);
156
+ $attributesData = $this->getRequest()->getParam('attributes', array());
157
+ $data = new Varien_Object();
158
+
159
+ try {
160
+ if ($attributesData) {
161
+ $dateFormat = Mage::app()->getLocale()->getDateFormat(Mage_Core_Model_Locale::FORMAT_TYPE_SHORT);
162
+ $storeId = $this->_getHelper()->getSelectedStoreId();
163
+
164
+ foreach ($attributesData as $attributeCode => $value) {
165
+ $attribute = Mage::getSingleton('eav/config')
166
+ ->getAttribute('catalog_product', $attributeCode);
167
+ if (!$attribute->getAttributeId()) {
168
+ unset($attributesData[$attributeCode]);
169
+ continue;
170
+ }
171
+ $data->setData($attributeCode, $value);
172
+ $attribute->getBackend()->validate($data);
173
+ }
174
+ }
175
+ } catch (Mage_Eav_Model_Entity_Attribute_Exception $e) {
176
+ $response->setError(true);
177
+ $response->setAttribute($e->getAttributeCode());
178
+ $response->setMessage($e->getMessage());
179
+ } catch (Mage_Core_Exception $e) {
180
+ $response->setError(true);
181
+ $response->setMessage($e->getMessage());
182
+ } catch (Exception $e) {
183
+ $this->_getSession()->addException($e, $this->__('An error occurred while updating the product(s) attributes.'));
184
+ $this->_initLayoutMessages('adminhtml/session');
185
+ $response->setError(true);
186
+ $response->setMessage($this->getLayout()->getMessagesBlock()->getGroupedHtml());
187
+ }
188
+
189
+ $this->getResponse()->setBody($response->toJson());
190
+ }
191
+
192
+ /* ---------------------------------------------------------------------------- */
193
+
194
+ public function clearRedirectsAction() {
195
+ // Mage::getModel('catalog/url')->refreshProductRewrites(0);
196
+ $write = Mage::getSingleton('core/resource')->getConnection('core_write');
197
+ try {
198
+ $write->beginTransaction();
199
+ $table = Mage::getSingleton('core/resource')->getTableName('core/url_rewrite');
200
+ $write->query('DELETE FROM ' . $table . ' WHERE options IS NOT NULL AND is_system = 0');
201
+ $write->commit();
202
+ $this->_getSession()->addSuccess($this->__('Successfully ...'));
203
+ } catch(Exception $e) {
204
+ $write->rollback();
205
+ $this->_getSession()->addException($e, $this->__('An error occurred while clearing url redirects.<br/>' . $e->getMessage()));
206
+ }
207
+
208
+ $this->_redirectReferer();
209
+ }
210
+
211
+ }
app/code/community/Mklauza/CustomProductUrls/controllers/Adminhtml/ProductUrlsController.php ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Marcin Klauza - Magento developer
4
+ * http://www.marcinklauza.com
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Open Software License (OSL 3.0)
9
+ * that is bundled with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://opensource.org/licenses/osl-3.0.php
12
+ * If you did not receive a copy of the license and are unable to
13
+ * obtain it through the world-wide-web, please send an email
14
+ * to marcinklauza@gmail.com so we can send you a copy immediately.
15
+ *
16
+ * @category Mklauza
17
+ * @package Mklauza_CustomProductUrls
18
+ * @author Marcin Klauza <marcinklauza@gmail.com>
19
+ * @copyright Copyright (c) 2015 (Marcin Klauza)
20
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
21
+ */
22
+
23
+ class Mklauza_CustomProductUrls_Adminhtml_ProductUrlsController extends Mage_Adminhtml_Controller_Action {
24
+
25
+ public function exampleAction() {
26
+ $pattern = $this->getRequest()->getParam('pattern');
27
+ $data['exampleUrl'] = Mage::helper('mklauza_customproducturls')->getRandomExample($pattern);
28
+ $data['isSuccess'] = true;
29
+ $this->getResponse()->setHeader('Content-type','application/json',true);
30
+ $this->getResponse()->setBody(json_encode($data));
31
+ }
32
+ // public function indexAction() {
33
+ // $this->loadLayout();
34
+ // $this->_setActiveMenu('system/mklauza_customproducturls');
35
+ // $this->_title('Custom Product Urls')->_addContent($this->getLayout()->createBlock('mklauza_customproducturls/adminhtml_settingsform'));
36
+ // $this->renderLayout();
37
+ // }
38
+ //
39
+ // public function saveAction() {
40
+ // try {
41
+ // $enabled = $this->getRequest()->getParam('is_active');
42
+ // Mage::getSingleton('core/config')->saveConfig('mklauza_customproducturls/general/is_active', $enabled, 'default', '0');
43
+ //
44
+ // $pattern = $this->getRequest()->getParam('pattern');
45
+ // Mage::getSingleton('core/config')->saveConfig('mklauza_customproducturls/general/pattern', $pattern, 'default', '');
46
+ //
47
+ // $applyToNew = $this->getRequest()->getParam('apply_to_new');
48
+ // Mage::getSingleton('core/config')->saveConfig('mklauza_customproducturls/general/apply_to_new', $applyToNew, 'default', '0');
49
+ //
50
+ // $this->_getSession()->addSuccess($this->__('Successfully saved.'));
51
+ // } catch (Exception $e) {
52
+ // $this->_getSession()->addError($e->getMessage());
53
+ // }
54
+ // $this->_redirect('*/*/index');
55
+ // }
56
+
57
+ }
app/code/community/Mklauza/CustomProductUrls/etc/adminhtml.xml ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <acl>
4
+ <resources>
5
+ <admin>
6
+ <children>
7
+ <system>
8
+ <children>
9
+ <config>
10
+ <children>
11
+ <mklauza_customproducturls translate="title" module="mklauza_customproducturls">
12
+ <title>Custom Product Urls</title>
13
+ <sort_order>130</sort_order>
14
+ </mklauza_customproducturls>
15
+ </children>
16
+ </config>
17
+ </children>
18
+ </system>
19
+ <system>
20
+ <children>
21
+ <mklauza_customproducturls translate="title" module="mklauza_customproducturls">
22
+ <title>Custom Product Urls</title>
23
+ <sort_order>200</sort_order>
24
+ </mklauza_customproducturls>
25
+ </children>
26
+ </system>
27
+ </children>
28
+ </admin>
29
+ </resources>
30
+ </acl>
31
+ <!-- <menu>
32
+ <system>
33
+ <children>
34
+ <mklauza_customproducturls translate="title" module="mklauza_customproducturls">
35
+ <title>Custom Product Urls</title>
36
+ <sort_order>91</sort_order>
37
+ <action>adminhtml/productUrls/</action>
38
+ </mklauza_customproducturls>
39
+ </children>
40
+ </system>
41
+ </menu> -->
42
+ </config>
app/code/community/Mklauza/CustomProductUrls/etc/config.xml ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Mklauza_CustomProductUrls>
5
+ <version>0.0.1</version>
6
+ </Mklauza_CustomProductUrls>
7
+ </modules>
8
+ <global>
9
+ <blocks>
10
+ <mklauza_customproducturls>
11
+ <class>Mklauza_CustomProductUrls_Block</class>
12
+ </mklauza_customproducturls>
13
+ </blocks>
14
+ <helpers>
15
+ <mklauza_customproducturls>
16
+ <class>Mklauza_CustomProductUrls_Helper</class>
17
+ </mklauza_customproducturls>
18
+ </helpers>
19
+ <models>
20
+ <mklauza_customproducturls>
21
+ <class>Mklauza_CustomProductUrls_Model</class>
22
+ </mklauza_customproducturls>
23
+ <catalog>
24
+ <rewrite>
25
+ <product_url>Mklauza_CustomProductUrls_Model_Catalog_Product_Url</product_url>
26
+ <!-- Mage_Catalog_Model_Product_Attribute_Backend_Urlkey -->
27
+ <!--<product_attribute_backend_urlkey>Mklauza_CustomProductUrls_Model_Catalog_Resource_Product_Attribute_Backend_Urlkey</product_attribute_backend_urlkey>-->
28
+ </rewrite>
29
+ </catalog>
30
+ </models>
31
+ </global>
32
+ <adminhtml>
33
+
34
+ <events>
35
+ <adminhtml_block_html_before>
36
+ <observers>
37
+ <add_custom_urls_mass_action>
38
+ <type>singleton</type>
39
+ <class>mklauza_customproducturls/adminhtml_observer</class>
40
+ <method>addCustomUrlsMassAction</method>
41
+ </add_custom_urls_mass_action>
42
+ <add_clear_permanent_redirects_button>
43
+ <type>singleton</type>
44
+ <class>mklauza_customproducturls/adminhtml_observer</class>
45
+ <method>addClearPermanentRedirectsButton</method>
46
+ </add_clear_permanent_redirects_button>
47
+ </observers>
48
+ </adminhtml_block_html_before>
49
+ <catalog_product_save_after>
50
+ <observers>
51
+ <change_url>
52
+ <type>singleton</type>
53
+ <class>mklauza_customproducturls/adminhtml_observer</class>
54
+ <method>generateUrlKey</method>
55
+ </change_url>
56
+ </observers>
57
+ </catalog_product_save_after>
58
+ <catalog_product_prepare_save>
59
+ <observers>
60
+ <detect_url_change>
61
+ <type>singleton</type>
62
+ <class>mklauza_customproducturls/adminhtml_observer</class>
63
+ <method>checkUrl</method>
64
+ </detect_url_change>
65
+ </observers>
66
+ </catalog_product_prepare_save>
67
+ </events>
68
+
69
+ <translate>
70
+ <modules>
71
+ <Mklauza_CustomProductUrls>
72
+ <files>
73
+ <default>mklauza/Mklauza_CustomProductUrls.csv</default>
74
+ </files>
75
+ </Mklauza_CustomProductUrls>
76
+ </modules>
77
+ </translate>
78
+ <layout>
79
+ <updates>
80
+ <Mklauza_CustomProductUrls>
81
+ <file>mklauza/product_urls.xml</file>
82
+ </Mklauza_CustomProductUrls>
83
+ </updates>
84
+ </layout>
85
+ </adminhtml>
86
+ <admin>
87
+ <routers>
88
+ <adminhtml>
89
+ <args>
90
+ <modules>
91
+ <Mklauza_CustomProductUrls after="Mage_Adminhtml">Mklauza_CustomProductUrls_Adminhtml</Mklauza_CustomProductUrls>
92
+ <Mklauza_CustomProductUrls_Mass_Action after="Mage_Adminhtml">Mklauza_CustomProductUrls_Adminhtml_Catalog_Product_Action</Mklauza_CustomProductUrls_Mass_Action>
93
+ </modules>
94
+ </args>
95
+ </adminhtml>
96
+ </routers>
97
+ </admin>
98
+ </config>
app/code/community/Mklauza/CustomProductUrls/etc/system.xml ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <tabs>
4
+ <mklauza translate="label" module="mklauza_customproducturls">
5
+ <label>Marcin Klauza Extensions</label>
6
+ <sort_order>201</sort_order>
7
+ </mklauza>
8
+ </tabs>
9
+ <sections>
10
+ <mklauza_customproducturls translate="label" module="mklauza_customproducturls">
11
+ <label>Custom Product Urls</label>
12
+ <tab>mklauza</tab>
13
+ <sort_order>120</sort_order>
14
+ <show_in_default>1</show_in_default>
15
+ <show_in_website>1</show_in_website>
16
+ <show_in_store>1</show_in_store>
17
+ <groups>
18
+ <general translate="label" module="mklauza_customproducturls">
19
+ <label>General</label>
20
+ <sort_order>10</sort_order>
21
+ <show_in_default>1</show_in_default>
22
+ <show_in_website>1</show_in_website>
23
+ <show_in_store>1</show_in_store>
24
+ <fields>
25
+ <is_active translate="label" module="mklauza_customproducturls">
26
+ <label>Enable Module</label>
27
+ <frontend_type>select</frontend_type>
28
+ <source_model>adminhtml/system_config_source_enabledisable</source_model>
29
+ <sort_order>10</sort_order>
30
+ <show_in_default>1</show_in_default>
31
+ <show_in_website>1</show_in_website>
32
+ <show_in_store>1</show_in_store>
33
+ </is_active>
34
+ <apply_to_new translate="label" module="mklauza_customproducturls">
35
+ <label>Apply pattern if empty Url Key attribute</label>
36
+ <comment>Creates custom url once Url Key is left empty on product save</comment>
37
+ <frontend_type>select</frontend_type>
38
+ <source_model>adminhtml/system_config_source_yesno</source_model>
39
+ <sort_order>20</sort_order>
40
+ <show_in_default>1</show_in_default>
41
+ <show_in_website>1</show_in_website>
42
+ <show_in_store>1</show_in_store>
43
+ </apply_to_new>
44
+ <pattern>
45
+ <label>Pattern</label>
46
+ <frontend_type>text</frontend_type>
47
+ <frontend_model>mklauza_customproducturls/adminhtml_form_pattern</frontend_model>
48
+ <!--<source_model>mklauza/system_config_source_enabledisable</source_model>-->
49
+ <sort_order>30</sort_order>
50
+ <show_in_default>1</show_in_default>
51
+ <show_in_website>1</show_in_website>
52
+ <show_in_store>1</show_in_store>
53
+ </pattern>
54
+ </fields>
55
+ </general>
56
+ </groups>
57
+ </mklauza_customproducturls>
58
+ </sections>
59
+ </config>
app/design/adminhtml/default/default/layout/mklauza/product_urls.xml ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!--
3
+ /**
4
+ * Netzarbeiter
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Open Software License (OSL 3.0)
9
+ * that is bundled with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://opensource.org/licenses/osl-3.0.php
12
+ *
13
+ * DISCLAIMER
14
+ *
15
+ * Do not edit or add to this file if you wish to upgrade this Module to
16
+ * newer versions in the future.
17
+ *
18
+ * @category Netzarbeiter
19
+ * @package Netzarbeiter_GroupsCatalog2
20
+ * @copyright Copyright (c) 2014 Vinai Kopp http://netzarbeiter.com
21
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
22
+ */
23
+ -->
24
+ <layout>
25
+ <adminhtml_producturls_index>
26
+ <reference name="content">
27
+ <!-- mklauza_customproducturls/adminhtml_form -->
28
+ <!--<block type="mklauza_customproducturls/adminhtml_form" name="customproducturls.form" template="mklauza/customproducturls/system/settings.phtml"/>-->
29
+ </reference>
30
+ </adminhtml_producturls_index>
31
+ </layout>
app/design/adminhtml/default/default/template/mklauza/customproducturls/massaction.phtml ADDED
@@ -0,0 +1,363 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Marcin Klauza - Magento developer
4
+ * http://www.marcinklauza.com
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Open Software License (OSL 3.0)
9
+ * that is bundled with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://opensource.org/licenses/osl-3.0.php
12
+ * If you did not receive a copy of the license and are unable to
13
+ * obtain it through the world-wide-web, please send an email
14
+ * to marcinklauza@gmail.com so we can send you a copy immediately.
15
+ *
16
+ * @category Mklauza
17
+ * @package Mklauza_CustomProductUrls
18
+ * @author Marcin Klauza <marcinklauza@gmail.com>
19
+ * @copyright Copyright (c) 2015 (Marcin Klauza)
20
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
21
+ */
22
+ ?>
23
+ <!--<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.3/themes/smoothness/jquery-ui.css">-->
24
+ <script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
25
+ <script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.3/jquery-ui.min.js"></script>
26
+ <script>jQuery.noConflict();</script>
27
+ <style>
28
+ /*@import url(http://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,300italic,400italic,600italic);
29
+ @import url(http://fonts.googleapis.com/css?family=Ubuntu+Condensed);*/
30
+ * {
31
+ box-sizing: border-box;
32
+ }
33
+ .color {
34
+ color: #19bc9c !important;
35
+ }
36
+ html,
37
+ body {
38
+ width: 100%;
39
+ height: 100%;
40
+ margin: 0;
41
+ font-family: 'Ubuntu Condensed', sans-serif;
42
+ background-color: #dddddd;
43
+ }
44
+ h1 {
45
+ text-align: center;
46
+ margin-bottom: 32px;
47
+ }
48
+ div.container {
49
+ display: block;
50
+ width: 50%;
51
+ margin: 32px auto;
52
+ padding: 16px 32px;
53
+ background-color: #ffffff;
54
+ box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.1);
55
+ }
56
+ div.inputTags-list {
57
+ display: inline-block;
58
+ width: 100%;
59
+ padding: 6px;
60
+ margin: 0 0 20px 0;
61
+ border: 1px solid rgba(25, 188, 156, 0.35);
62
+ background-color: #f9f9f9;
63
+ box-shadow: 1px 2px 2px rgba(221, 221, 221, 0.2);
64
+ border-radius: 4px;
65
+ }
66
+ div.inputTags-list span.inputTags-item {
67
+ position: relative;
68
+ display: inline-block;
69
+ margin: 2px;
70
+ padding: 3px 22px 4px 8px;
71
+ border-radius: 3px;
72
+ background-color: #19bc9c;
73
+ text-align: center;
74
+ color: #ffffff;
75
+ opacity: 1;
76
+ white-space: nowrap;
77
+ }
78
+
79
+ div.inputTags-list.tag-cloud span.inputTags-item {
80
+ background-color: #ed6502;
81
+ }
82
+ div.inputTags-list span.inputTags-item.blocked {
83
+ background-color: #ed6502;
84
+ }
85
+
86
+ div.inputTags-list span.inputTags-item.is-edit {
87
+ display: none;
88
+ }
89
+ div.inputTags-list span.inputTags-item.is-hidden {
90
+ display: none !important;
91
+ }
92
+ div.inputTags-list span.inputTags-item.is-exists {
93
+ background-color: rgba(231, 76, 60, 0.7);
94
+ }
95
+ div.inputTags-list span.inputTags-item span.value {
96
+ cursor: default;
97
+ }
98
+ div.inputTags-list span.inputTags-item i {
99
+ position: absolute;
100
+ top: 50%;
101
+ right: 6px;
102
+ font-size: 20px;
103
+ cursor: pointer;
104
+ z-index: 10;
105
+ font-weight: 400;
106
+ transition: color 0.2s;
107
+ font-family: sans-serif;
108
+ transform: translateY(-50%);
109
+ }
110
+ div.inputTags-list span.inputTags-item i:hover {
111
+ color: #e74c3c;
112
+ }
113
+ div.inputTags-list input.inputTags-field {
114
+ border: none;
115
+ width: auto;
116
+ white-space: nowrap;
117
+ margin-left: 4px;
118
+ background-color: transparent;
119
+ }
120
+ div.inputTags-list input.inputTags-field:focus,
121
+ div.inputTags-list input.inputTags-field:active {
122
+ outline: none;
123
+ }
124
+ div.inputTags-list input.inputTags-field.is-edit {
125
+ margin: 0 2px;
126
+ padding: 4px 8px 3px 8px;
127
+ border: 1px dashed #c4c4c4;
128
+ border-radius: 4px;
129
+ }
130
+ div.inputTags-list ul.inputTags-autocomplete-list {
131
+ position: absolute;
132
+ max-height: 192px;
133
+ margin: 0;
134
+ padding: 0;
135
+ list-style-type: none;
136
+ background-color: #ffffff;
137
+ border: 1px solid #dddddd;
138
+ border-radius: 4px;
139
+ transform: scaleY(0);
140
+ transform-origin: 50% 0;
141
+ transition-duration: 0.2s;
142
+ overflow-y: auto;
143
+ z-index: 100;
144
+ opacity: 0;
145
+ }
146
+ div.inputTags-list ul.inputTags-autocomplete-list.is-active {
147
+ opacity: 1;
148
+ transform: scaleY(1);
149
+ }
150
+ div.inputTags-list ul.inputTags-autocomplete-list li {
151
+ height: 32px;
152
+ line-height: 32px;
153
+ padding: 0 16px;
154
+ transition-duration: 0.3s;
155
+ cursor: pointer;
156
+ border-bottom: 1px solid #dddddd;
157
+ transition-duration: 0.2s;
158
+ }
159
+ div.inputTags-list ul.inputTags-autocomplete-list li:last-child {
160
+ border: none;
161
+ }
162
+ div.inputTags-list ul.inputTags-autocomplete-list li:hover {
163
+ background-color: #19bc9c;
164
+ color: #ffffff;
165
+ }
166
+ div.inputTags-list ul.inputTags-autocomplete-list li.is-disabled {
167
+ cursor: default;
168
+ background-color: #f7f7f7;
169
+ color: initial;
170
+ }
171
+ p.inputTags-error {
172
+ position: relative;
173
+ margin: 0;
174
+ padding: 0.5em 1em;
175
+ color: #ffffff;
176
+ background-color: rgba(231, 76, 60, 0.7);
177
+ border-radius: 4px;
178
+ cursor: pointer;
179
+ }
180
+ p.inputTags-error:first-of-type {
181
+ margin-top: 8px;
182
+ }
183
+ p.inputTags-error:after {
184
+ position: absolute;
185
+ content: "\000D7";
186
+ top: 50%;
187
+ right: 0.5em;
188
+ transform: translateY(-50%);
189
+ font-size: 28px;
190
+ }
191
+ </style>
192
+
193
+ <script lang="Javascript">
194
+ (function($) {
195
+ $.fn.closestToOffset = function(offset) {
196
+ var el = null, elOffset, x = offset.left, y = offset.top, distance, dx, dy, minDistance;
197
+ this.each(function() {
198
+ elOffset = $(this).offset();
199
+
200
+ if (
201
+ (x >= elOffset.left) && (x <= elOffset.right) &&
202
+ (y >= elOffset.top) && (y <= elOffset.bottom)
203
+ ) {
204
+ el = $(this);
205
+ return false;
206
+ }
207
+
208
+ var offsets = [[elOffset.left, elOffset.top], [elOffset.right, elOffset.top], [elOffset.left, elOffset.bottom], [elOffset.right, elOffset.bottom]];
209
+ for (off in offsets) {
210
+ dx = offsets[off][0] - x;
211
+ dy = offsets[off][1] - y;
212
+ distance = Math.sqrt((dx*dx) + (dy*dy));
213
+ if (minDistance === undefined || distance < minDistance) {
214
+ minDistance = distance;
215
+ el = $(this);
216
+ }
217
+ }
218
+ });
219
+ return el;
220
+ }
221
+ })(jQuery);
222
+ </script>
223
+
224
+ <script lang="Javascript">
225
+
226
+ serializePattern = function() {
227
+ var patternParam = '';
228
+ jQuery('.js-pattern').children().each(function(){
229
+ if(jQuery(this).hasClass('inputTags-item')) {
230
+ patternParam += '{'+jQuery(this).data('value')+'}';
231
+ } else if(jQuery(this).hasClass('inputTags-field')) {
232
+ patternParam += jQuery(this).val();
233
+ }
234
+ });
235
+ return patternParam;
236
+ };
237
+
238
+ submitChanges = function(url) {
239
+ patternParam = serializePattern();
240
+ // console.log(encodeURIComponent(patternParam));
241
+ var saveRewrite = document.getElementById('url_key_create_redirect').checked == true ? 1 : 0;
242
+ location.href = url + '?pattern=' + encodeURIComponent(patternParam) + '&url_key_create_redirect=' + saveRewrite ;
243
+ };
244
+ </script>
245
+
246
+ <div class="js-tag-cloud inputTags-list">
247
+ <?php echo $this->getAttributesCloudHtml() ?>
248
+ </div>
249
+ <br/>
250
+ <div class="js-pattern inputTags-list">
251
+ <?php echo $this->getPatternHtml() ?>
252
+ </div>
253
+
254
+ <div>
255
+ <input id="url_key_create_redirect" name="url_key_create_redirect" <?php echo $this->getSaveRewritesHistory() ? 'checked' : '' ?> type="checkbox"> <!-- checked="checked" -->
256
+ <label for="url_key_create_redirect"><?php echo $this->__('Create Permanent Redirect for old URL') ?></label>
257
+ </div>
258
+ <br/>
259
+
260
+ <div>
261
+ <button onclick="return showExample()">Example</button>
262
+ <span id="js-example"></span>
263
+ </div>
264
+ <br/>
265
+ <button id="apply" onclick="submitChanges('<?php echo $this->getSubmitUrl() ?>')"><?php echo $this->__('Apply') ?></button>
266
+
267
+ <script lang="Javascript">
268
+
269
+ function showExample() {
270
+ var pattern = serializePattern();
271
+ jQuery.ajax({
272
+ method: 'get',
273
+ url: '<?php echo $this->getExampleUrl() ?>',
274
+ data: {
275
+ pattern: pattern
276
+ }
277
+ }).success(function(data){
278
+ if(typeof data !== 'undefined' && data.isSuccess) {
279
+ jQuery('#js-example').text(data.exampleUrl);
280
+ }
281
+ });
282
+ return false;
283
+ }
284
+
285
+ jQuery.fn.textWidth = function(){
286
+ var html_org = jQuery(this).val();
287
+ var html_calc = '<span id="temp-span">' + html_org + '</span>';
288
+ jQuery('body').append(html_calc);
289
+ var width = jQuery('span#temp-span').width();
290
+ jQuery('span#temp-span').remove();
291
+ return width + (jQuery(this).val().length)*1.33;
292
+ };
293
+
294
+ jQuery.fn.adjustSize = function() {
295
+ return jQuery(this).each(function(){
296
+ jQuery(this).css('width', jQuery(this).textWidth()+5 + 'px' );
297
+ });
298
+ };
299
+
300
+ jQuery.fn.validatePattern = function() {
301
+ jQuery(this).children().each(function(){
302
+ if(jQuery(this).hasClass('inputTags-field') && jQuery(this).next().hasClass('inputTags-field')) {
303
+ if( jQuery(this).next().val() !== '') {
304
+ jQuery(this).val( jQuery(this).val() + '-' + jQuery(this).next().val()).adjustSize();
305
+ }
306
+ jQuery(this).next().remove();
307
+ }
308
+ });
309
+ };
310
+
311
+ jQuery('body').on('keydown', '.inputTags-list input.inputTags-field', function(){
312
+ jQuery(this).adjustSize();
313
+ });
314
+ // $('body').on('blur', '.inputTags-list input.inputTags-field', function(){
315
+ // this.style.width = 10 + 'px';
316
+ // this.value = '';
317
+ // });
318
+
319
+ jQuery('.js-pattern').sortable({
320
+ connectWith: '.js-tag-cloud',
321
+ update: function(event, ui) {
322
+ jQuery(this).validatePattern();
323
+ }
324
+ });
325
+ jQuery('.js-tag-cloud').sortable({
326
+ connectWith: '.js-pattern'
327
+ });
328
+
329
+ jQuery('.js-pattern').click(function(e){
330
+ var clickedX = e.clientX;
331
+ var element = jQuery(this).children().closestToOffset({left: clickedX, top: e.clientY});
332
+
333
+ var elPositionX = element[0].offsetLeft;
334
+ if(clickedX < elPositionX) {
335
+ if(!jQuery(element).hasClass('inputTags-field') && !jQuery(element).prev().hasClass('inputTags-field')) {
336
+ jQuery('<input type=text value="" class="inputTags-field ui-sortable-handle"/>').insertBefore(element).adjustSize().focus();
337
+ } else {
338
+ if(jQuery(element).hasClass('inputTags-field')) {
339
+ jQuery(element).focus();
340
+ } else {
341
+ jQuery(element).prev().focus();
342
+ }
343
+ }
344
+ } else {
345
+ if(!jQuery(element).hasClass('inputTags-field') && !jQuery(element).next().hasClass('inputTags-field')) {
346
+ jQuery('<input type=text value="" class="inputTags-field ui-sortable-handle"/>').insertAfter(element).adjustSize().focus();
347
+ } else {
348
+ if(jQuery(element).hasClass('inputTags-field')) {
349
+ jQuery(element).focus();
350
+ } else {
351
+ jQuery(element).next().focus();
352
+ }
353
+ }
354
+
355
+ }
356
+ });
357
+ jQuery(document).ready(function(){
358
+ jQuery('.inputTags-field').adjustSize();
359
+ });
360
+ </script>
361
+
362
+
363
+
app/design/adminhtml/default/default/template/mklauza/customproducturls/system/settings.phtml ADDED
@@ -0,0 +1,356 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Marcin Klauza - Magento developer
4
+ * http://www.marcinklauza.com
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Open Software License (OSL 3.0)
9
+ * that is bundled with this package in the file LICENSE.txt.
10
+ * It is also available through the world-wide-web at this URL:
11
+ * http://opensource.org/licenses/osl-3.0.php
12
+ * If you did not receive a copy of the license and are unable to
13
+ * obtain it through the world-wide-web, please send an email
14
+ * to marcinklauza@gmail.com so we can send you a copy immediately.
15
+ *
16
+ * @category Mklauza
17
+ * @package Mklauza_CustomProductUrls
18
+ * @author Marcin Klauza <marcinklauza@gmail.com>
19
+ * @copyright Copyright (c) 2015 (Marcin Klauza)
20
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
21
+ */
22
+ ?>
23
+ <!--<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.3/themes/smoothness/jquery-ui.css">-->
24
+ <script src="//code.jquery.com/jquery-1.11.2.min.js"></script>
25
+ <script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.11.3/jquery-ui.min.js"></script>
26
+ <script>jQuery.noConflict();</script>
27
+ <style>
28
+ /*@import url(http://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,300italic,400italic,600italic);
29
+ @import url(http://fonts.googleapis.com/css?family=Ubuntu+Condensed);*/
30
+ * {
31
+ box-sizing: border-box;
32
+ }
33
+ .color {
34
+ color: #19bc9c !important;
35
+ }
36
+ html,
37
+ body {
38
+ width: 100%;
39
+ height: 100%;
40
+ margin: 0;
41
+ font-family: 'Ubuntu Condensed', sans-serif;
42
+ background-color: #dddddd;
43
+ }
44
+ h1 {
45
+ text-align: center;
46
+ margin-bottom: 32px;
47
+ }
48
+ div.container {
49
+ display: block;
50
+ width: 50%;
51
+ margin: 32px auto;
52
+ padding: 16px 32px;
53
+ background-color: #ffffff;
54
+ box-shadow: 2px 2px 8px rgba(0, 0, 0, 0.1);
55
+ }
56
+ div.inputTags-list {
57
+ display: inline-block;
58
+ width: 100%;
59
+ padding: 6px;
60
+ margin: 0 0 20px 0;
61
+ border: 1px solid rgba(25, 188, 156, 0.35);
62
+ background-color: #f9f9f9;
63
+ box-shadow: 1px 2px 2px rgba(221, 221, 221, 0.2);
64
+ border-radius: 4px;
65
+ }
66
+ div.inputTags-list span.inputTags-item {
67
+ position: relative;
68
+ display: inline-block;
69
+ margin: 2px;
70
+ padding: 3px 22px 4px 8px;
71
+ border-radius: 3px;
72
+ background-color: #19bc9c;
73
+ text-align: center;
74
+ color: #ffffff;
75
+ opacity: 1;
76
+ white-space: nowrap;
77
+ }
78
+
79
+ div.inputTags-list.tag-cloud span.inputTags-item {
80
+ background-color: #ed6502;
81
+ }
82
+ div.inputTags-list span.inputTags-item.blocked {
83
+ background-color: #ed6502;
84
+ }
85
+
86
+ div.inputTags-list span.inputTags-item.is-edit {
87
+ display: none;
88
+ }
89
+ div.inputTags-list span.inputTags-item.is-hidden {
90
+ display: none !important;
91
+ }
92
+ div.inputTags-list span.inputTags-item.is-exists {
93
+ background-color: rgba(231, 76, 60, 0.7);
94
+ }
95
+ div.inputTags-list span.inputTags-item span.value {
96
+ cursor: default;
97
+ }
98
+ div.inputTags-list span.inputTags-item i {
99
+ position: absolute;
100
+ top: 50%;
101
+ right: 6px;
102
+ font-size: 20px;
103
+ cursor: pointer;
104
+ z-index: 10;
105
+ font-weight: 400;
106
+ transition: color 0.2s;
107
+ font-family: sans-serif;
108
+ transform: translateY(-50%);
109
+ }
110
+ div.inputTags-list span.inputTags-item i:hover {
111
+ color: #e74c3c;
112
+ }
113
+ div.inputTags-list input.inputTags-field {
114
+ border: none;
115
+ width: auto;
116
+ white-space: nowrap;
117
+ margin-left: 4px;
118
+ background-color: transparent;
119
+ }
120
+ div.inputTags-list input.inputTags-field:focus,
121
+ div.inputTags-list input.inputTags-field:active {
122
+ outline: none;
123
+ }
124
+ div.inputTags-list input.inputTags-field.is-edit {
125
+ margin: 0 2px;
126
+ padding: 4px 8px 3px 8px;
127
+ border: 1px dashed #c4c4c4;
128
+ border-radius: 4px;
129
+ }
130
+ div.inputTags-list ul.inputTags-autocomplete-list {
131
+ position: absolute;
132
+ max-height: 192px;
133
+ margin: 0;
134
+ padding: 0;
135
+ list-style-type: none;
136
+ background-color: #ffffff;
137
+ border: 1px solid #dddddd;
138
+ border-radius: 4px;
139
+ transform: scaleY(0);
140
+ transform-origin: 50% 0;
141
+ transition-duration: 0.2s;
142
+ overflow-y: auto;
143
+ z-index: 100;
144
+ opacity: 0;
145
+ }
146
+ div.inputTags-list ul.inputTags-autocomplete-list.is-active {
147
+ opacity: 1;
148
+ transform: scaleY(1);
149
+ }
150
+ div.inputTags-list ul.inputTags-autocomplete-list li {
151
+ height: 32px;
152
+ line-height: 32px;
153
+ padding: 0 16px;
154
+ transition-duration: 0.3s;
155
+ cursor: pointer;
156
+ border-bottom: 1px solid #dddddd;
157
+ transition-duration: 0.2s;
158
+ }
159
+ div.inputTags-list ul.inputTags-autocomplete-list li:last-child {
160
+ border: none;
161
+ }
162
+ div.inputTags-list ul.inputTags-autocomplete-list li:hover {
163
+ background-color: #19bc9c;
164
+ color: #ffffff;
165
+ }
166
+ div.inputTags-list ul.inputTags-autocomplete-list li.is-disabled {
167
+ cursor: default;
168
+ background-color: #f7f7f7;
169
+ color: initial;
170
+ }
171
+ p.inputTags-error {
172
+ position: relative;
173
+ margin: 0;
174
+ padding: 0.5em 1em;
175
+ color: #ffffff;
176
+ background-color: rgba(231, 76, 60, 0.7);
177
+ border-radius: 4px;
178
+ cursor: pointer;
179
+ }
180
+ p.inputTags-error:first-of-type {
181
+ margin-top: 8px;
182
+ }
183
+ p.inputTags-error:after {
184
+ position: absolute;
185
+ content: "\000D7";
186
+ top: 50%;
187
+ right: 0.5em;
188
+ transform: translateY(-50%);
189
+ font-size: 28px;
190
+ }
191
+ </style>
192
+
193
+ <script lang="Javascript">
194
+ (function($) {
195
+ $.fn.closestToOffset = function(offset) {
196
+ var el = null, elOffset, x = offset.left, y = offset.top, distance, dx, dy, minDistance;
197
+ this.each(function() {
198
+ elOffset = $(this).offset();
199
+
200
+ if (
201
+ (x >= elOffset.left) && (x <= elOffset.right) &&
202
+ (y >= elOffset.top) && (y <= elOffset.bottom)
203
+ ) {
204
+ el = $(this);
205
+ return false;
206
+ }
207
+
208
+ var offsets = [[elOffset.left, elOffset.top], [elOffset.right, elOffset.top], [elOffset.left, elOffset.bottom], [elOffset.right, elOffset.bottom]];
209
+ for (off in offsets) {
210
+ dx = offsets[off][0] - x;
211
+ dy = offsets[off][1] - y;
212
+ distance = Math.sqrt((dx*dx) + (dy*dy));
213
+ if (minDistance === undefined || distance < minDistance) {
214
+ minDistance = distance;
215
+ el = $(this);
216
+ }
217
+ }
218
+ });
219
+ return el;
220
+ }
221
+ })(jQuery);
222
+ </script>
223
+
224
+ <script lang="Javascript">
225
+
226
+ serializePattern = function() {
227
+ var patternParam = '';
228
+ jQuery('.js-pattern').children().each(function(){
229
+ if(jQuery(this).hasClass('inputTags-item')) {
230
+ patternParam += '{'+jQuery(this).data('value')+'}';
231
+ } else if(jQuery(this).hasClass('inputTags-field')) {
232
+ patternParam += jQuery(this).val();
233
+ }
234
+ });
235
+ return patternParam;
236
+ };
237
+
238
+ submitChanges = function() {
239
+ jQuery('#<?php echo $this->getElement()->getHtmlId() ?>').val(serializePattern());
240
+ };
241
+
242
+ </script>
243
+
244
+ <div class="js-tag-cloud inputTags-list">
245
+ <?php echo $this->getAttributesCloudHtml() ?>
246
+ </div>
247
+ <br/>
248
+ <div class="js-pattern inputTags-list">
249
+ <?php echo $this->getPatternHtml() ?>
250
+ </div>
251
+
252
+ <?php echo $this->getElement()->getElementHtml() ?>
253
+
254
+ <button onclick="return showExample()">Example</button>
255
+ <span id="js-example"></span>
256
+
257
+ <script lang="Javascript">
258
+
259
+ function showExample() {
260
+ var pattern = serializePattern();
261
+ jQuery.ajax({
262
+ method: 'get',
263
+ url: '<?php echo $this->getExampleUrl() ?>',
264
+ data: {
265
+ pattern: pattern
266
+ }
267
+ }).success(function(data){
268
+ if(typeof data !== 'undefined' && data.isSuccess) {
269
+ jQuery('#js-example').text(data.exampleUrl);
270
+ }
271
+ });
272
+ return false;
273
+ }
274
+
275
+ jQuery.fn.textWidth = function(){
276
+ var html_org = jQuery(this).val();
277
+ var html_calc = '<span id="temp-span">' + html_org + '</span>';
278
+ jQuery('body').append(html_calc);
279
+ var width = jQuery('span#temp-span').width();
280
+ jQuery('span#temp-span').remove();
281
+ return width + (jQuery(this).val().length)*1.33;
282
+ };
283
+
284
+ jQuery.fn.adjustSize = function() {
285
+ return jQuery(this).each(function(){
286
+ jQuery(this).css('width', jQuery(this).textWidth()+5 + 'px' );
287
+ });
288
+ };
289
+
290
+ jQuery.fn.validatePattern = function() {
291
+ jQuery(this).children().each(function(){
292
+ if(jQuery(this).hasClass('inputTags-field') && jQuery(this).next().hasClass('inputTags-field')) {
293
+ if( jQuery(this).next().val() !== '') {
294
+ jQuery(this).val( jQuery(this).val() + '-' + jQuery(this).next().val()).adjustSize();
295
+ }
296
+ jQuery(this).next().remove();
297
+ }
298
+ });
299
+ };
300
+
301
+ jQuery('body').on('keydown', '.inputTags-list input.inputTags-field', function(){
302
+ jQuery(this).adjustSize();
303
+ });
304
+
305
+ jQuery('.js-pattern').sortable({
306
+ connectWith: '.js-tag-cloud',
307
+ update: function(event, ui) {
308
+ jQuery(this).validatePattern();
309
+ submitChanges();
310
+ }
311
+ });
312
+ jQuery('body').on('change', '.js-pattern', function(){
313
+ submitChanges();
314
+ });
315
+
316
+ jQuery('.js-tag-cloud').sortable({
317
+ connectWith: '.js-pattern'
318
+ });
319
+
320
+ jQuery('.js-pattern').click(function(e){
321
+ var clickedX = e.clientX;
322
+ var element = jQuery(this).children().closestToOffset({left: clickedX, top: e.clientY});
323
+
324
+ var elPositionX = element[0].offsetLeft;
325
+ if(clickedX < elPositionX) {
326
+ if(!jQuery(element).hasClass('inputTags-field') && !jQuery(element).prev().hasClass('inputTags-field')) {
327
+ jQuery('<input type=text value="" class="inputTags-field ui-sortable-handle"/>').insertBefore(element).adjustSize().focus();
328
+ } else {
329
+ if(jQuery(element).hasClass('inputTags-field')) {
330
+ jQuery(element).focus();
331
+ } else {
332
+ jQuery(element).prev().focus();
333
+ }
334
+ }
335
+ } else {
336
+ if(!jQuery(element).hasClass('inputTags-field') && !jQuery(element).next().hasClass('inputTags-field')) {
337
+ jQuery('<input type=text value="" class="inputTags-field ui-sortable-handle"/>').insertAfter(element).adjustSize().focus();
338
+ } else {
339
+ if(jQuery(element).hasClass('inputTags-field')) {
340
+ jQuery(element).focus();
341
+ } else {
342
+ jQuery(element).next().focus();
343
+ }
344
+ }
345
+
346
+ }
347
+ });
348
+
349
+ jQuery(document).ready(function(){
350
+ jQuery('.inputTags-field').adjustSize();
351
+ });
352
+
353
+ </script>
354
+
355
+
356
+
app/etc/modules/Mklauza_CustomProductUrls.xml ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Mklauza_CustomProductUrls>
5
+ <active>true</active>
6
+ <codePool>community</codePool>
7
+ <depends>
8
+ <Mage_Core />
9
+ <Mage_Catalog />
10
+ </depends>
11
+ </Mklauza_CustomProductUrls>
12
+ </modules>
13
+ </config>
14
+
15
+
package.xml ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>2f0ed0fddbc299a929e59604a51b5159</name>
4
+ <version>1.0.0</version>
5
+ <stability>devel</stability>
6
+ <license>OSL</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>Create mass custom product urls.</summary>
10
+ <description>Extension allowing to mass change product url key according to template consisting of product attributes.</description>
11
+ <notes>notes</notes>
12
+ <authors><author><name>Marcin Klauza</name><user>marcin</user><email>marcinklauza@gmail.com</email></author></authors>
13
+ <date>2015-11-29</date>
14
+ <time>15:23:22</time>
15
+ <contents><target name="magecommunity"><dir><dir name="Mklauza"><dir name="CustomProductUrls"><dir name="Block"><dir name="Adminhtml"><dir name="Form"><file name="Abstract.php" hash="afca4db57042355a089f0ec809135c2b"/><file name="Pattern.php" hash="6497c9271c7418fea95f457a8dff8741"/></dir><file name="MassActionForm.php" hash="6b67e72a96d2548be84a51bc9241d4e6"/><file name="SettingsForm.php" hash="a07564eb01840511b6e2b24149f0dd6a"/><dir name="Urlrewrite"><file name="Grid.php" hash="48789c8053977b71111b600fcac592c6"/></dir></dir></dir><dir name="Helper"><file name="Data.php" hash="68f7d60c4916a57ab15b765a06957af4"/></dir><dir name="Model"><dir name="Adminhtml"><file name="Observer.php" hash="bc11ab14c66255cda7f6ae09934488a5"/></dir><dir name="Catalog"><dir name="Product"><file name="Url.php" hash="c14f7d9a39775c1e636286c9f7820cc2"/></dir><dir name="Resource"><dir name="Product"><file name="Action.php" hash="1dc3bb8d629f799812e1a0f72ab43902"/><dir name="Attribute"><dir name="Backend"><file name="_Urlkey.php" hash="7d8ca0fe2c768d2b89daa2d5b567b474"/></dir></dir></dir></dir></dir></dir><dir name="controllers"><dir name="Adminhtml"><dir name="Catalog"><dir name="Product"><dir name="Action"><file name="ProductUrlsMassActionController.php" hash="25744bc799faf9871f16067762834191"/></dir></dir></dir><file name="ProductUrlsController.php" hash="c11f3161ab717132e4db2e9931d5d422"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="54ab0a5774d316a80e05ebbd908ead77"/><file name="config.xml" hash="a80f832c6649cbccd77f46d490a44d39"/><file name="system.xml" hash="62c471970b154f3f19ac6ebb82e9cd0c"/></dir></dir></dir></dir></target><target name="magedesign"><dir><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><dir name="mklauza"><file name="product_urls.xml" hash="ad42e99261645c3993390b60d5bc7a66"/></dir></dir><dir name="template"><dir name="mklauza"><dir name="customproducturls"><file name="massaction.phtml" hash="fe77f7260f20c727447131ae3b6942f2"/><dir name="system"><file name="settings.phtml" hash="989bab675608982ea10b552a740dd5a6"/></dir></dir></dir></dir></dir></dir></dir></dir></target><target name="mageetc"><dir><dir name="modules"><file name="Mklauza_CustomProductUrls.xml" hash="0f6d8d6a5dd2261fed9f49e853f68adf"/></dir></dir></target></contents>
16
+ <compatible/>
17
+ <dependencies><required><php><min>5.1.0</min><max>6.0.0</max></php></required></dependencies>
18
+ </package>