Категории форума

Market PRO + всё, что связано с ЧПУ

Привет , ты много пропустил
webitproff
Телеграм для сообщений
@webitproff
webitproff • 13.09.2026 01:09 #1

 пресет правил

/plugins/urleditor/presets/marketplace.dat

forums    m=posts&q=&d=    forums/{forums_url_structure()}/page{$d}
forums    m=posts&q=*    forums/{forums_url_structure()}
forums    m=posts&id=*    forums/{forums_url_structure()}
forums    m=topics&s=&d=    forums/{forums_url_structure()}/page{$d}{!$m}
forums    m=topics&s=*    forums/{forums_url_structure()}{!$m}
forums    c=*    forums/{$c}
forums    *    forums
page    m=*                        page?m={$m}
page    c=system&al=*            {$al}{!$c}
page    c=*&al=*                {cot_url_catpath()}/{$al}
page    c=*&id=*                {cot_url_catpath()}/{$id}
page    c=*                        {cot_url_catpath()}
index    *                        {$_path}
plug    e=tags&a=pages&t=*        {$e}/{$t}{!$a}
plug    e=tags&a=*&t=*            {$e}/{$a}/{$t}
plug    e=*                        {$e}
users    m=details&u=*&tab=*&cat=*    users/{cot_url_username()}/tab/{$tab}/{$cat}{!$m}
users    m=details&u=*&tab=*           users/{cot_url_username()}/tab/{$tab}{!$m}
users    m=details&u=*                users/{cot_url_username()}{!$m}
users    group=customer&cat=*            customers/{$cat}{!$group}
users    group=contractor&cat=*            contractors/{$cat}{!$group}
users    group=customer            customers/{!$group}
users    group=contractor            contractors/{!$group}
# users    m=details&u=*            users/{cot_url_username()} 
# закоментировано и вместо неё использовать users    m=details&u=*                users/{cot_url_username()}{!$m}
login    *                        {$_area}
message    *                        {$_area}
admin    m=*                        admin/{$m}
admin    *                        {$_area}
rss        m=*&c=*                    {$_area}/{$m}/{$c}
rss        m=*&id=*                {$_area}/{$m}/{$id}
rss        c=*                        {$_area}/{$c}
rss        m=*                        {$_area}/{$m}
market    m=vendors                    market/vendors{!$m}
market    m=vendor&u=*&c=*            market/vendor/{$u}/{$c}{!$m}
market    m=vendor&u=*                market/vendor/{$u}{!$m}
market    m=vendor&uid=*&u=*          market/vendor-{$uid}-{$u}{!$m}
*        c=*&al=*                {$_area}/{cot_url_catpath()}/{$al}
*        c=*&id=*                {$_area}/{cot_url_catpath()}/{$id}
*        c=*                        {$_area}/{cot_url_catpath()}
*        al=*                    {$_area}/{$al}
*        id=*                    {$_area}/{$id}
*        *                        {$_area}

 

 .htaccess


################ Cotonti Handy URLs for Apache #######################

# Below are the rules to be included in your main .htaccess file or httpd.conf

# Rewrite engine options
Options -Indexes
RewriteEngine On
# Принудительное перенаправление на HTTPS и удаление www
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [R=301,L]

# Prevent to load sensible data
<FilesMatch "\.(dat|tpl|inc)$">
order deny,allow
deny from all
</FilesMatch>

# Server-relative path to Cotonti. Replace it with your path if you run Cotonti
# in a subfolder
RewriteBase "/"

RewriteRule ^sitemap-forums\.xml$ index.php?r=sitemap_forums [L]
RewriteRule ^sitemap-forums-index\.xml$ index.php?r=sitemap_forums&a=index [L]

RewriteRule ^sitemap-users\.xml$ index.php?r=sitemap_users [L]
RewriteRule ^sitemap-users-index\.xml$ index.php?r=sitemap_users&a=index [L]

