Перейти к публикации
View in the app

A better way to browse. Learn more.

Дизайн и модификация Invision Community

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

[IPB 3.1.4] Устранение бага фильтрации топиков при сортировке по start_date

(0 отзывов)

В IPB 3.1.4 пользователю предоставляется удобный инструмент фильтрации и сортировки отображаемых топиков. Но в этом инструменте есть бага. Точнее бага не в GUI, а в коде, который обрабатывает параметры запроса и строит SQL-запрос.

 

Для начала опишу причину, из-за которой пришлось этот инструмент дорабатывать. На нашем форуме есть один большущий подфорум BigForum, в котором каждый день создаётся от 4 до 20 топиков. И очень часто возникает потребность просмотра топиков, которые созданы в течении последних суток и отсортированных в порядке создания первого поста в топиках.

Я предложил главному админу (идеологу проекта) создать фейковый подфорум с названием "Все темы за последние сутки", который бы просто редиректил на BigForum с заранее установленными параметрами фильтрации и сортировки в строке запроса. Начал изучать возможность реализации этой идеи. В настройках создания нового форума нашёл опцию, в которой указавается редирект. Изучил возможные параметры в запросе, полазив по php-исходникам.

 

Screen_Hunter_0002.png

 

Строка запроса, которая осуществляет описанную фильтрацию и сортировку для форума #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 комментарий

Рекомендованные комментарии

Опубликовано:

Ну это не совсем баг. "Показать за время" никак не подразумевает, что выборка будет идти по потому же полю что указано в сортировке. Тут два варианта: либо по последнему сообщению, либо по дате создания. Очевидно что разработчики решили сделать по последнему сообщению, и имхо это вполне разумно.

Ну если вам нужно чтобы именно при "Сортировать по" в селекте участвовало поле start_date, создайте отдельное условие

 

$prune_field = ( $sort_key == 'start_date') ? 'start_date' : 'last_post';

 

Зачем весь остальной код, так и не понял.

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.