Ранее в этом блоге была создана аналогичная тема, в которой описываются небольшие доработки, призванные улучшить эргономику интерфейса и функциональную логику ПО OpenCart 1.5+. Дабы не перегружать исходную тему, решено было поделить её на части. Здесь будет публиковаться вторая часть. Описанные ниже доработки могут быть выполнены самостоятельно или заказаны у автора.
15. Прямые ссылки на вкладки редактируемых товаров с запоминанием последних.
Итак, суть задачи в том, чтобы дать возможность разным пользователям административной панели OpenCart оперативно вносить изменения в карточки товаров по прямым ссылкам. Это могут быть ссылки как от коллег, так и от руководителей. Также необходимо запоминание последней закладки при редактировании одних и тех же полей для нескольких и более товаров. Целью доработки является снижение временных затрат при работе с интерфейсом.
В скрипте ./admin/view/javascript/jquery/tabs.js после $(obj).click(function() { добавить следующие строки:
if ($(this).parent().attr('id') == 'tabs') {
location.hash = $(this).attr('href');
$.cookie('selected_tab', location.hash);
}
В этом же файле строку $(this).first().click(); заменить на следующий блок кода:
var is_tabs = $(this).parent().attr('id') == 'tabs';
var hash = location.hash;
if (is_tabs && hash) {
$('[href=' + hash + ']', '#tabs').click();
} else if (is_tabs && getURLVar('route').indexOf('/update') > 0 && $.cookie('selected_tab')) {
$('[href=' + $.cookie('selected_tab') + ']', '#tabs').click();
} else {
$(this).first().click();
}
Теперь прямая ссылка на правку содержимого конкретной вкладки товара примет следующий вид: http://opencart.com/admin/index.php?route=catalog/product/update&token={token}&product_id=1#tab-attribute. В данном примере после перехода по ссылке сразу будет открыта вкладка Атрибуты.
Ссылку можно копировать прямо с адресной строки браузера, хештег будет автоматически изменяться в зависимости от выбранной вкладки. Следующий редактируемый товар будет открыт на вкладке, которая редактировалась в последнем товаре.
Примечание: Данная доработка распространяется и на другие разделы, где вкладки построены аналогично вкладкам в карточке товара.
16. Оптимизация нагрузки для разделов без товаров или пустых результатов поиска.
В основных контроллерах OpenCart (категории, акции, поиск, производители, модули) можно встретить строки следующего вида: $product_total = $this->model_catalog_product->getTotalProducts($data); $results = $this->model_catalog_product->getProducts($data);
Нетрудно догадаться, что если $product_total возвращает ноль, то и незачем вызывать функцию getProducts(), т.е. выполнять лишнее обращение к БД. Чтобы учесть данный нюанс, во всех контроллерах, где встречаются подобного рода конструкции, функцию getProducts() и блок кода обработки полученных результатов необходимо заключить в условие вида if ($product_total) { ... }
17. Быстрое сохранение карточки редактируемого объекта в панели администрирования OpenCart (Ctrl+S).
Суть проблемы заключается в лишних действиях по открытию и закрытию редактируемой формы, например карточки товара, когда периодически требуется смотреть результаты обновления на витрине магазина. Именно так и происходит, когда мы нажимаем стандартную кнопку Сохранить, после чего происходит переадресация, в нашем случае, на список товаров. Далее необходимо снова нажимать на ссылку Изменить и открывать карточку редактируемого товара повторно. Всё это ведёт к потере времени и траты вычислительных ресурсов браузера на прорисовку контента (сервер тоже принимает запросы, которые можно опустить).
Автором блога разработано решение быстрого сохранения формы любого объекта (товары, категории, статьи, отзывы и т.д.) без перезагрузки браузера путём нажатия сочетания клавиш Ctrl+S. При этом выводятся все необходимые сообщения, включая сообщения об ошибках. Решение на заказ, выполнено на базе jQuery, затрагивается только один файл: ./admin/view/template/common/footer.tpl.
18. Простая оптимизация SQL-запросов.
В моделях OpenCart для всех запросов к БД идентификаторы ключевых полей берутся в одинарные кавычки, причём до конкатенации переменных со строкой запроса происходит их преобразование в целочисленный тип: $sql = "SELECT * FROM " . DB_PREFIX . "product WHERE product_id = '" . (int)$data['product_id'] . "'";
Во-первых, если преобразование типа присутствует, то отпадает необходимость в "экранировании" кавычками. Во-вторых, число в кавычках SQL-сервер принимает за строку и при сопоставлении с числовым полем таблицы вынужден выполнять преобразование, т.е. тратить, пусть и малозначительное, но всё же драгоценное процессорное время.
19. Обновление закрытой сессии для нективных окон или вкладок браузера в панели администрирования OpenCart.
Вы плодотворно работаете с контентом магазина, открыли несколько окон в панели администрирования OpenCart и вносите необходимые данные. В какой-то момент вас отвлекли, прошло немало времени, и по возвращении вы видите, что сессия истекла. Теперь всё что остаётся - это закрыть все вкладки браузера кроме одной активной и пройти авторизацию заново. Как результат, информация внесена не до конца, а время потеряно.
Решением предложенным ниже этот вопрос можно решить. Достаточно будет авторизоваться на одной из вкладок и при переклюении на другие устаревшее значение ключа token в контенте будет обновлено, т.е. можно будет продолжить работать в открытых окнах.
В файле ./admin/controller/common/login.php после строки $this->session->data['token'] = md5(mt_rand()); добавляем: setcookie('token', $this->session->data['token'], 0, '/admin/');
Затем в шаблон ./admin/view/template/common/footer.tpl добавлем блок кода на javascript:
var token_proceed = false;
$(window).focus(function() { if (!token_proceed && $.cookie('token')) {
var token = getURLVar('token'); var _token = $.cookie('token');
if (token != _token) { token_proceed = true;
$('script, a, form, [onclick], [onchange]').each(function() {
var target, tag = this.nodeName.toLowerCase();
switch (tag) { case 'script' : target = $(this).html(); break;
case 'form' : target = $(this).attr('action'); break;
case 'a' : target = $(this).attr('href'); break;
default : var is_onclick = $(this).is('[onclick]');
if (is_onclick) { target = $(this).attr('onclick');
} else { target = $(this).attr('onchange'); }break;}
if (target && target != undefined) {
var _target = target.replace(token, _token); if (target != _target) {
switch (tag) {case 'script' : $(this).html(_target); break;
case 'form' : $(this).attr('action', _target); break;
case 'a' : $(this).attr('href', _target); break;
default : if (is_onclick) { $(this).attr('onclick', _target);
} else { $(this).attr('onchange', _target); }break; }}
}}); } }});
20. Добавляем поддержку локали в языковый пакет.
Чтобы дата и время корректно отображались на том или ином языке, достаточно добавить соответствующую языку локаль в корневые файлы языковых пакетов. Например, если речь идёт о русском языке, то в файлы ./admin/language/russian/russian.php и ./catalog/language/russian/russian.php необходимо добавить строку setlocale(LC_ALL, 'ru_RU.UTF-8');
21. Учитываем ведущий амерсанд в ссылке запроса.
Ранее в теме, посвященной настройке файла robots.txt, упоминались роботы, которые могут перестраивать порядок аргументов в ссылке запроса. Это допускается с точки зрения структуры запроса, однако не будет работать в OpenCart. Например, ссылки вида http://domain.com/index.php&route=common/home или http://domain.com/ipod_classic&search=Apple приведут на несуществующую страницу (404 Not Found). Чтобы учесть подобную структуру ссылок и заставить роботов и посетителей правильно набирать адрес, в файле .htaccess после строки RewriteBase / следует добавить: RewriteRule ^([^&]*)&(.+)$ $1?$2 [R,L].
22. В OpenCart 1.5+ переменные конфигурации config загружаются и десериализируются в индексном файле index.php, при этом не факт, что некоторые из них вообще будут затребованы, особенно это касается временно отключенных модулей и модулей как таковых, редко использующих чужие настройки. Так зачем тратить вычислительные ресурсы на десериализацию неиспользуемых переменных и выделять под их массивы дополнительную память? Это довольно актуально при большом количестве модулей, доработка ниже даёт некоторый прирост производительности.
В файле ./system/library/config.php функции get() и set() заменить на обновленный блок кода:
private $serialized = array();
public function get($key) { if (isset($this->data[$key])) { if (isset($this->serialized[$key])) { $this->data[$key] = unserialize($this->data[$key]); unset($this->serialized[$key]); } return $this->data[$key]; }}
public function set($key, $value, $serialized = false) { if ($serialized) { $this->serialized[$key] = true; } $this->data[$key] = $value; }
В индексных файлах код в теле цикла foreach ($query->rows as $setting) { заменить на строку $config->set($setting['key'], $setting['value'], $setting['serialized']);
23. Просматриваем SQL-запросы в системных файлах и модулях, ищем конструкции JOIN, затем проверяем наличие индексов для ключевых полей в объединяемых таблицах (ON). Индексы могут существенно повысить производительность БД.
24. Горизонтальная вкладка в административном интерфейсе.
Если обратить внимание, то во всех подверсиях OpenCart 1.5+ активная горизонтальная вкладка выглядит неестественно из-за наличия нижней границы, которой быть не должно (как в случае с вертикальной вкладкой). Чтобы исправить это недоразумение, в файл ./admin/view/stylesheet/stylesheet.css необходимо добавить следующий блок стилей:
.htabs a.selected:before,
.htabs a.selected ~ a:before,
.htabs a:last-child.selected:after {
display: inline-block;
content: '_';
color: transparent;
height: 1px;
position: absolute;
margin-top: 22px;
width: 25%;
}
.htabs a.selected:before {
margin-left: -15px;
background-color: white;
}
.htabs a.selected ~ a:before {
margin-left: -19px;
background-color: #ddd;
}
.htabs a:last-child.selected:after {
margin-left: 15px;
background-color: #ddd;
}
25. Сообщаем роботу о страницах на других языках.
Многие из пользователей OpenCart добавляют ссылки на страницы на разных языках непосредственно в карту сайта. Однако такое решение можно считать избыточным, поскольку достаточно об этом сообщить альтернативной ссылкой в теле документа на ведущем языке. Выгдядеть это может следующим образом (для товара):
if ($GLOBALS['languages'] > 1) {
$config_language = $this->config->get('config_language');
foreach ($GLOBALS['languages'] as $code => $language) {
if ($code != $config_language) {
$alternate_url = str_replace(HTTP_SERVER, HTTP_SERVER . $code . '/', $this->url->link('product/product', 'product_id=' . $product_id)) . '" hreflang="' . $code;
$this->document->addLink($alternate_url, 'alternate');
}
}
}
26. Убираем лишнюю нагрузку в модулях
Практически все модули в OpenCart делаются по умолчанию, т.е. на основе стандартной модели, где в конце модуля происходит его дамп в шаблон ($this->template=... $this->render();). Однако рендеринг лучше выполнять только тогда, когда есть выборка данных, тогда не будет лишнего обращения к файлу-шаблону (*.tpl). Для этого во всех модулях строку $this->render(); необходимо заключить в тело соответствующего условия if.
27. Уменьшаем нагрузку на БД для одного магазина
Если в системе используется конфигурация только одного магазина, т.е. товары не распределяются между разными интерфейсами, то нет необходимости в лишних sql-объединениях с целью определения связи с идентификатором магазина (для всех по умолчанию store_id = 0). Поэтому из всех пользовательских запросов к БД, в частности в файлах-моделях, можно удалить части следующего типа:
LEFT JOIN " . DB_PREFIX . "product_to_store p2s ON (p.product_id = p2s.product_id)
AND p2s.store_id = '" . (int)$this->config->get('config_store_id') . "'"
28. Снижаем нагрузку на файловую систему
Очень актуально для расшаренных тарифных планов, где есть ограничения на загрузку файловой системы. Если у вас используется шаблон default, то OpenCart всё равно будет проверять существование других шаблонов, поскольку почти в каждом контроллере встречается запись вида if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') ...
Оптимальным будет такое решение: if ($this->config->get('config_template') != 'default' && file_exists(DIR_TEMPLATE . $this->config->get('config_template') ...
15. Прямые ссылки на вкладки редактируемых товаров с запоминанием последних.
Итак, суть задачи в том, чтобы дать возможность разным пользователям административной панели OpenCart оперативно вносить изменения в карточки товаров по прямым ссылкам. Это могут быть ссылки как от коллег, так и от руководителей. Также необходимо запоминание последней закладки при редактировании одних и тех же полей для нескольких и более товаров. Целью доработки является снижение временных затрат при работе с интерфейсом.
В скрипте ./admin/view/javascript/jquery/tabs.js после $(obj).click(function() { добавить следующие строки:
if ($(this).parent().attr('id') == 'tabs') {
location.hash = $(this).attr('href');
$.cookie('selected_tab', location.hash);
}
В этом же файле строку $(this).first().click(); заменить на следующий блок кода:
var is_tabs = $(this).parent().attr('id') == 'tabs';
var hash = location.hash;
if (is_tabs && hash) {
$('[href=' + hash + ']', '#tabs').click();
} else if (is_tabs && getURLVar('route').indexOf('/update') > 0 && $.cookie('selected_tab')) {
$('[href=' + $.cookie('selected_tab') + ']', '#tabs').click();
} else {
$(this).first().click();
}
Теперь прямая ссылка на правку содержимого конкретной вкладки товара примет следующий вид: http://opencart.com/admin/index.php?route=catalog/product/update&token={token}&product_id=1#tab-attribute. В данном примере после перехода по ссылке сразу будет открыта вкладка Атрибуты.
Ссылку можно копировать прямо с адресной строки браузера, хештег будет автоматически изменяться в зависимости от выбранной вкладки. Следующий редактируемый товар будет открыт на вкладке, которая редактировалась в последнем товаре.
Примечание: Данная доработка распространяется и на другие разделы, где вкладки построены аналогично вкладкам в карточке товара.
16. Оптимизация нагрузки для разделов без товаров или пустых результатов поиска.
В основных контроллерах OpenCart (категории, акции, поиск, производители, модули) можно встретить строки следующего вида: $product_total = $this->model_catalog_product->getTotalProducts($data); $results = $this->model_catalog_product->getProducts($data);
Нетрудно догадаться, что если $product_total возвращает ноль, то и незачем вызывать функцию getProducts(), т.е. выполнять лишнее обращение к БД. Чтобы учесть данный нюанс, во всех контроллерах, где встречаются подобного рода конструкции, функцию getProducts() и блок кода обработки полученных результатов необходимо заключить в условие вида if ($product_total) { ... }
17. Быстрое сохранение карточки редактируемого объекта в панели администрирования OpenCart (Ctrl+S).
Суть проблемы заключается в лишних действиях по открытию и закрытию редактируемой формы, например карточки товара, когда периодически требуется смотреть результаты обновления на витрине магазина. Именно так и происходит, когда мы нажимаем стандартную кнопку Сохранить, после чего происходит переадресация, в нашем случае, на список товаров. Далее необходимо снова нажимать на ссылку Изменить и открывать карточку редактируемого товара повторно. Всё это ведёт к потере времени и траты вычислительных ресурсов браузера на прорисовку контента (сервер тоже принимает запросы, которые можно опустить).
Автором блога разработано решение быстрого сохранения формы любого объекта (товары, категории, статьи, отзывы и т.д.) без перезагрузки браузера путём нажатия сочетания клавиш Ctrl+S. При этом выводятся все необходимые сообщения, включая сообщения об ошибках. Решение на заказ, выполнено на базе jQuery, затрагивается только один файл: ./admin/view/template/common/footer.tpl.
18. Простая оптимизация SQL-запросов.
В моделях OpenCart для всех запросов к БД идентификаторы ключевых полей берутся в одинарные кавычки, причём до конкатенации переменных со строкой запроса происходит их преобразование в целочисленный тип: $sql = "SELECT * FROM " . DB_PREFIX . "product WHERE product_id = '" . (int)$data['product_id'] . "'";
Во-первых, если преобразование типа присутствует, то отпадает необходимость в "экранировании" кавычками. Во-вторых, число в кавычках SQL-сервер принимает за строку и при сопоставлении с числовым полем таблицы вынужден выполнять преобразование, т.е. тратить, пусть и малозначительное, но всё же драгоценное процессорное время.
19. Обновление закрытой сессии для нективных окон или вкладок браузера в панели администрирования OpenCart.
Вы плодотворно работаете с контентом магазина, открыли несколько окон в панели администрирования OpenCart и вносите необходимые данные. В какой-то момент вас отвлекли, прошло немало времени, и по возвращении вы видите, что сессия истекла. Теперь всё что остаётся - это закрыть все вкладки браузера кроме одной активной и пройти авторизацию заново. Как результат, информация внесена не до конца, а время потеряно.
Решением предложенным ниже этот вопрос можно решить. Достаточно будет авторизоваться на одной из вкладок и при переклюении на другие устаревшее значение ключа token в контенте будет обновлено, т.е. можно будет продолжить работать в открытых окнах.
В файле ./admin/controller/common/login.php после строки $this->session->data['token'] = md5(mt_rand()); добавляем: setcookie('token', $this->session->data['token'], 0, '/admin/');
Затем в шаблон ./admin/view/template/common/footer.tpl добавлем блок кода на javascript:
var token_proceed = false;
$(window).focus(function() { if (!token_proceed && $.cookie('token')) {
var token = getURLVar('token'); var _token = $.cookie('token');
if (token != _token) { token_proceed = true;
$('script, a, form, [onclick], [onchange]').each(function() {
var target, tag = this.nodeName.toLowerCase();
switch (tag) { case 'script' : target = $(this).html(); break;
case 'form' : target = $(this).attr('action'); break;
case 'a' : target = $(this).attr('href'); break;
default : var is_onclick = $(this).is('[onclick]');
if (is_onclick) { target = $(this).attr('onclick');
} else { target = $(this).attr('onchange'); }break;}
if (target && target != undefined) {
var _target = target.replace(token, _token); if (target != _target) {
switch (tag) {case 'script' : $(this).html(_target); break;
case 'form' : $(this).attr('action', _target); break;
case 'a' : $(this).attr('href', _target); break;
default : if (is_onclick) { $(this).attr('onclick', _target);
} else { $(this).attr('onchange', _target); }break; }}
}}); } }});
20. Добавляем поддержку локали в языковый пакет.
Чтобы дата и время корректно отображались на том или ином языке, достаточно добавить соответствующую языку локаль в корневые файлы языковых пакетов. Например, если речь идёт о русском языке, то в файлы ./admin/language/russian/russian.php и ./catalog/language/russian/russian.php необходимо добавить строку setlocale(LC_ALL, 'ru_RU.UTF-8');
21. Учитываем ведущий амерсанд в ссылке запроса.
Ранее в теме, посвященной настройке файла robots.txt, упоминались роботы, которые могут перестраивать порядок аргументов в ссылке запроса. Это допускается с точки зрения структуры запроса, однако не будет работать в OpenCart. Например, ссылки вида http://domain.com/index.php&route=common/home или http://domain.com/ipod_classic&search=Apple приведут на несуществующую страницу (404 Not Found). Чтобы учесть подобную структуру ссылок и заставить роботов и посетителей правильно набирать адрес, в файле .htaccess после строки RewriteBase / следует добавить: RewriteRule ^([^&]*)&(.+)$ $1?$2 [R,L].
22. В OpenCart 1.5+ переменные конфигурации config загружаются и десериализируются в индексном файле index.php, при этом не факт, что некоторые из них вообще будут затребованы, особенно это касается временно отключенных модулей и модулей как таковых, редко использующих чужие настройки. Так зачем тратить вычислительные ресурсы на десериализацию неиспользуемых переменных и выделять под их массивы дополнительную память? Это довольно актуально при большом количестве модулей, доработка ниже даёт некоторый прирост производительности.
В файле ./system/library/config.php функции get() и set() заменить на обновленный блок кода:
private $serialized = array();
public function get($key) { if (isset($this->data[$key])) { if (isset($this->serialized[$key])) { $this->data[$key] = unserialize($this->data[$key]); unset($this->serialized[$key]); } return $this->data[$key]; }}
public function set($key, $value, $serialized = false) { if ($serialized) { $this->serialized[$key] = true; } $this->data[$key] = $value; }
В индексных файлах код в теле цикла foreach ($query->rows as $setting) { заменить на строку $config->set($setting['key'], $setting['value'], $setting['serialized']);
23. Просматриваем SQL-запросы в системных файлах и модулях, ищем конструкции JOIN, затем проверяем наличие индексов для ключевых полей в объединяемых таблицах (ON). Индексы могут существенно повысить производительность БД.
24. Горизонтальная вкладка в административном интерфейсе.
Если обратить внимание, то во всех подверсиях OpenCart 1.5+ активная горизонтальная вкладка выглядит неестественно из-за наличия нижней границы, которой быть не должно (как в случае с вертикальной вкладкой). Чтобы исправить это недоразумение, в файл ./admin/view/stylesheet/stylesheet.css необходимо добавить следующий блок стилей:
.htabs a.selected:before,
.htabs a.selected ~ a:before,
.htabs a:last-child.selected:after {
display: inline-block;
content: '_';
color: transparent;
height: 1px;
position: absolute;
margin-top: 22px;
width: 25%;
}
.htabs a.selected:before {
margin-left: -15px;
background-color: white;
}
.htabs a.selected ~ a:before {
margin-left: -19px;
background-color: #ddd;
}
.htabs a:last-child.selected:after {
margin-left: 15px;
background-color: #ddd;
}
25. Сообщаем роботу о страницах на других языках.
Многие из пользователей OpenCart добавляют ссылки на страницы на разных языках непосредственно в карту сайта. Однако такое решение можно считать избыточным, поскольку достаточно об этом сообщить альтернативной ссылкой в теле документа на ведущем языке. Выгдядеть это может следующим образом (для товара):
if ($GLOBALS['languages'] > 1) {
$config_language = $this->config->get('config_language');
foreach ($GLOBALS['languages'] as $code => $language) {
if ($code != $config_language) {
$alternate_url = str_replace(HTTP_SERVER, HTTP_SERVER . $code . '/', $this->url->link('product/product', 'product_id=' . $product_id)) . '" hreflang="' . $code;
$this->document->addLink($alternate_url, 'alternate');
}
}
}
26. Убираем лишнюю нагрузку в модулях
Практически все модули в OpenCart делаются по умолчанию, т.е. на основе стандартной модели, где в конце модуля происходит его дамп в шаблон ($this->template=... $this->render();). Однако рендеринг лучше выполнять только тогда, когда есть выборка данных, тогда не будет лишнего обращения к файлу-шаблону (*.tpl). Для этого во всех модулях строку $this->render(); необходимо заключить в тело соответствующего условия if.
27. Уменьшаем нагрузку на БД для одного магазина
Если в системе используется конфигурация только одного магазина, т.е. товары не распределяются между разными интерфейсами, то нет необходимости в лишних sql-объединениях с целью определения связи с идентификатором магазина (для всех по умолчанию store_id = 0). Поэтому из всех пользовательских запросов к БД, в частности в файлах-моделях, можно удалить части следующего типа:
LEFT JOIN " . DB_PREFIX . "product_to_store p2s ON (p.product_id = p2s.product_id)
AND p2s.store_id = '" . (int)$this->config->get('config_store_id') . "'"
28. Снижаем нагрузку на файловую систему
Очень актуально для расшаренных тарифных планов, где есть ограничения на загрузку файловой системы. Если у вас используется шаблон default, то OpenCart всё равно будет проверять существование других шаблонов, поскольку почти в каждом контроллере встречается запись вида if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') ...
Оптимальным будет такое решение: if ($this->config->get('config_template') != 'default' && file_exists(DIR_TEMPLATE . $this->config->get('config_template') ...
0 comments:
Отправить комментарий