# ==========================================================
# Sitemap Market – multilingual sitemap for the Market module (Cotonti)
# https://github.com/webitproff/sitemap-market-xml-i18n-cotonti
# ==========================================================
RewriteRule ^sitemap-market\.xml$ index.php?r=sitemap_market [QSA,L]
RewriteRule ^(en|ru|pl|ua)/sitemap-market\.xml$ index.php?r=sitemap_market&l=$1 [QSA,L]
RewriteRule ^sitemap-market-index\.xml$ index.php?r=sitemap_market&a=index [QSA,L]

RewriteRule ^sitemap-pages\.xml$ index.php?r=sitemap_pages [QSA,L]
RewriteRule ^(en|ru|pl|ua)/sitemap-pages\.xml$ index.php?r=sitemap_pages&l=$1 [QSA,L]
RewriteRule ^sitemap-pages-index\.xml$ index.php?r=sitemap_pages&a=index [QSA,L]



# Language selector
RewriteRule ^(en|ru|pl|ua)/(.*) $2?l=$1 [QSA,NC,NE,DPI]

# Sitemap shortcut
# RewriteRule ^sitemap\.xml$ index.php?r=sitemap [L]

# Admin area and message are special scripts
RewriteRule ^admin/([a-z0-9]+) admin.php?m=$1 [QSA,NC,NE,L]
RewriteRule ^(admin|login|message)(/|\?|$) $1.php [QSA,NC,NE,L]

# System category has priority over /system folder
RewriteRule ^system/?$  index.php?rwr=system [QSA,NC,NE,L]

# ========== Market PRO: витрины продавцов ==========

# Список всех продавцов
RewriteRule ^market/vendors/?$ index.php?e=market&m=vendors [L,QSA]

# Витрина конкретного продавца по имени
RewriteRule ^market/vendor/([^/]+)/?$ index.php?e=market&m=vendor&u=$1 [L,QSA]

# Витрина продавца с фильтром по категории
RewriteRule ^market/vendor/([^/]+)/([^/]+)/?$ index.php?e=market&m=vendor&u=$1&c=$2 [L,QSA]

# Комбинированный вариант: vendor-<id>-<username>
RewriteRule ^market/vendor-([0-9]+)-([^/]+)/?$ index.php?e=market&m=vendor&uid=$1&u=$2 [L,QSA]


# users
RewriteRule ^customers/?$ index.php?e=users&group=customer [QSA,NC,NE,L]
RewriteRule ^contractors/?$ index.php?e=users&group=contractor [QSA,NC,NE,L]
RewriteRule ^customers/([a-zA-Z0-9_./%-]+)/?$ index.php?e=users&group=customer&cat=$1 [QSA,NC,NE,L]
RewriteRule ^contractors/([a-zA-Z0-9_./%-]+)/?$ index.php?e=users&group=contractor&cat=$1 [QSA,NC,NE,L]
# users profile tabs
RewriteRule ^users/([^/]+)/tab/([^/]+)/([^/]+)/?$ index.php?e=users&m=details&u=$1&tab=$2&cat=$3 [QSA,NC,NE,L]
RewriteRule ^users/([^/]+)/tab/([^/]+)/?$ index.php?e=users&m=details&u=$1&tab=$2 [QSA,NC,NE,L]
# RewriteRule ^users/([^/]+)/?$ index.php?e=users&m=details&u=$1 [QSA,NC,NE,L]

