Вывод всех опций minishop2 и автоматическое их добавление в словарь одной кнопкой.
Всем привет, как всегда возникла задача максимально упростить и автоматизировать рутинные процессы в MODX. Будем делать автоматическое добавление опций в словарь и автоматически подтягивать список опций, куда вам угодно будет.Если у вас есть советы как улучшить мой вариант или указать на ошибки — буду только рад. Честно признаюсь, что не искал похожие варианты, так что если повторю чей-то функционал — извиняйте :)
Тут все очень просто, создаем сниппет getAllOptions и вставляем в него этот код:
Далее просто вызываем этот сниппет в нужном месте, в моем случае это сниппет msOptionsPrice.option
В итоге все опции которые будут добавляться, будут приходить в этот сниппет самостоятельно. Точно таким же способом можно подтягивать опции и в mFilter2.
Я думаю многие сталкивались с тем, что вместо названия опции или фильтра выводилось, что-то типа ms2_product_bar_length. Это не проблема, можно просто добавить ее в словарь, но мы же все ленивые, особенно когда нужно добавить больше чем одну опцию. Лично мой заказчик даже не знает, что такое словарь и даже разбираться не хочет, поэтому постараемся сделать это максимально комфортно для нас.
Создаем файл addOptionsToLexicon.php (да, мне так удобно называть), и помещаем его в директорию assets, в моем случае это assets/components/msCustomField/ и вставляем в него код:
Теперь нам нужно его как-то запускать, по ссылке запускать не комильфо, поэтому сделаем кнопку.
1. Создаем плагин на событие msOnManagerCustomCssJs и вставляем в него код:
2. Внутри assets/components/msCustomSettings/ создаем файл default.js, открываем его и вставляем этот код:
И в итоге мы получаем вот такую кнопку на странице опций, в настройках минишопа.
При клике на которую запускается скрипт, который добавляет все новый опции в словарь или же обновляет существующие.
Такой вариант защищает глупеньких заказчиков от страшных слов и дает им возможность самостоятельно работать с опциями и связанными с ними компонентами, такими как msOptionsPrice2 или mSearch2(mFilter2).
И больше не нужно добавлять опцию и бежать в словарь, достаточно просто нажать кнопочку :)
Я очень надеюсь, что это будет кому-то полезно, лично я постоянно сталкиваюсь с этим.
Если у вас есть предложения как улучшить код, дополнить его еще какими-то фишками, буду рад почитать.
Написание подобных, простых мануалов помогает мне улучшать свой скил программирования и нести хоть какую-то пользу людям. Так что строго не судите :)
Получаем список всех опций minishop2
Тут все очень просто, создаем сниппет getAllOptions и вставляем в него этот код:
$optCollection = $modx->getCollection('msOption');
$options = '';
foreach ($optCollection as $item) {
$options .= $item->get('key').',';
}
return $options;
Далее просто вызываем этот сниппет в нужном месте, в моем случае это сниппет msOptionsPrice.option
{set $options = '!getAllOptions'|snippet}
{'!msOptionsPrice.option'|snippet:[
'options' => $options,
'tpl' => '@FILE chunk/product.options.tpl'
]}
В итоге все опции которые будут добавляться, будут приходить в этот сниппет самостоятельно. Точно таким же способом можно подтягивать опции и в mFilter2.
Автоматическое добавление опций в словарь
Я думаю многие сталкивались с тем, что вместо названия опции или фильтра выводилось, что-то типа ms2_product_bar_length. Это не проблема, можно просто добавить ее в словарь, но мы же все ленивые, особенно когда нужно добавить больше чем одну опцию. Лично мой заказчик даже не знает, что такое словарь и даже разбираться не хочет, поэтому постараемся сделать это максимально комфортно для нас.
Создаем файл addOptionsToLexicon.php (да, мне так удобно называть), и помещаем его в директорию assets, в моем случае это assets/components/msCustomField/ и вставляем в него код:
<?php
define('MODX_API_MODE', true);
require_once dirname(dirname(dirname(dirname(__FILE__)))).'/index.php';
// Подключаем MODX API
if (!$modx->user->isAuthenticated('mgr')) {
return false;
}
$modx->getService('error','error.modError');
$modx->setLogLevel(modX::LOG_LEVEL_INFO);
$modx->setLogTarget(XPDO_CLI_MODE ? 'ECHO' : 'HTML');
if (!$modx->getService('minishop2')) {
return false;
}
//Проверяем авторизирован ли пользователь
$optCollection = $modx->getCollection('msOption');
// Получаем все опции минишопа
if (!$optCollection){
return false;
}
foreach ($optCollection as $opt) {
$key = 'ms2_product_'.$opt->get('key'); // Добавляем к каждой опции префикс
$q = $modx->newQuery('modLexiconEntry');
$q->where(array(
'namespace' => 'minishop2',
'topic' => 'default',
'name' => $key
));
$lexicon = $modx->getObject('modLexiconEntry', $q);
// Пытаемся получить запись из словаря для этой опции
if (!$lexicon){
// Если записи нет - добавляем опцию в словарь
$newLexicon = $modx->newObject('modLexiconEntry', array(
'name' => $key,
'value' => $opt->get('caption'),
'namespace' => 'minishop2',
'topic' => 'default',
'language' => 'ru',
'createdon' => time()
));
$newLexicon->save();
}else{
// Иначе просто обновляем у нее значение, на случай, если отредактируют название опции
$lexicon->set('value', $opt->caption);
$lexicon->save();
}
}
Теперь нам нужно его как-то запускать, по ссылке запускать не комильфо, поэтому сделаем кнопку.
Добавляем свою кнопку на страницу опций minishop2
1. Создаем плагин на событие msOnManagerCustomCssJs и вставляем в него код:
<?php
switch ($modx->event->name) {
case 'msOnManagerCustomCssJs':
if ($page === 'settings'){
$modx->controller->addLastJavascript(MODX_ASSETS_URL.'components/msCustomSettings/default.js');
}
return;
break;
}
2. Внутри assets/components/msCustomSettings/ создаем файл default.js, открываем его и вставляем этот код:
Ext.override(miniShop2.grid.Option, {
// Переписываем метод getTopBar из класса miniShop2.grid.Option
getTopBar: function (config) {
return [{
text: '<i class="icon icon-plus"></i> ' + _('ms2_btn_create'),
handler: this.createOption,
scope: this
}, {
text: '<i class="icon icon-check"></i> ' + _('ms2_btn_assign'),
id: config.id + '-btn-assign',
handler: this.assignOption,
scope: this,
disabled: true,
}, {
// Добавляем нашу кнопку
text: '<i class="icon icon-plus"></i> ' + 'Записать в словарь',
handler: function () {
// Вызываем при клике Ajax запрос на наш файл с логикой
Ext.Ajax.request({
url: '../assets/components/msCustomField/addOptionsToLexicon.php',
success: function(response, opts) {
Ext.MessageBox.alert('Успешно','Опции успешно добавлены в словарь');
},
failure: function(response, opts) {
Ext.MessageBox.alert('Ошибка');
}
});
},
scope: this
}, '->', this.getSearchField()];
},
});
И в итоге мы получаем вот такую кнопку на странице опций, в настройках минишопа.
При клике на которую запускается скрипт, который добавляет все новый опции в словарь или же обновляет существующие.
Такой вариант защищает глупеньких заказчиков от страшных слов и дает им возможность самостоятельно работать с опциями и связанными с ними компонентами, такими как msOptionsPrice2 или mSearch2(mFilter2).
И больше не нужно добавлять опцию и бежать в словарь, достаточно просто нажать кнопочку :)
Я очень надеюсь, что это будет кому-то полезно, лично я постоянно сталкиваюсь с этим.
Если у вас есть предложения как улучшить код, дополнить его еще какими-то фишками, буду рад почитать.
Написание подобных, простых мануалов помогает мне улучшать свой скил программирования и нести хоть какую-то пользу людям. Так что строго не судите :)
Поблагодарить автора
Отправить деньги
Комментарии: 21
Не понятно для чего была необходимость использовать сырые запросы sql? Особенно вот это нравится, фильтрация данных? Зачем? И так сойдет!
Очень грустно что статья висит уже день а об этом только я говорю, еще полтора года назад автора закидали бы ссаными тряпками за такой код и дыру в безопасности
$sql = "INSERT INTO modx_lexicon_entries (name, value, topic, namespace, language, createdon) VALUES ('$key', '$opt->caption', 'default', 'minishop2', 'ru', CURRENT_TIMESTAMP)";
Ок, предположим что у нас доступ в админку есть только у админов, но файл то находится в assets, его может запустить кто угодно, проверять права? Зачем! Использовать процессоры где проверка прав уже предусмотрена? В жопу!Очень грустно что статья висит уже день а об этом только я говорю, еще полтора года назад автора закидали бы ссаными тряпками за такой код и дыру в безопасности
Спасибо за комментарий, исправлю.
Исправил дыры в безопасности, убрал сырые запросы и поставил проверку пользователя, теперь все по человечески. Прошу прощения за говнокод.
if (!$modx->user->isAuthenticated('web')) {
return false;
}
это авторизация в контексте web, а надо в mgr Можно еще так проверять (нашёл тут недалеко)
if ( !$modx->user->hasSessionContext('mgr') || !$modx->user->isMember('Administrator' )) {
return false;
}
Спасибо за подсказку, похоже у меня дефицит внимания разыгрался.
Я то хотел проверить контекст web, и не заметил что поставил восклицательный знак вначале, сейчас исправлю :)
Я то хотел проверить контекст web, и не заметил что поставил восклицательный знак вначале, сейчас исправлю :)
Исправил, еще раз спасибо, что заметили
С js тоже не всё так хорошо, дело в том, что ты именно перезаписываешь метод getTopBar а не расширяешь, т.е. в теории если выйдет обновление miniShop2 и в нём этот метод изменится, то люди которые используют предложенное тобой решение не увидят каких-то изменений.
Решение: Получить сначала результат оригинального метода (массив) и добавить в него уже свою кнопку.
Решение: Получить сначала результат оригинального метода (массив) и добавить в него уже свою кнопку.
через onAvailable?
Нет, через прототип
хорошо, спасибо
Что-то типа такого
Ext.override(miniShop2.grid.Option, {
originalFields: miniShop2.grid.Option.prototype.getTopBar
,getTopBar: function (config) {
var fields = this.originalFields.call(this, config);
fields.push({
// Твоя кнопка
})
return fields;
}
Понял, сейчас попробую, благодарю :)
Ну и чтобы всё по фэншую было, то по мне лучше использовать MODx.msg.alert вместо Ext.MessageBox.alert
Я не силен в extJs, много чего не знаю, но за советы, спасибо, я то хочу сделать максимально правильно.
Добрый день. У меня почему-то пишет опции только в лексиконы minishop2? а можно их записывать еще и в msearch2, а то в фильтре выводятся названия системные.
Не пробовал, но думаю можно. Сейчас там неймспейс минишопа, попробуйте адаптировать для mSearch2, думаю проблем не составит :)
попробовал, получилось,
А в словать добавляется mse2_filter_msoption_Height
т.к. в опциях используются большие и маленькие буквы, а на стр идут только маленькие.
Как быть?
foreach ($optCollection as $opt) {
$key = 'mse2_filter_msoption_'.$opt->get('key'); // Добавляем к каждой опции префикс
$q = $modx->newQuery('modLexiconEntry');
$q->where(array(
'namespace' => 'msearch2',
'topic' => 'default',
'name' => $key
));
$lexicon = $modx->getObject('modLexiconEntry', $q);
// Пытаемся получить запись из словаря для этой опции
if (!$lexicon){
// Если записи нет - добавляем опцию в словарь
$newLexicon = $modx->newObject('modLexiconEntry', array(
'name' => $key,
'value' => $opt->get('caption'),
'namespace' => 'msearch2',
'topic' => 'default',
'language' => 'ru',
'createdon' => time()
));
но проблема в том, что на стр. — mse2_filter_msoption_heightА в словать добавляется mse2_filter_msoption_Height
т.к. в опциях используются большие и маленькие буквы, а на стр идут только маленькие.
Как быть?
использовать в названии опций только маленькие буквы))
использовать mb_strtolower к значению
Подскажите пожалуйста как интегрировать правильно в mFilter2, буду признателен за готовый пример. В целом с записыванием в словарь все получилось, но не хватает опыта внедрить в mFilter2. Фактически надо как-то добавить в &filters
foreach ($optCollection as $opt) {
$key = 'mse2_filter_msoption_'.$opt->get('key'); // Добавляем к каждой опции префикс
$q = $modx->newQuery('modLexiconEntry');
$q->where(array(
'namespace' => 'msearch2',
'topic' => 'default',
'name' => $key
));
$lexicon = $modx->getObject('modLexiconEntry', $q);
// Пытаемся получить запись из словаря для этой опции
if (!$lexicon){
// Если записи нет — добавляем опцию в словарь
$newLexicon = $modx->newObject('modLexiconEntry', array(
'name' => $key,
'value' => $opt->get('caption'),
'namespace' => 'msearch2',
'topic' => 'default',
'language' => 'ru',
'createdon' => time()
));
$key = 'mse2_filter_msoption_'.$opt->get('key'); // Добавляем к каждой опции префикс
$q = $modx->newQuery('modLexiconEntry');
$q->where(array(
'namespace' => 'msearch2',
'topic' => 'default',
'name' => $key
));
$lexicon = $modx->getObject('modLexiconEntry', $q);
// Пытаемся получить запись из словаря для этой опции
if (!$lexicon){
// Если записи нет — добавляем опцию в словарь
$newLexicon = $modx->newObject('modLexiconEntry', array(
'name' => $key,
'value' => $opt->get('caption'),
'namespace' => 'msearch2',
'topic' => 'default',
'language' => 'ru',
'createdon' => time()
));
Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.