OCJ: в акаунте у купленных файлов теперь видна дата последнего обновления

- Posted in Uncategorized by

В магазине расширений OpencartJazz.com мелкое, но удобное улучшение: в акаунте покупателя, в "Мои заказы / Файлы для скачивания" теперь видна дата обновления файлов.

Следить за изменениями стало проще!

В данный момент следить за изменениями можно по этой дате, а дальше смотреть `history.txt` в скачанном архиве. На очереди - дублирование списка обновлений в отдельной вкладке описания товара и подписка по RSS. Думаю, так за обновлениями следить будет ещё легче.

P.S. Стандартно Опенкарт выводит там никому не нужную дату первого создания файла для скачивания, которая никогда не обновляется.

Совсем забыл: Opencart SeoPro для OC2 с кешированием и мультиязыками в URL

- Posted in Uncategorized by

Что-то я совсем забыл написать: у нас уже давно есть и прекрасно работает (на Opencart 2.0.1.1) SeoPro для OC2!

"Из коробки" есть:

  • кеширование
  • мультиязык в URL (site.com/ru/tratata/, site.com/en/tratata/)

Возможно, что-то ещё, что я уже не очень помню. Это основное. Я активно пользуюсь версией 2.0.1.1 для живого магазина, благодаря чему русский перевод и SeoPro/OC2 ежедневно тестируются и шлифуются. Перевод во многих местах вычитывается в контексте и исправляется по мелочам, сеопро уже не трогаем - работает стабильно. Хотя может ещё про дефолтный язык что-то подумаем. Позже.

Github: https://github.com/rb2/opencart-seopro

OpencartJazz: OCJ SeoPro для Опенкарт 2.0.x

Русское описание пострадало - была мешанина из английского и русского, я в процессе переделки оставил только английский в README. Русское добавлю когда-нибудь, пункт в туду записан.

Устройство Opencart 2.0 (OC2): работа инсталлятора, модификаций и модулей

- Posted in Uncategorized by