# forums
RewriteRule ^forums/([a-zA-Z0-9_./%-]+)/topic([0-9]+)/page([0-9]+)?$ index.php?e=forums&m=posts&q=$2&d=$3 [QSA,NC,NE,L]
RewriteRule ^forums/([a-zA-Z0-9_./%-]+)/topic([0-9]+)?$ index.php?e=forums&m=posts&q=$2 [QSA,NC,NE,L]
RewriteRule ^forums/([a-zA-Z0-9_./%-]+)/post([0-9]+)?$ index.php?e=forums&m=posts&id=$2 [QSA,NC,NE,L]
RewriteRule ^forums/([a-zA-Z0-9_./%-]+)/([a-zA-Z0-9_%-]+)/page([0-9]+)?$ index.php?e=forums&m=topics&s=$2&d=$3 [QSA,NC,NE,L]
RewriteRule ^forums/([a-zA-Z0-9_./%-]+)/([a-zA-Z0-9_%-]+)/?$ index.php?e=forums&m=topics&s=$2 [QSA,NC,NE,L]
RewriteRule ^forums/([a-zA-Z0-9_%-]+)/?$ index.php?e=forums&m=topics&s=$1 [QSA,NC,NE,L]
# RewriteRule ^forums/([a-zA-Z0-9_%-]+)/?$ index.php?e=forums&c=$1 [QSA,NC,NE,L]
RewriteRule ^forums/?$ index.php?e=forums [QSA,NC,NE,L]

# All the rest goes through standard rewrite gateway
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^([^?]+) index.php?rwr=$1 [QSA,NC,NE,L]

 

 

 

webitproff
Телеграм для сообщений
@webitproff
webitproff • 13.09.2026 01:11 #2

частиный functions.custom.php

 

<?php
/**
 * Файл: system/functions.custom.php
 * 
 * Читать инструкцию https://github.com/webitproff/functions.custom.php-cotonti/blob/main/README.md
 * 
 * Пользовательские функции Cotonti, расширяющие стандартный функционал.
 *
 * Список функций:
 *
 * - cot_load_structure_custom()
 *   Загружает структуру категорий из базы данных с учетом иерархии,
 *   дополнительных полей и шаблонов.
 *
 * - forums_url_structure(&$args)
 *   Преобразует параметры URL форумов в человекопонятный вид на основе структуры.
 *
 * - cot_customfuncs_getUserDataOwner()
 *   Возвращает данные пользователя-владельца страницы.
 *
 * - cot_customfuncs_isOwnerSuperAdmin()
 *   Проверяет, является ли владелец страницы суперадминистратором.
 *
 * - cot_customfuncs_isOwnerAdmin()
 *   Проверяет, имеет ли владелец страницы права администратора
 *   (учитывает как основную, так и дополнительные группы).
 *
 * - cot_customfuncs_getOwnerGroupId()
 *   Возвращает ID основной группы владельца страницы.
 *
 * - cot_customfuncs_isOwner()
 *   Проверяет, является ли текущий пользователь владельцем страницы.
 *
 * - cot_customfuncs_isTopicAuthor()
 *   Проверяет, является ли текущий пользователь автором топика форума.
 *
 * - cot_customfuncs_isPageAuthor()
 *   Проверяет, является ли текущий пользователь автором статьи.
 *
 * - cot_customfuncs_getOwnerId()
 *   Возвращает ID пользователя-владельца страницы.
 *
 * - cot_customfuncs_getOwnerName()
 *   Возвращает экранированное имя пользователя-владельца страницы.
 *
 * - cot_customfuncs_getPageOwnerId()
 *   Возвращает ID владельца статьи (страницы) на основе текущего URL.
 *
 * - cot_langfile_custom($name, $type = 'plug', $default = 'en')
 *   Загружает пользовательский языковой файл для модуля или плагина.
 */
 
defined('COT_CODE') or die('Wrong URL');


// Определение глобальных переменных для работы с базой данных, конфигурацией и структурой
global $db, $db_structure, $cfg, $cot_extrafields, $L;
// Объявление глобальной переменной структуры
global $structure;

/**
 * Загружает структуру категорий из базы данных с учетом иерархии и дополнительных полей
 *
 * @return void
 */
