[IPB 3.1.4] Устранение бага фильтрации топиков при сортировке по start_date
В IPB 3.1.4 пользователю предоставляется удобный инструмент фильтрации и сортировки отображаемых топиков. Но в этом инструменте есть бага. Точнее бага не в GUI, а в коде, который обрабатывает параметры запроса и строит SQL-запрос.
Для начала опишу причину, из-за которой пришлось этот инструмент дорабатывать. На нашем форуме есть один большущий подфорум BigForum, в котором каждый день создаётся от 4 до 20 топиков. И очень часто возникает потребность просмотра топиков, которые созданы в течении последних суток и отсортированных в порядке создания первого поста в топиках.
Я предложил главному админу (идеологу проекта) создать фейковый подфорум с названием "Все темы за последние сутки", который бы просто редиректил на BigForum с заранее установленными параметрами фильтрации и сортировки в строке запроса. Начал изучать возможность реализации этой идеи. В настройках создания нового форума нашёл опцию, в которой указавается редирект. Изучил возможные параметры в запросе, полазив по php-исходникам.
Строка запроса, которая осуществляет описанную фильтрацию и сортировку для форума #13:
index.php?showforum=13&prune_day=1&st=0&sort_key=start_date&sort_by=Z-A
Описание параметров запроса:
showforum=13 - указывает на ID форума в БД (BigForum)
prune_day=1 - указывает на количество дней, за которые нужно выбрать топики (1 день)
sort_key=start_date - указывает на параметр, по которому будет осуществлена сортировка (по дате создания топика)
sort_by=Z-A - указывает на направление сортировки (от большего к меньшему)
Так вот в ходе эксперементов выяснил, что при таких параметрах выборка топиков из БД всегда осуществляется по полю topics.last_post , что и является БАГОМ РАЗРАБОТЧИКОВ IPB. Ну сами посудите: вы хотите делать выборку по полю topics.start_date , но сделать это не можете, т.к. параметр sort_key отвечает только за сортировку. Пришлось искать место в коде, которое отвечает за это.
Затем главный админ решил фильтровать не за последние сутки, а за последние 3 дня. Поэтому название нового подфорума стало таким: "Все темы за последние 3 дня".
Так же было решено сделать дополнительно ещё 3 подфорума с редиректами: "Темы за последние 30 дней", "Темы за предыдущий месяц" и "Темы за позапрошлый месяц". На самом деле от двух последних тем мы отказались (после тестирования среди модераторов), но я всё равно опишу как это сделать.
Инструкция по доработке фильтрации и сортировки топиков.
Открываем на редактирование файл admin/applications/forums/modules_public/forums/forums.php и ищем строку:
$Prune = $prune_value < 100 ? (time() - ($prune_value * 60 * 60 * 24)) : ( ( $prune_value == 200 AND $this->memberData['member_id'] ) ? $this->memberData['last_visit'] : 0 );
Заменяем эту строку на:
if ($prune_value < 0) { $Prune = $prune_value; } else { $Prune = $prune_value < 100 ? (time() - ($prune_value * 60 * 60 * 24)) : ( ( $prune_value == 200 AND $this->memberData['member_id'] ) ? $this->memberData['last_visit'] : 0 ); }
Через несколько строчек идёт заполнение массива $prune_by_day, который отвечает за локализацию параметров сортировки (см. скриншот выше).
Т.к. мы хотим добавить 3 новых сортировки, то нужно добавить 3 новых параметра в массив.
Заменяем массив $prune_by_day на такой:
$prune_by_day = array( '-2' => 'show_before_prev_month', '-1' => 'show_prev_month', '1' => 'show_today', '3' => 'show_3_days', '5' => 'show_5_days', '7' => 'show_7_days', '10' => 'show_10_days', '15' => 'show_15_days', '20' => 'show_20_days', '25' => 'show_25_days', '30' => 'show_30_days', '60' => 'show_60_days', '90' => 'show_90_days', '100' => 'show_all', '200' => 'show_last_visit' );
Чуть ниже находим строчку "if ( $Prune )". Следующий блок кода:
if ( $Prune ) { if ( $prune_value == 200 ) { /* Just new content, don't show pinned, please */ $_SQL_AGE_PRUNE = " AND (t.last_post > {$Prune})"; } else { $_SQL_AGE_PRUNE = " AND (t.pinned=1 or t.last_post > {$Prune})"; } }
заменяем на такой:
if ( $Prune > 0 ) { $flt_field = 'last_post'; if ( $sort_key == 'start_date' ) $flt_field = 'start_date'; if ( $prune_value == 200 ) { /* Just new content, don't show pinned, please */ $_SQL_AGE_PRUNE = " AND (t.$flt_field > {$Prune})"; } else { $_SQL_AGE_PRUNE = " AND (t.pinned=1 OR t.$flt_field > {$Prune})"; } } else { // отрицательные значения параметра prune_day имеет силу только при сортировке по полю start_date !!! if ( $sort_key == 'start_date' ) { if ( $Prune == -1 OR $Prune == -2 ) { // прошлый и позапрошлый месяц $ct = time(); $y = intval(date('Y', $ct)); $m = intval(date('n', $ct)); $m += 1 + $Prune; if ($m <= 0) { $y--; $m += 12; } $d2 = strtotime(sprintf("%04d-%02d-%02d", $y, $m, 1)); $m--; if ($m <= 0) { $y--; $m += 12; } $d1 = strtotime(sprintf("%04d-%02d-%02d", $y, $m, 1)); $_SQL_AGE_PRUNE = " AND (t.pinned=0 AND t.start_date >= $d1 AND t.start_date < $d2)"; } } }
Данный код как раз таки заставит при указании sort_key=start_date производить выборку из БД по полю topics.start_date. Также данный код отвечает за отображение форумов "Темы за предыдущий месяц" и "Темы за позапрошлый месяц".
Чуть ниже находим строчку:
else if ( ( $_SQL_EXTRA or $_SQL_AGE_PRUNE ) and ! $this->request['modfilter'] )
и заменяем её на:
else if ( $_SQL_EXTRA or $_SQL_AGE_PRUNE OR $this->request['modfilter'] )
Новая строка взята из 3.3.4 (видимо баг какойто исправили в отображении топиков для модераторов).
Сохраняем файл forums.php и копируем его на WEB-сервер.
Теперь нужно локализировать 3 новых параметра.
Открываем на редактирование файл /admin/applications/forums/xml/public_forums_language_pack.xml и после строчки <languagegroup> добавляем 3 блока:
<lang> <word_app>forums</word_app> <word_pack>public_forums</word_pack> <word_key>show_before_prev_month</word_key> <word_default>From: before prev days</word_default> <word_custom>За: позапрошлый месяц</word_custom> <word_default_version>31006</word_default_version> <word_custom_version/> <word_js>0</word_js> </lang> <lang> <word_app>forums</word_app> <word_pack>public_forums</word_pack> <word_key>show_prev_month</word_key> <word_default>From: prev days</word_default> <word_custom>За: предыдущий месяц</word_custom> <word_default_version>31006</word_default_version> <word_custom_version/> <word_js>0</word_js> </lang> <lang> <word_app>forums</word_app> <word_pack>public_forums</word_pack> <word_key>show_3_days</word_key> <word_default>From: 3 days</word_default> <word_custom>За: 3 дня</word_custom> <word_default_version>31006</word_default_version> <word_custom_version/> <word_js>0</word_js> </lang>
Сохраняем файл public_forums_language_pack.xml и копируем его на WEB-сервер.
Заходим в админскую панель.
Импортируем файлик public_forums_language_pack.xml в кеш IPB ("Внешний вид" -> "Языки системы" -> "Загрузка XML-архива с языковыми настройками").
Создаём четыре новых форума, в каждом из которых заполняем поле "Redirect URL":
1) "Все темы за последние 3 дня" : index.php?showforum=13&prune_day=3&st=0&sort_key=start_date&sort_by=Z-A
2) "Все темы за последние 30 дней" : index.php?showforum=13&prune_day=30&st=0&sort_key=start_date&sort_by=Z-A
3) "Темы за предыдущий месяц" : index.php?showforum=13&prune_day=-1&st=0&sort_key=start_date&sort_by=Z-A
4) "Темы за позапрошлый месяц" : index.php?showforum=13&prune_day=-2&st=0&sort_key=start_date&sort_by=Z-A
Этим самым мы создали удобную навигацию по BigForum, а также пофиксили фильтрацию топиков при указании сортировки "По: дате открытия".
PS. Данная бага с выборкой присутствует и в IPB 3.3.4
1 комментарий
Рекомендованные комментарии
Создайте аккаунт или войдите в него для комментирования
Вы должны быть пользователем, чтобы оставить комментарий
Создать аккаунт
Зарегистрируйтесь для получения аккаунта. Это просто!
Зарегистрировать аккаунтВойти
Уже зарегистрированы? Войдите здесь.
Войти сейчас