Мда… Синтаксические ошибки на этапе формирования модификации запросто укладывают весь сайт. OCMOD формирует файл с ошибкой, дальше ВСЁ… ФИНИШ. Пока не пофискишь - не поедет. Учитывая, что синтаксическая ошибка может запросто возникнуть при конфликне модулей, система будет слабо автоматизируемой. Должен работать квалифицированный админ. Сценарий примерно такой:

  • ставим модификацию
  • обновляем кэш
  • если система загнулась:
    • удаляем system/modification/*
    • заходим в систему как админ и удаляем проблемную модификацию
    • перегенерируем кэш
    • пишем рекламацию

Чем модификация отличается от инсталлятора

Модификация работает только в каталоге system/modification . Ей не нужны права на запись по всему движку: это инсталлеру надо. И достигается через фтп-функции и фтп-пользователя.

Модификация исходных файлов не меняет. Результат работы записывается в system/modification .

Что такое инсталлятор, модификация и модуль. Их взаимодействие

По большому счёту, в системе модуля нет вообще. Причина в том, что в принципе отсутствует интерфейс взаимодействия внешнего кода с ядром. Некоторые зачатки появились во второй версии с внесением events. И всё. В остальном - есть некоторое изменение кода, состоящее из новых файлов и изменения старых, а также механизм настройки параметров и визуальной привязки кода к layout. Вот это всё горделиво названо словом “модуль”. И дальше есть инсталлятор, который вносит новые файлы в систему и регистрирует xml для внесения изменений в существующие файлы. А модификация просто реализует эти изменения. Вот и всё.

Процедура инсталляции размещает по местам новые файлы и записывает в таблицу XML. Кроме того, она исполняет скрипты install.sql & install.php . Больше она не делает ничего.

Модификация при нажатии кнопки “Refresh”:

  • очищает кэш модификаций system/modification/*
  • ищет system/modification.xml и исполняет его
  • ищет system/*.ocmod.xml и исполняет их. Это “форточка” для девелопера.
  • последовательно извлекает из таблицы oc_modification все xml, запись за записью, и создаёт новый кэш из модифицированных файлов.

Всё

Opencart 2.0.1.1 bugfix: default language fallback

- Posted in Uncategorized by

Если вы пользуетесь не только английским языком, то вам наверняка попадались отсутствующие строки наподобие text_home, button_continue, button_login.

Раньше в этом случае вообще происходила ошибка и страница "ломалась": надо было следить за соответствием переводов и добавлять отсутствующие в переводе строки или дублировать файл целиком из английской версии модуля. В версиях Opencart 2.0 отсутствие некоторых строк в переводах наконец-то более-менее исправлено. Если раньше возникала ошибка, то сейчас берётся строка из языка по умолчанию (английского).

Но всё равно не учтён один момент. Если в английском работает логика наследования строки из english/default.php (например, переводы text_continue, text_yes, text_no и т.п. не дублируются в языковых файлах модулей и компонентах движка, а берутся из default.php), то в случае точно такой же ситуации в дополнительном языке языковый ресурс выбирается по неправльной цепочке:

  • надо: ru/module -> ru/default.php -> en/default.php
  • а происходит так: ru/module -> en/module

И вуаля: в русском строки нет (т.к. её не было в оригинале), в английском нет (т.к. там оно берётся из default.php), в результате - вывод служебного ключа строки, а не правильного перевода. Вот те самые text_home, button_continue, button_ok и тому подобные.

Лечится так:

commit b08fa836f2a55eb9ef2205ce8c3491b6d00c5319
Author: Ruslan Brest <rb@labtodo.com>
Date:   Tue Jan 13 11:01:54 2015 -0500
    [!][lang] fix language fallback:
    
    if translation string not found in lang/module/submodule,
    fall back to lang/default at first, then to english/default
diff --git a/html/extensions/system/library/language.php b/html/extensions/system/library/language.php
index c8ba268..5d10d50 100644
--- a/html/extensions/system/library/language.php
+++ b/html/extensions/system/library/language.php
@@ -15,16 +15,18 @@ class Language {
    public function load($filename) {
        $_ = array();
 
-       $file = DIR_LANGUAGE . $this->default . '/' . $filename . '.php';
 
-       if (file_exists($file)) {
-           require($file);
-       }
-
-       $file = DIR_LANGUAGE . $this->directory . '/' . $filename . '.php';
-
-       if (file_exists($file)) {
-           require($file);
+       $files = array(
+           DIR_LANGUAGE . $this->default   . '/' . $filename . '.php',
+           DIR_LANGUAGE . $this->directory . '/' . 'default.php',
+           DIR_LANGUAGE . $this->directory . '/' . $filename . '.php'
+           );
+
+       foreach($files as $file)
+       {
+           if (file_exists($file)) {
+               require($file);
+           }
        }
 
        $this->data = array_merge($this->data, $_);

Процессы в мелких webdev командах

- Posted in Uncategorized by

Форум для обсуждения внутренних тем не взлетел за полгода. Очень хотелось уйти от неструктурированных обсуждений в скайпе и иметь что-то более самодокументируемое. Ближе к email, но более централизованное и разделённое на потоки-топики. Форум, в общем. Нормально подходит.

Но вот увы. Теоретически очень хорошо подходит под идею. На практике - не работает. Точно так же у нас не взлетели и багтрекеры (issue tracker) в гит-репозиториях (Github, Bitbucket). Но там мне они и самому неудобны: хочется доступности в оффлайне, как весь репо с работой - рядом и перед носом. А оно где-то далеко и оторвано.

Что работает?

Сумбурные обсуждения по скайпу плюс быстрая фиксация кем-то важных огрызков разговоров в файлы - в общем репо или в соседней с репо-папкой локальной "репо.MNT" (MNT - от слова maintenance, обслуживание). Забыли оперативно записать - считай потеряли. Потом фиг найдёшь. Поиск в скайпе сделан для отъявленных мазохистов.

Ах, ну да - гит-репозитории как бы подразумеваются. Любые распределённые VCS, но мы только с гитом работаем. Возможность кипучей работы оффлайн и синхронизация с удалёнными репами -- киллерфича.

Такие дела.

На сегодня наверное всё, хотя у меня ещё есть что сказать про тудушки на flat files и "наколенных" вики на россыпях Markdown файлов. Но пусть утрясётся и проверится подольше.

Opencart 2.0.1.1 bugfix: отправление отзывов к товару

- Posted in Uncategorized by

Починил ошибку при отправлении email-уведомлений админу, когда покупатель оставляет отзыв к товару. Из-за неё скорей всего форма отзыва вела себя невнятно, не показывая покупателю, что всё уже случилось и жизнь прекрасна.

В результате было непонятно, что вообще произошло, пользователи отправляли по несколько отзывов (самые прилежные), а лог ошибок опенкарта заполнялся строчками, причину и место возникновения которых хрен угадаешь:

2014-12-30 18:44:07 - PHP Warning:  html_entity_decode() expects parameter 1 to be
string, array given in /..../system/library/mail.php on line 30
2014-12-30 18:44:07 - PHP Notice:  Error: E-Mail to required!
in /..../system/library/mail.php on line 63

Админ также не получал уведомлений о непроверенных отзывах, что тоже печально и грустно и не способствует повышению доверия между покупателем и магазином.

Лечится так

Простыми словами:

  • открываем catalog/model/catalog/review.php,
  • ищем строку $mail->setTo(array($this->config->get('config_email')));
  • и убираем `array(` с одной стороны и лишний `)` с другой.

Вторая добавка там же рядом, чуть ниже (см. diff) - чтобы избежать ошибок при отправке уведомлений по списку email-ов другим админам магазина. Уведомления отправляются на email владельца магазна (указывается в настройках магазина) и по списку дополнительных адресов в настройках, разделённому запятыми. Если у вас вокруг запятых затешутся пробелы - будут ошибки.

Цветными словами:

commit 870bb1469173e9ec28346408bc19838838c6fd17
Author: Ruslan Brest <rb@labtodo.com>
Date:   Sat Jan 10 20:47:00 2015 -0500
    [!] fix admin email notification sending when customer posts product review
diff --git a/catalog/model/catalog/review.php b/catalog/model/catalog/review.php
index 2eeab26..ae23828 100644
--- a/catalog/model/catalog/review.php
+++ b/catalog/model/catalog/review.php
@@ -22,7 +22,7 @@ class ModelCatalogReview extends Model {
                        $message .= $this->db->escape(strip_tags($data['text'])) . "\n\n";
 
                        $mail = new Mail($this->config->get('config_mail'));
-                       $mail->setTo(array($this->config->get('config_email')));
+                       $mail->setTo($this->config->get('config_email'));
                        $mail->setFrom($this->config->get('config_email'));
                        $mail->setSender($this->config->get('config_name'));
                        $mail->setSubject($subject);
@@ -33,6 +33,7 @@ class ModelCatalogReview extends Model {
                        $emails = explode(',', $this->config->get('config_mail_alert'));
 
                        foreach ($emails as $email) {
+                               $email = trim($email);
                                if ($email && preg_match('/^[^\@]+@.*.[a-z]{2,15}$/i', $email)) {
                                        $mail->setTo($email);
                                        $mail->send();

Opencart 2.0.1.1 bugfix: OCMOD Multiline fix

- Posted in Uncategorized by

В OCMOD нами добавлена поддержка атрибута "quote" (bool) в режиме regex. Это позволяет делать замену не строки, а набора строк. С этим переключателем используется функция preg_quote:

preg_quote() takes str and puts a backslash in front of every character that is part of the regular expression syntax. This is useful if you have a run-time string that you need to match in some text and the string may contain special regex characters. The special regular expression characters are: . \ + * ? [ ^ ] $ ( ) { } = ! < > | : -

После этого preg позволяет многострочную замену. Обычный режим работы продолжает работать по-старому: просто добавляется опция, с которой становится возможно использовать многострочные замены в ocmod XML.

Рекомендуется всем: стандартный функционал не затрагивается, появляется новый.

Также описано на OpencartJazz: OCJ :: OCMOD Multiline fix. Там прикреплён изменённый файл, но пока его можно скачать только после регистрации и "покупки" за 0.00. Будет время - починю это неудобство.

diff --git a/admin/controller/extension/modification.php b/admin/controller/extension/modification.php
index 086a65c..7159ffb 100644
--- a/admin/controller/extension/modification.php
+++ b/admin/controller/extension/modification.php
@@ -307,12 +307,18 @@ class ControllerExtensionModification extends Controller {
 } else {                                   
    $search = $operation->getElementsByTagName('search')->item(0)->textContent;
    $limit = $operation->getElementsByTagName('search')->item(0)->getAttribute('limit');
+   $quote = $operation->getElementsByTagName('search')->item(0)->getAttribute('quote');
    $replace = $operation->getElementsByTagName('add')->item(0)->textContent;
                                        
    // Limit
    if (!$limit) {
        $limit = -1;
    }
+
+   // Quote
+   if ($quote=='true') {
+       $search = preg_quote($search);
+   }
 
    // Log
    $match = array();