function cot_load_structure_custom()
{
    // Доступ к глобальным переменным
    global $db, $db_structure, $cfg, $cot_extrafields, $structure;
    // Инициализация массива структуры
    $structure = [];
    // Инициализация массива подкатегорий
    $subcats = [];

    // Выбор SQL-запроса в зависимости от режима обновления
    if (defined('COT_UPGRADE')) {
        // Запрос для режима обновления, сортировка только по пути
        $sql = $db->query("SELECT * FROM $db_structure ORDER BY COALESCE(structure_path, '') ASC");
    } else {
        // Запрос для обычного режима, сортировка по области и пути
        $sql = $db->query("SELECT * FROM $db_structure ORDER BY structure_area ASC, COALESCE(structure_path, '') ASC");
    }

    // Инициализация массивов для путей, текстовых путей и шаблонов
    $path = [];
    $tpath = [];
    $tpls = [];

    // Обработка каждой записи из результата запроса
    foreach ($sql->fetchAll() as $row) {
        // Пропуск записей с пустым или нестроковым кодом или областью
        if (empty($row['structure_code']) || !is_string($row['structure_code']) || empty($row['structure_area']) || !is_string($row['structure_area'])) {
            continue;
        }

        // Присваивание кода категории
        $row['structure_code'] = $row['structure_code'];
        // Установка пути категории, если не указан — использование кода
        $row['structure_path'] = !empty($row['structure_path']) && is_string($row['structure_path']) ? $row['structure_path'] : $row['structure_code'];
        // Присваивание области категории
        $row['structure_area'] = $row['structure_area'];
        // Установка заголовка, если не указан — пустая строка
        $row['structure_title'] = !empty($row['structure_title']) && is_string($row['structure_title']) ? $row['structure_title'] : '';
        // Установка описания, если не указано — пустая строка
        $row['structure_desc'] = !empty($row['structure_desc']) && is_string($row['structure_desc']) ? $row['structure_desc'] : '';
        // Установка иконки, если не указана — пустая строка
        $row['structure_icon'] = !empty($row['structure_icon']) && is_string($row['structure_icon']) ? $row['structure_icon'] : '';
        // Приведение флага блокировки к целому числу
        $row['structure_locked'] = isset($row['structure_locked']) ? (int)$row['structure_locked'] : 0;
        // Приведение счетчика к целому числу
        $row['structure_count'] = isset($row['structure_count']) ? (int)$row['structure_count'] : 0;
        // Установка шаблона, если не указан — использование кода
        $row['structure_tpl'] = !empty($row['structure_tpl']) && is_string($row['structure_tpl']) ? $row['structure_tpl'] : $row['structure_code'];
        // Приведение идентификатора к целому числу
        $row['structure_id'] = isset($row['structure_id']) ? (int)$row['structure_id'] : 0;

        // Поиск последней точки в пути
        $last_dot = mb_strrpos($row['structure_path'], '.');

        // Обработка иерархического пути
        if ($last_dot !== false) {
            // Извлечение родительского пути
            $path1 = mb_substr($row['structure_path'], 0, $last_dot);
            // Формирование полного пути
            $path[$row['structure_path']] = !empty($path[$path1]) ? $path[$path1] . '.' . $row['structure_code'] : $row['structure_code'];
            // Определение разделителя для текстового пути
            $separator = (strip_tags($cfg['separator']) === $cfg['separator']) ? ' ' . $cfg['separator'] . ' ' : ' \ ';
            // Формирование текстового пути
            $tpath[$row['structure_path']] = !empty($tpath[$path1]) ? $tpath[$path1] . $separator . $row['structure_title'] : $row['structure_title'];
            // Определение родительской категории
            $parent_dot = mb_strrpos($path[$path1] ?? '', '.');
            $parent = ($parent_dot !== false) ? mb_substr($path[$path1], $parent_dot + 1) : ($path[$path1] ?? $row['structure_code']);
            // Добавление кода категории в массив подкатегорий
            $subcats[$row['structure_area']][$parent][] = $row['structure_code'];
        } else {
            // Установка пути для корневой категории
            $path[$row['structure_path']] = $row['structure_code'];
            // Установка текстового пути для корневой категории
            $tpath[$row['structure_path']] = $row['structure_title'];
            // Установка родительской категории
            $parent = $row['structure_code'];
        }

        // Обработка шаблона, если указано 'same_as_parent'
        if ($row['structure_tpl'] === 'same_as_parent') {
            // Использование шаблона родителя или кода категории
            $row['structure_tpl'] = $tpls[$parent] ?? $row['structure_code'];
        }

        // Сохранение шаблона для категории
        $tpls[$row['structure_code']] = $row['structure_tpl'];

        // Формирование структуры данных категории
        $structure[$row['structure_area']][$row['structure_code']] = [
            // Путь категории
            'path' => $path[$row['structure_path']],
            // Текстовый путь категории
            'tpath' => $tpath[$row['structure_path']],
            // Исходный путь категории
            'rpath' => $row['structure_path'],
            // Идентификатор категории
            'id' => $row['structure_id'],
            // Шаблон категории
            'tpl' => $row['structure_tpl'],
            // Заголовок категории
            'title' => $row['structure_title'],
            // Описание категории
            'desc' => $row['structure_desc'],
            // Иконка категории
            'icon' => $row['structure_icon'],
            // Флаг блокировки
            'locked' => $row['structure_locked'],
            // Счетчик элементов
            'count' => $row['structure_count'],
            // Подкатегории
            'subcats' => $subcats[$row['structure_area']][$row['structure_code']] ?? []
        ];

        // Обработка дополнительных полей, если они существуют
        if (!empty($cot_extrafields[$db_structure])) {
            // Перебор дополнительных полей
            foreach ($cot_extrafields[$db_structure] as $exfld) {
                // Формирование имени поля
                $fieldName = 'structure_' . $exfld['field_name'];
                // Добавление значения дополнительного поля в структуру
                $structure[$row['structure_area']][$row['structure_code']][$exfld['field_name']] = $row[$fieldName] ?? null;
            }
        }
    }

    // Финальная проверка и фильтрация структуры
    foreach ($structure as $area => &$area_structure) {
        // Проверка, что структура области является массивом
        if (!is_array($area_structure)) {
            // Инициализация пустого массива для невалидной области
            $area_structure = [];
            continue;
        }
        // Проверка каждой записи в области
        foreach ($area_structure as $i => &$x) {
            // Пропуск невалидных записей
            if (!is_array($x) || empty($x['path']) || !is_string($x['path'])) {
                unset($area_structure[$i]);
                continue;
            }
            // Установка подкатегорий
            $x['subcats'] = $subcats[$area][$i] ?? [];
            // Присваивание пути
            $x['path'] = $x['path'];
            // Установка текстового пути, если не указан — использование кода
            $x['tpath'] = !empty($x['tpath']) && is_string($x['tpath']) ? $x['tpath'] : $i;
            // Установка исходного пути, если не указан — использование кода
            $x['rpath'] = !empty($x['rpath']) && is_string($x['rpath']) ? $x['rpath'] : $i;
            // Установка заголовка, если не указан — пустая строка
            $x['title'] = !empty($x['title']) && is_string($x['title']) ? $x['title'] : '';
            // Установка описания, если не указано — пустая строка
            $x['desc'] = !empty($x['desc']) && is_string($x['desc']) ? $x['desc'] : '';
            // Установка иконки, если не указана — пустая строка
            $x['icon'] = !empty($x['icon']) && is_string($x['icon']) ? $x['icon'] : '';
            // Приведение счетчика к целому числу
            $x['count'] = isset($x['count']) ? (int)$x['count'] : 0;
            // Приведение флага блокировки к целому числу
            $x['locked'] = isset($x['locked']) ? (int)$x['locked'] : 0;
            // Установка шаблона, если не указан — использование кода
            $x['tpl'] = !empty($x['tpl']) && is_string($x['tpl']) ? $x['tpl'] : $i;
            // Приведение идентификатора к целому числу
            $x['id'] = isset($x['id']) ? (int)$x['id'] : 0;
        }
        // Освобождение ссылки на последнюю запись
        unset($x);
    }
    // Освобождение ссылки на последнюю область
    unset($area_structure);

    // Сохранение копии структуры перед выполнением плагинов
    $temp_structure = $structure;
    // Выполнение плагинов, подключенных к событию structure
    foreach (cot_getextplugins('structure') as $pl) {
        // Восстановление структуры перед выполнением плагина
        $structure = $temp_structure;
        // Подключение файла плагина
        include $pl;
        // Проверка структуры после выполнения плагина
        foreach ($structure as $area => &$area_structure) {
            // Проверка, что структура области является массивом
            if (!is_array($area_structure)) {
                // Инициализация пустого массива для невалидной области
                $area_structure = [];
                continue;
            }
            // Проверка каждой записи в области
            foreach ($area_structure as $i => &$x) {
                // Пропуск невалидных записей
                if (!is_array($x) || empty($x['path']) || !is_string($x['path'])) {
                    unset($area_structure[$i]);
                    continue;
                }
            }
            // Освобождение ссылки на последнюю запись
            unset($x);
        }
        // Освобождение ссылки на последнюю область
        unset($area_structure);
    }
    // Финальное восстановление структуры
    $structure = $temp_structure;
}

function forums_url_structure(&$args)
{
    global $cfg, $db, $structure, $db_forum_topics, $db_forum_posts;

    require_once cot_incfile('forums', 'module');

    $script = 'forums';
    $replacement = '';

    if (isset($args['m']) && $args['m'] === 'topics') {
        if (isset($args['s'])) {
            $d = isset($args['d']) ? (int) $args['d'] : 0;
            $replacement .= str_replace('.', '/', $structure['forums'][$args['s']]['path'] ?? '');

            if (isset($args['d'])) {
                $replacement .= '/page' . $d;
            }

            unset($args['d'], $args['s']);
        } else {
            $replacement .= $script;
        }
    } elseif (isset($args['m']) && $args['m'] === 'posts') {
        if (isset($args['q'])) {
            $q = (int) $args['q'];
            $d = isset($args['d']) ? (int) $args['d'] : 0;
            $s = $db->query("SELECT fp_cat FROM $db_forum_posts WHERE fp_topicid = $q")->fetchColumn();

            if ($s !== false) {
                $replacement .= str_replace('.', '/', $structure['forums'][$s]['path'] ?? '') . '/topic' . $q;
            } else {
                $replacement .= $script;
            }

            if (isset($args['d'])) {
                $replacement .= '/page' . $d;
            }

            unset($args['d'], $args['q'], $args['m']);
        } elseif (isset($args['id'])) {
            $id = (int) $args['id'];
            $s = $db->query("SELECT fp_cat FROM $db_forum_posts WHERE fp_id = $id")->fetchColumn();

            if ($s !== false) {
                $replacement .= str_replace('.', '/', $structure['forums'][$s]['path'] ?? '') . '/post' . $id;
            } else {
                $replacement .= $script;
            }

            unset($args['id'], $args['m']);
        } else {
            $replacement .= $script;
        }
    } else {
        $replacement .= $script;
    }

    return $replacement;
}
🗿

🧙‍♂️ Радуйся, странниче добрый и честный! Не понапрасну привела тя стезя в земли сии. Зде бо мужи мудры и искусники дела писменнаго и численнаго, что куют словеса и плетут узоры кода, тайны разгадывают и знанием делятся, летописи множа и ремесло цифровое творя.
⬅️ Аще налево пойдеши — обрящеши грамоты древния, писания старинныя и свитки учения. ⬆️ Аще прямо — слово мудрое и совет от мужей разумеющих, что в деле кодописном искусны, получиши. ➡️ Аще направо — сам в писцы и летописцы внидеши, и в ремесло цифровое, где строки и знаки в дело живое обращаются, слово свое в память веков вложиши.
📝 Не медли же — нареки имя свое, и вниди в чин наш, и стань с нами в братстве, где код есть магия, а строки — заклятия живыя, числом и буквою слово едины суть.
🏰 Не тайно есть собрание сие, и не инициации в нем, но многое сокрыто от пришлых и ступалого, понеже не всякому открывается знание, но токмо ищущим и пребывающим в деле сем.