Pages, Articles & News
Tools & Plugins
Example / Placeholder Title


Description as an example placeholder. Sample text content for further customization of the "Index36" template.

You are free to edit and customize the template however you like. If you don’t have time or enough knowledge — you can always order template adaptation by contacting me via GitHub or private messages on the digital goods marketplace.

Файл page.functions.php в Cotonti

содержит функции, которые используются для генерации списков страниц, фильтрации контента, работы с категориями, сортировки страниц, а также для выполнения кэширования запросов

Описание файла "page.functions.php" в Cotonti CMF

1. Основное назначение и место в системе Cotonti

Файл "page.functions.php" в системе Cotonti находится в директории /modules/page/inc и выполняет роль вспомогательного скрипта для работы с функционалом страниц (page module). Этот файл содержит функции, которые используются для генерации списков страниц, фильтрации контента, работы с категориями, сортировки страниц, а также для выполнения кэширования запросов. Он служит для создания динамических частей страниц, таких как списки, категории и элементы навигации, а также для реализации взаимодействия с базой данных.

Файл тесно интегрирован с другими модулями системы Cotonti, такими как пользовательская авторизация, кэширование, комментарии и другие плагины.

2. Взаимодействие внутри сайта

Внутри сайта этот файл используется для динамического вывода контента, связанного с страницами. Он формирует запросы к базе данных для получения данных о страницах, их категориях, а также выполняет отображение этих данных в формате HTML через шаблоны. Пример использования — это отображение списка страниц в административной части сайта или на публичной части сайта.

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

3. Переменные, хуки, методы, функции, классы

Переменные:

  • $categories — Строка или массив, который содержит коды категорий для фильтрации страниц. Влияет на то, какие страницы будут выбраны.
  • $count — Количество элементов, которые нужно отобразить. Если 0, то выводятся все страницы.
  • $template — Путь к шаблону, который используется для отображения данных.
  • $order — Параметр для сортировки страниц в SQL-запросе.
  • $condition — Дополнительные условия для выборки страниц.
  • $active_only — Параметр, ограничивающий выборку только активными страницами.
  • $use_subcat — Включает ли подкатегории в выборку.
  • $exclude_current — Исключает текущую страницу из выборки.
  • $blacklist — Список категорий, которые нужно исключить из выборки.
  • $pagination — Строка для настройки постраничной навигации.
  • $cache_ttl — Время жизни кэша для запроса в секундах.

Хуки:

  • cot_getextplugins('page.enum.query') — Хук для расширения запроса к базе данных.
  • cot_getextplugins('page.enum.loop') — Хук для расширения цикла перебора страниц.
  • cot_getextplugins('page.enum.tags') — Хук для расширения тегов, которые используются в шаблоне.

Методы и функции:

  • cot_structure_children() — Получает подкатегории для указанной категории.
  • cot_generate_pagetags() — Генерирует теги для страницы (мета-информация, URL и т. д.).
  • cot_generate_usertags() — Генерирует теги для пользователя, связанного с текущей страницей.
  • cot_comments_link() — Получает ссылку на комментарии для страницы, если плагин комментариев активен.
  • cot_comments_count() — Получает количество комментариев для страницы.
  • cot_pagenav() — Формирует строку для постраничной навигации.

Классы:

  • XTemplate — Класс, который используется для обработки шаблонов и вывода HTML-контента на основе данных, полученных в процессе выполнения функций.

4. Суть содержания кода и выполняемые задачи

Файл "page.functions.php" включает несколько ключевых задач:

  1. Фильтрация страниц по категориям: В зависимости от переданных параметров, код извлекает страницы из определенных категорий, включая или исключая подкатегории, фильтруя по состоянию активности и дате публикации.

  2. Работа с кэшированием: В случае, если включен кэш и задано время его жизни, файл кэширует результаты запросов, что позволяет ускорить выполнение запросов при повторных обращениях.

  3. Генерация динамического контента: Через шаблон XTemplate происходит генерация HTML-разметки для отображения страниц. Включает в себя перебор данных о страницах и вывод информации о них в соответствующих тегах (например, мета-информация, ссылки на страницы, комментарии).

  4. Постраничная навигация: Файл формирует постраничную навигацию для списков страниц, чтобы ограничить количество отображаемых элементов на одной странице.

  5. Работа с комментариями: Если плагин комментариев активен, код подключает данные о комментариях для каждой страницы и выводит ссылки на них, а также количество комментариев.

  6. Расширяемость через хуки: Код предоставляет возможность расширять его функциональность через хуки, которые могут добавлять дополнительные данные, фильтрации, теги и обработчики.

5. Как использовать этот сценарий владельцу сайта

Владелец сайта может использовать данный файл для:

  • Вывод списка страниц: Он может использовать функцию cot_page_enum() для генерации списка страниц на сайте. Например, для вывода всех страниц в определенной категории или для создания меню с динамическим содержимым.

  • Настройка вывода информации: Благодаря передаче параметров, таких как сортировка, фильтрация по категориям или по статусу, владелец может настроить, какие страницы и как будут отображаться на сайте.

  • Оптимизация с помощью кэширования: Используя кэш, владельцы сайтов могут ускорить выполнение страниц, уменьшая нагрузку на базу данных при повторных запросах.

  • Интеграция с комментариями: При активированном плагине комментариев владелец может легко интегрировать систему комментариев для каждой страницы, автоматически выводя количество комментариев и ссылки на них.

  • Постраничная навигация: Владелец сайта может настроить отображение большого количества страниц с помощью постраничной навигации, что улучшает UX при просмотре контента.

В целом, данный файл является мощным инструментом для управления содержимым сайта и позволяет владельцу гибко настраивать вывод страниц, используя систему фильтрации и сортировки.

 

<?php
/**
 * Page API
 *
 * @package Page
 * @copyright (c) Cotonti Team
 * @license https://github.com/Cotonti/Cotonti/blob/master/License.txt
 */

use cot\extensions\ExtensionsService;  // Подключение пространства имен для работы с расширениями

defined('COT_CODE') or die('Wrong URL.');  // Проверка на корректность URL-адреса для предотвращения прямого доступа к файлу

// Requirements
require_once cot_langfile('page', 'module');  // Подключение языкового файла модуля "page"
require_once cot_incfile('page', 'module', 'resources');  // Подключение ресурсов модуля "page"
require_once cot_incfile('forms');  // Подключение функционала работы с формами
require_once cot_incfile('extrafields');  // Подключение функционала для работы с дополнительными полями

/*
 * Page States
 * 0 - опубликована
 * 1 - ожидает утверждения администратором (модератором)
 * 2 - черновик
*/
const COT_PAGE_STATE_PUBLISHED = 0;  // Константа для состояния "опубликована"
const COT_PAGE_STATE_PENDING = 1;  // Константа для состояния "ожидает утверждения"
const COT_PAGE_STATE_DRAFT = 2;  // Константа для состояния "черновик"

// Tables and extras
Cot::$db->registerTable('pages');  // Регистрация таблицы "pages" в базе данных

cot_extrafields_register_table('pages');  // Регистрация дополнительный полей для таблицы "pages"

if (empty(Cot::$structure['page'])) {  // Проверка, если структура страницы еще не определена
    Cot::$structure['page'] = [];  // Инициализация пустого массива для структуры страницы
}

 

/**
 * Обрезает страницу после тега 'more' или после первой страницы (если мультистраничный контент)
 *
 * @param string $html Тело страницы
 * @return string
 */
function cot_cut_more($html)  // Функция для обрезки страницы до тега 'more' или до первого разрыва страницы в случае мультистраничного контента
{
	$mpos = mb_strpos($html, '<!--more-->');  // Поиск тега <!--more--> в контенте страницы
	if ($mpos === false)  // Если тег <!--more--> не найден
	{
		$mpos = mb_strpos($html, '[more]');  // Пытаемся найти альтернативный тег [more]
	}
	if ($mpos === false)  // Если тег [more] также не найден
	{
		$mpos = mb_strpos($html, '<hr class="more" />');  // Пытаемся найти разрыв страницы <hr class="more" />
	}
	if ($mpos !== false)  // Если хотя бы один из тегов найден
	{
		$html = mb_substr($html, 0, $mpos);  // Обрезаем контент страницы до найденного тега
	}
	$mpos = mb_strpos($html, 'newpage');  // Ищем тег newpage, который используется для создания новых страниц в мультистраничном контенте
	if ($mpos !== false)  // Если тег newpage найден
	{
		$html = mb_substr($html, 0, $mpos);  // Обрезаем контент до этого тега
	}
	if (mb_strpos($html, 'title'))  // Проверяем наличие тега title в контенте
	{
		$html = preg_replace('#\[title\](.*?)\[/title\][\s\r\n]*(<br />)?#i', '', $html);  // Удаляем все вхождения тега [title] с его содержимым
	}
	return $html;  // Возвращаем обрезанный HTML-контент
}
  • Эта функция выполняет обрезку контента страницы, учитывая различные теги, такие как <!--more-->, [more], <hr class="more" />, и newpage, чтобы оставить только часть страницы до этих тегов.
  • Также удаляется содержимое внутри тегов title, если они присутствуют в контенте.
  • Это полезно для разделения страницы на части или создания превью, где только первая часть контента отображается, а остальная скрыта или доступна по ссылке.

 

/**
 * Читает необработанные данные из файла
 *
 * @param string $file Путь к файлу
 * @return string
 */
function cot_readraw($file)  // Функция для чтения данных из файла
{
	return (mb_strpos($file, '..') === false && file_exists($file)) ? file_get_contents($file) : 'Файл не найден : '.$file;  // Если путь не содержит '..' и файл существует, читаем содержимое, иначе выводим сообщение о несуществующем файле
}

 

/**
 * Возвращает все теги страницы для coTemplate
 *
 * @param int|array $page_data Массив данных страницы или ID
 * @param string $tag_prefix Префикс для тегов
 * @param int $textLength Длина обрезаемого текста
 * @param bool $admin_rights Права администратора страницы
 * @param bool $pagepath_home Добавить ссылку на главную в путь страницы
 * @param string $emptytitle Текст заголовка страницы, если страница не существует
 * @param string $backUrl URL для действий с валидацией страницы
 *
 * @return array|null
 * @global CotDB $db
 */
function cot_generate_pagetags(  // Функция для генерации тегов страницы для coTemplate
    $page_data,  // Данные страницы или её ID
    $tag_prefix = '',  // Префикс для тегов
    $textLength = 0,  // Длина для обрезки текста
    $admin_rights = null,  // Права администратора страницы
    $pagepath_home = false,  // Добавление ссылки на главную в путь страницы
    $emptytitle = '',  // Текст заголовка страницы, если страница не существует
    $backUrl = null  // URL для действия с валидацией
) {
    // $L, $Ls, $R нужны для включения хуков
    global $L, $Ls, $R, $cfg;  // Объявление глобальных переменных для хуков

    global $db, $cot_extrafields, $db_pages, $usr, $sys, $cot_yesno, $structure, $db_structure;  // Объявление глобальных переменных для базы данных и других системных значений

    static $extp_first = null, $extp_main = null;  // Статические переменные для плагинов
    static $pag_auth = [];  // Статический массив для авторизации страницы

    if (is_null($extp_first)) {  // Если переменная $extp_first ещё не инициализирована
        $extp_first = cot_getextplugins('pagetags.first');  // Загружаем плагины для хуков на этапе 'first'
        $extp_main = cot_getextplugins('pagetags.main');  // Загружаем плагины для главного этапа
    }

    /* === Хук === */
    foreach ($extp_first as $pl) {  // Включаем плагины первого этапа
        include $pl;  // Подключаем файл плагина
    }
    /* ===== */

 

if (!empty($page_data) && !is_array($page_data)) {  // Если данные страницы не пусты и не являются массивом
    $pageID = (int) $page_data;  // Преобразуем $page_data в целое число, если оно не массив
    $page_data = null;  // Обнуляем переменную $page_data
    if ($pageID > 0) {  // Если ID страницы больше 0
        $sql = Cot::$db->query('SELECT * FROM ' . Cot::$db->pages . ' WHERE page_id = ? LIMIT 1', $pageID);  // Выполняем SQL запрос для получения данных страницы по её ID
        $page_data = $sql->fetch();  // Извлекаем результат запроса в переменную $page_data
    }
}

if (empty($page_data)) {  // Если данные страницы пустые
    return null;  // Возвращаем null, если страница не найдена
}

 

if ($page_data['page_id'] > 0 && !empty($page_data['page_title'])) {  // Если ID страницы больше 0 и есть название страницы
    if (is_null($admin_rights)) {  // Если права администратора не заданы
        if (!isset($pag_auth[$page_data['page_cat']])) {  // Если права доступа для категории страницы ещё не установлены
            $pag_auth[$page_data['page_cat']] = cot_auth('page', $page_data['page_cat'], 'RWA1');  // Получаем права доступа для указанной категории страницы
        }
        $admin_rights = (bool) $pag_auth[$page_data['page_cat']][2];  // Устанавливаем флаг прав администратора на основе полученных прав
    }
    $pagepath = cot_structure_buildpath('page', $page_data['page_cat']);  // Строим путь к странице на основе категории
    $catpath = cot_breadcrumbs($pagepath, $pagepath_home, false);  // Генерируем хлебные крошки для пути к категории
    $page_data['page_pageurl'] = cot_page_url($page_data);  // Получаем URL страницы
    $pageLink = [[$page_data['page_pageurl'], $page_data['page_title']]];  // Создаём массив с URL и заголовком страницы
    $breadcrumbs = cot_breadcrumbs(array_merge($pagepath, $pageLink), $pagepath_home);  // Генерируем хлебные крошки для страницы
    if (!empty($page_data['page_url']) && $page_data['page_file']) {  // Если у страницы есть URL и файл
        $dotpos = mb_strrpos($page_data['page_url'], ".") + 1;  // Находим позицию последней точки в URL
        $type = mb_strtolower(mb_substr($page_data['page_url'], $dotpos, 5));  // Получаем расширение файла
        $page_data['page_fileicon'] = cot_rc('page_icon_file_path', ['type' => $type]);  // Получаем путь к иконке файла на основе расширения
        if (!file_exists($page_data['page_fileicon'])) {  // Если иконка файла не существует
            $page_data['page_fileicon'] = cot_rc('page_icon_file_default');  // Используем иконку по умолчанию
        }
        $page_data['page_fileicon'] = cot_rc('page_icon_file', ['icon' => $page_data['page_fileicon']]);  // Генерируем иконку файла
    } else {
        $page_data['page_fileicon'] = '';  // Если у страницы нет файла, иконка пустая
    }

 

$date_format = 'datetime_medium';  // Устанавливаем формат даты в 'datetime_medium'

$text = cot_parse($page_data['page_text'], $cfg['page']['markup'], $page_data['page_parser']);  // Применяем разметку и парсер к тексту страницы
$text_cut = cot_cut_more($text);  // Обрезаем текст после тега 'more' или на первой странице (если многостраничный текст)
if ($textLength > 0 && mb_strlen($text_cut) > $textLength) {  // Если задана длина текста и текст больше этой длины
    $text_cut = cot_string_truncate($text_cut, $textLength);  // Обрезаем текст до указанной длины
}
$cutted = mb_strlen($text) > mb_strlen($text_cut);  // Проверяем, был ли текст обрезан

$cat_url = cot_url('page', ['c' => $page_data['page_cat']]);  // Формируем URL для категории страницы

$urlParams = [  // Формируем параметры для URL
    'm' => 'page',  // Указываем модуль страницы
    'a' => 'validate',  // Указываем действие для валидации
    'id' => $page_data['page_id'],  // Указываем ID страницы
    'x' => Cot::$sys['xk'],  // Добавляем токен безопасности
];
if (!empty($backUrl)) {  // Если задан URL возврата
    $urlParams['back'] = base64_encode($backUrl);  // Добавляем параметр для возврата
}
$validate_url = cot_url('admin', $urlParams);  // Формируем URL для действия валидации

$urlParams['a'] = 'unvalidate';  // Меняем действие на 'unvalidate' для отмены валидации
$unvalidate_url = cot_url('admin', $urlParams);  // Формируем URL для отмены валидации

$edit_url = cot_url('page', "m=edit&id={$page_data['page_id']}");  // Формируем URL для редактирования страницы
$delete_url = cot_url('page', "m=edit&a=update&delete=1&id={$page_data['page_id']}&x={$sys['xk']}");  // Формируем URL для удаления страницы

$page_data['page_status'] = cot_page_status(  // Получаем статус страницы (опубликована, на модерации, черновик)
    $page_data['page_state'],  // Состояние страницы
    $page_data['page_begin'],  // Дата начала публикации
    $page_data['page_expire']  // Дата окончания публикации
);

 

 

$haveFile = Cot::$L['No'];  // Инициализируем переменную $haveFile значением "No" (по умолчанию файл отсутствует)
$page_data['page_file'] = (int) $page_data['page_file'];  // Преобразуем значение 'page_file' в целое число
if ($page_data['page_file'] == 1) {  // Если 'page_file' равно 1
    $haveFile = Cot::$L['Yes'];  // Устанавливаем $haveFile в "Yes" (файл есть)
} elseif ($page_data['page_file'] == 2) {  // Если 'page_file' равно 2
    $haveFile = Cot::$L['Members_download'];  // Устанавливаем $haveFile в "Members_download" (доступно для скачивания только для пользователей)
}

$catTitle = isset($structure['page'][$page_data['page_cat']]['title'])  // Проверяем, существует ли заголовок категории страницы
    ? htmlspecialchars($structure['page'][$page_data['page_cat']]['title'])  // Если существует, получаем и экранируем заголовок
    : '';  // Если не существует, оставляем пустое значение
$catDescription = isset($structure['page'][$page_data['page_cat']]['desc'])  // Проверяем, существует ли описание категории страницы
    ? $structure['page'][$page_data['page_cat']]['desc']  // Если существует, получаем описание
    : '';  // Если не существует, оставляем пустое значение
$pageDescription = (isset($page_data['page_desc']) && $page_data['page_desc'] !== '')  // Проверяем, существует ли описание страницы и оно не пустое
    ? htmlspecialchars($page_data['page_desc'])  // Если существует, экранируем описание страницы
    : '';  // Если не существует, оставляем пустое значение

 

$temp_array = [  // Создаем массив с данными страницы
    'URL' => $page_data['page_pageurl'],  // Ссылка на страницу
    'ID' => $page_data['page_id'],  // Идентификатор страницы
    'TITLE' => htmlspecialchars($page_data['page_title'], ENT_COMPAT, 'UTF-8', false),  // Заголовок страницы с экранированием HTML
    'BREADCRUMBS' => $breadcrumbs,  // Хлебные крошки для страницы
    'ALIAS' => $page_data['page_alias'],  // Псевдоним страницы
    'STATE' => $page_data['page_state'],  // Состояние страницы
    'STATUS' => $page_data['page_status'],  // Статус страницы
    'LOCAL_STATUS' => $L['page_status_' . $page_data['page_status']],  // Локализованный статус страницы
    'CAT' => $page_data['page_cat'],  // Категория страницы
    'CAT_URL' => $cat_url,  // Ссылка на категорию страницы
    'CAT_TITLE' => $catTitle,  // Название категории страницы
    'CAT_PATH' => $catpath,  // Путь к категории
    'CAT_PATH_SHORT' => cot_rc_link($cat_url, $catTitle),  // Краткая версия пути с ссылкой
    'CAT_DESCRIPTION' => $catDescription,  // Описание категории
    'CAT_ICON' => !empty($structure['page'][$page_data['page_cat']]['icon'])  // Проверка на наличие иконки категории
        ? cot_rc(
            'img_structure_cat',
            [
                'icon' => $structure['page'][$page_data['page_cat']]['icon'],  // Иконка категории
                'title' => $catTitle,  // Заголовок категории
                'desc' => htmlspecialchars($catDescription),  // Описание категории с экранированием
            ]
        )
        : '',  // Если иконка не указана, пустое значение
    'CAT_ICON_SRC' => isset($structure['page'][$page_data['page_cat']]['icon'])  // Проверка на наличие источника иконки
        ? $structure['page'][$page_data['page_cat']]['icon']  // Если есть, возвращаем иконку
        : '',  // Если нет, пустое значение
    'KEYWORDS' => (isset($page_data['page_keywords']) && $page_data['page_keywords'] != '')  // Проверка на наличие ключевых слов
        ? htmlspecialchars($page_data['page_keywords'])  // Если есть, экранируем ключевые слова
        : '',  // Если нет, пустое значение
    'DESCRIPTION' => $pageDescription,  // Описание страницы
    'TEXT' => $text,  // Текст страницы
    'TEXT_CUT' => $text_cut,  // Обрезанный текст
    'TEXT_IS_CUT' => $cutted,  // Признак, что текст был обрезан
    'DESCRIPTION_OR_TEXT' => $pageDescription !== '' ? $pageDescription : $text,  // Логика выбора между описанием и текстом
    'DESCRIPTION_OR_TEXT_CUT' => $pageDescription !== '' ? $pageDescription : $text_cut,  // Логика выбора между описанием и обрезанным текстом
    'MORE' => ($cutted) ? cot_rc('list_more', ['page_url' => $page_data['page_pageurl']]) : '',  // Кнопка "Еще" для обрезанных текстов
    'AUTHOR' => (isset($page_data['page_author']) && $page_data['page_author'] != '')  // Проверка на наличие автора страницы
        ? htmlspecialchars($page_data['page_author'])  // Если автор есть, экранируем
        : '',  // Если автора нет, пустое значение
    'OWNER_ID' => $page_data['page_ownerid'],  // Идентификатор владельца страницы
    'OWNER_NAME' => (isset($page_data['user_name']) && $page_data['user_name'] != '')  // Проверка на имя владельца страницы
        ? htmlspecialchars($page_data['user_name'])  // Если имя пользователя есть, экранируем
        : '',  // Если нет, пустое значение
    'CREATED' => cot_date($date_format, $page_data['page_date']),  // Дата создания страницы
    'BEGIN' => cot_date($date_format, $page_data['page_begin']),  // Дата начала действия страницы
    'EXPIRE' => cot_date($date_format, $page_data['page_expire']),  // Дата истечения срока действия страницы
    'UPDATED' => cot_date($date_format, $page_data['page_updated']),  // Дата последнего обновления страницы
    'CREATED_STAMP' => $page_data['page_date'],  // Метка времени для даты создания
    'BEGIN_STAMP' => $page_data['page_begin'],  // Метка времени для начала действия
    'EXPIRE_STAMP' => $page_data['page_expire'],  // Метка времени для истечения срока действия
    'UPDATED_STAMP' => $page_data['page_updated'],  // Метка времени для обновления страницы
    'FILE' => $haveFile,  // Статус наличия файла
    'FILE_URL' => !empty($page_data['page_url'])  // Проверка на наличие URL файла
        ? cot_url('page', ['c' => $page_data['page_cat'], 'id' => $page_data['page_id'], 'a' => 'dl'])  // Ссылка на файл для скачивания
        : '',  // Если нет файла, пустое значение
    'FILE_SIZE' => $page_data['page_size'] / 1024,  // Размер файла в КБ (устаревшая версия для совместимости)
    'FILE_SIZE_BYTES' => $page_data['page_size'],  // Размер файла в байтах
    'FILE_SIZE_READABLE' => cot_build_filesize($page_data['page_size'], 1),  // Читаемый размер файла
    'FILE_ICON' => $page_data['page_fileicon'],  // Иконка файла
    'FILE_DOWNLOADS' => $page_data['page_filecount'],  // Количество скачиваний файла
    'FILE_DOWNLOADS_TIMES' => cot_declension($page_data['page_filecount'], $Ls['Times']),  // Скачивания с учетом склонений
    'FILE_NAME' => !empty($page_data['page_url']) ? basename($page_data['page_url']) : '',  // Имя файла
    'HITS' => $page_data['page_count'],  // Количество просмотров страницы
    'ADMIN' => $admin_rights  // Права администратора
        ? cot_rc('list_row_admin', ['unvalidate_url' => $unvalidate_url, 'edit_url' => $edit_url])  // Выводим ссылки на редактирование и отмену валидации
        : '',  // Если нет прав администратора, пустое значение
    'NOT_AVAILABLE' => ($page_data['page_begin'] > Cot::$sys['now'])  // Проверка на доступность страницы
        ? Cot::$L['page_notavailable'] . cot_build_timegap(Cot::$sys['now'], $page_data['page_begin'])  // Сообщение о недоступности с таймером
        : '',  // Если страница доступна, пустое значение
];

 

if (isset(Cot::$cfg['legacyMode']) && Cot::$cfg['legacyMode']) { // Проверка, включен ли режим устаревания в конфигурации.
    // @deprecated in 0.9.24
    $temp_array += [ // Объединение дополнительных данных в массив $temp_array для режима устаревания
        'SHORTTITLE' => htmlspecialchars($page_data['page_title'], ENT_COMPAT, 'UTF-8', false), // Краткое название страницы
        'LOCALSTATUS' => $L['page_status_' . $page_data['page_status']], // Локализованный статус страницы (из языкового файла)
        'CATURL' => $cat_url, // URL категории
        'CATTITLE' => $catTitle, // Название категории
        'CATPATH' => $catpath, // Путь категории
        'CATPATH_SHORT' => cot_rc_link($cat_url, $catTitle), // Краткая ссылка на путь категории
        'CATDESC' => (isset($structure['page'][$page_data['page_cat']]['desc']) 
            && $structure['page'][$page_data['page_cat']]['desc'] != '') ? 
            htmlspecialchars($structure['page'][$page_data['page_cat']]['desc']) : '', // Описание категории, если оно есть
        'CATICON' => isset($structure['page'][$page_data['page_cat']]['icon']) ? 
            $structure['page'][$page_data['page_cat']]['icon'] : '', // Иконка категории, если она есть
        'OWNERID' => $page_data['page_ownerid'], // ID владельца страницы
        'OWNERNAME' => (isset($page_data['user_name']) && $page_data['user_name'] != '') ? 
            htmlspecialchars($page_data['user_name']) : '', // Имя владельца, если оно есть
        'DESC' => (isset($page_data['page_desc']) && $page_data['page_desc'] != '') ? 
            htmlspecialchars($page_data['page_desc']) : '', // Описание страницы, если оно есть
        'DESC_OR_TEXT' => (isset($page_data['page_desc']) && $page_data['page_desc'] != '') ? 
            htmlspecialchars($page_data['page_desc']) : $text, // Если описание доступно, используется оно, иначе используется текст
        'DESC_OR_TEXT_CUT' => (isset($page_data['page_desc']) && $page_data['page_desc'] != '') ? 
            htmlspecialchars($page_data['page_desc']) : $text_cut, // То же, что и DESC_OR_TEXT, но с урезанной версией
        'DATE' => cot_date($date_format, $page_data['page_date']), // Дата создания страницы
        'DATE_STAMP' => $page_data['page_date'], // Временная метка даты создания страницы
        'FILE_COUNT' => $page_data['page_filecount'], // Количество файлов, прикрепленных к странице
        'FILE_COUNTTIMES' => cot_declension($page_data['page_filecount'], $Ls['Times']), // Описание количества файлов во множественном числе
        'COUNT' => $page_data['page_count'], // Количество просмотров страницы
        'NOTAVAILABLE' => ($page_data['page_begin'] > Cot::$sys['now']) // Если страница еще не доступна
            ? Cot::$L['page_notavailable'] . cot_build_timegap(Cot::$sys['now'], $page_data['page_begin']) // Показывает временной промежуток до доступности
            : '', // В противном случае, пустая строка
    ];
}

 

// Admin tags
if ($admin_rights) { // Если у пользователя есть права администратора
    $validate_confirm_url = cot_confirm_url($validate_url, 'page', 'page_confirm_validate'); // Генерация URL для подтверждения валидации страницы
    $unvalidate_confirm_url = cot_confirm_url($unvalidate_url, 'page', 'page_confirm_unvalidate'); // Генерация URL для подтверждения отмены валидации страницы
    $delete_confirm_url = cot_confirm_url($delete_url, 'page', 'page_confirm_delete'); // Генерация URL для подтверждения удаления страницы
    $temp_array['ADMIN_EDIT'] = cot_rc_link($edit_url, Cot::$L['Edit']); // Ссылка на редактирование страницы
    $temp_array['ADMIN_EDIT_URL'] = $edit_url; // URL для редактирования страницы
    $temp_array['ADMIN_UNVALIDATE'] = $page_data['page_state'] == COT_PAGE_STATE_PENDING ? // Если страница в ожидании, ссылка для подтверждения валидации
        cot_rc_link($validate_confirm_url, Cot::$L['Validate'], 'class="confirmLink"') : 
        cot_rc_link($unvalidate_confirm_url, Cot::$L['Putinvalidationqueue'], 'class="confirmLink"'); // Ссылка для отмены валидации или постановки в очередь на валидацию
    $temp_array['ADMIN_UNVALIDATE_URL'] = $page_data['page_state'] == 1 ? // Если страница активна, URL для подтверждения валидации
        $validate_confirm_url : $unvalidate_confirm_url; // URL для подтверждения отмены валидации
    $temp_array['ADMIN_DELETE'] = cot_rc_link($delete_confirm_url, $L['Delete'], 'class="confirmLink"'); // Ссылка для удаления страницы
    $temp_array['ADMIN_DELETE_URL'] = $delete_confirm_url; // URL для удаления страницы
} elseif ($usr['id'] == $page_data['page_ownerid']) { // Если пользователь является владельцем страницы
    $temp_array['ADMIN_EDIT'] = cot_rc_link($edit_url, $L['Edit']); // Ссылка на редактирование страницы для владельца
    $temp_array['ADMIN_EDIT_URL'] = $edit_url; // URL для редактирования страницы
}

if (cot_auth('page', 'any', 'W')) { // Если пользователь имеет права на запись (W) для страниц
    $clone_url = cot_url('page', "m=add&c={$page_data['page_cat']}&clone={$page_data['page_id']}"); // Генерация URL для клонирования страницы
    $temp_array['ADMIN_CLONE'] = cot_rc_link($clone_url, $L['page_clone']); // Ссылка для клонирования страницы
    $temp_array['ADMIN_CLONE_URL'] = $clone_url; // URL для клонирования страницы
}

 

// Extrafields
if (!empty(Cot::$extrafields[Cot::$db->pages])) { // Если есть дополнительные поля для страниц
    foreach (Cot::$extrafields[Cot::$db->pages] as $exfld) { // Проходим по всем дополнительным полям
        $tag = mb_strtoupper($exfld['field_name']); // Преобразуем имя поля в верхний регистр
        $exfld_title = cot_extrafield_title($exfld, 'page_'); // Получаем название поля

        $temp_array[$tag . '_TITLE'] = $exfld_title; // Сохраняем название поля
        $temp_value = null; // Инициализация переменной для хранения значения поля
        if (isset($page_data['page_'.$exfld['field_name']])) { // Если значение поля существует
            $temp_value = $page_data['page_'.$exfld['field_name']]; // Присваиваем его переменной
        }
        $temp_array[$tag] = cot_build_extrafields_data('page', $exfld, $temp_value, $page_data['page_parser']); // Строим данные для поля
        $temp_array[$tag . '_VALUE'] = $temp_value; // Сохраняем значение поля
    }
}

// Extra fields for structure
if (isset(Cot::$extrafields[Cot::$db->structure])) { // Если есть дополнительные поля для структуры
    foreach (Cot::$extrafields[Cot::$db->structure] as $exfld) { // Проходим по всем дополнительным полям структуры
        $tag = mb_strtoupper($exfld['field_name']); // Преобразуем имя поля в верхний регистр
        $exfld_title = cot_extrafield_title($exfld, 'structure_'); // Получаем название поля

        $temp_array['CAT_' . $tag . '_TITLE'] = $exfld_title; // Сохраняем название поля
        $temp_value = null; // Инициализация переменной для хранения значения поля
        if (isset(Cot::$structure['page'][$page_data['page_cat']][$exfld['field_name']])) { // Если значение поля существует
            $temp_value = Cot::$structure['page'][$page_data['page_cat']][$exfld['field_name']]; // Присваиваем его переменной
        }
        $temp_array['CAT_' . $tag] = cot_build_extrafields_data('structure', $exfld, $temp_value); // Строим данные для поля структуры
        $temp_array['CAT_' . $tag.'_VALUE'] = $temp_value; // Сохраняем значение поля структуры
    }
}

/* === Hook === */
foreach ($extp_main as $pl) { // Выполняем все хуки
    include $pl; // Подключаем каждый плагин
}
/* ===== */

Здесь добавляются дополнительные поля для страниц и структуры. Если для страниц или структуры есть дополнительные поля, они обрабатываются, и значения полей сохраняются в массив $temp_array. Также для каждого поля генерируется соответствующий тег и сохраняются значения, если они существуют. В конце выполняются хуки, подключая соответствующие плагины для обработки

 

} else {
    $temp_array = [ // Если страница не найдена, создаем массив с данными для ответа
        'TITLE' => (!empty($emptytitle)) ? $emptytitle : Cot::$L['Deleted'], // Заголовок страницы или текст "Удалено"
    ];
    if (isset(Cot::$cfg['legacyMode']) && Cot::$cfg['legacyMode']) { // Если включен режим совместимости
        // @deprecated in 0.9.24
        $temp_array += [ // Добавляем в массив дополнительные данные
            'SHORTTITLE' => (!empty($emptytitle)) ? $emptytitle : Cot::$L['Deleted'], // Короткий заголовок страницы или текст "Удалено"
        ];
    }
}

$return_array = []; // Инициализируем массив для возвращаемых данных
foreach ($temp_array as $key => $val) { // Проходим по всем элементам массива $temp_array
    $return_array[$tag_prefix . $key] = $val; // Добавляем префикс к ключам и сохраняем в $return_array
}

return $return_array; // Возвращаем массив с результатами

 

/**
 * Возможные значения для порядка сортировки категорий
 * @param bool $adminpart Вызов из административной части
 * @return array
 */
function cot_page_config_order($adminpart = false)
{
	global $cot_extrafields, $L, $db_pages;

	$options_sort = array( // Массив с возможными параметрами сортировки
		'id' => $L['Id'], // ID
		'title' => $L['Title'], // Заголовок
		'desc' => $L['Description'], // Описание
		'text' => $L['Body'], // Тело
		'author' => $L['Author'], // Автор
		'ownerid' => $L['Owner'], // Владелец
		'date' => $L['Date'], // Дата
		'begin' => $L['Begin'], // Начало
		'expire' => $L['Expire'], // Истечение
		'file' => $L['adm_fileyesno'], // Файл (да/нет)
		'url' => $L['adm_fileurl'], // URL файла
		'size' => $L['adm_filesize'], // Размер файла
		'filecount' => $L['adm_filecount'], // Количество файлов
		'count' => $L['Count'], // Количество просмотров
		'updated' => $L['Updated'], // Обновлено
		'cat' => $L['Category'] // Категория
	);

	// Добавление экстраполяции полей
	foreach($cot_extrafields[$db_pages] as $exfld)
	{
		$options_sort[$exfld['field_name']] = isset($L['page_'.$exfld['field_name'].'_title']) 
			? $L['page_'.$exfld['field_name'].'_title'] 
			: $exfld['field_description']; // Добавляем поле экстрафайла, если оно существует
	}

	// Возвращаем массив в зависимости от контекста (админская часть или обычная версия)
	if ($adminpart || version_compare('0.9.19', Cot::$cfg['version']) < 1)
	{
		return $options_sort; // Возвращаем весь массив для административной части
	}
	else
	{
		// Старый стиль, будет удален в следующих версиях
		$L['cfg_order_params'] = array_values($options_sort); // Обновляем локализацию
		return array_keys($options_sort); // Возвращаем только ключи массива для старой версии
	}
}

В этой функции создается массив с возможными значениями для сортировки категорий страниц в Cotonti. В зависимости от контекста (админская часть или версия Cotonti) возвращается либо полный массив с параметрами, либо только его ключи, если версия старее 0.9.19.

/**
 * Определяет статус страницы
 *
 * @param int $page_state Статус страницы (0 - опубликована, 2 - черновик, 1 - ожидает подтверждения)
 * @param int $page_begin Время начала действия страницы
 * @param int $page_expire Время истечения действия страницы
 * @return string 'draft', 'pending', 'approved', 'published' или 'expired'
 */
function cot_page_status($page_state, $page_begin, $page_expire)
{
	global $sys;

	if ($page_state == 0) // Если статус страницы - опубликована
	{
		if ($page_expire > 0 && $page_expire <= $sys['now']) // Если страница устарела
		{
			return 'expired'; // Страница истекла
		}
		elseif ($page_begin > $sys['now']) // Если дата начала действия страницы в будущем
		{
			return 'approved'; // Страница одобрена, но еще не опубликована
		}
		return 'published'; // Страница опубликована
	}
	elseif ($page_state == 2) // Если статус страницы - черновик
	{
		return 'draft'; // Черновик
	}
	return 'pending'; // Страница ожидает подтверждения
}

Эта функция определяет статус страницы в зависимости от ее состояния, времени начала и времени истечения действия. Она возвращает один из следующих статусов: draft (черновик), pending (ожидает подтверждения), approved (одобрена), published (опубликована) или expired (истекла).

 

/**
 * Возвращает количество страниц в категории
 * Используется в Админ/Структура/Пересинхронизация всех
 *
 * @param string $category Код категории
 * @return int Количество страниц в категории
 */
function cot_page_sync($category)
{
    if (empty($category)) { // Если категория пуста
        return 0; // Возвращаем 0, так как категории нет
    }

    // Выполняем запрос для подсчета количества страниц в данной категории
    return (int) Cot::$db->query(
        'SELECT COUNT(*) FROM ' . Cot::$db->quoteTableName(Cot::$db->pages) . // Выполняем запрос к таблице страниц
        ' WHERE page_cat=?', // Фильтруем по категории
        $category // Передаем параметр категории
    )->fetchColumn(); // Получаем количество страниц и возвращаем
}

Эта функция выполняет SQL-запрос, чтобы получить количество страниц в указанной категории. Если категория пуста, функция возвращает 0

 

/**
 * Пересчитывает и обновляет счетчики для структуры
 * @param string $category Код категории
 * @return void
 */
function cot_page_updateStructureCounters($category)
{
    // Проверяем, если категория пуста или структура страницы для этой категории не существует
    if (empty($category) || empty(Cot::$structure['page'][$category])) { 
        return; // Прерываем выполнение функции, если условие выполнено
    }

    // Получаем количество страниц в указанной категории
    $count = cot_page_sync($category);

    // Обновляем поле structure_count в таблице structure для данной категории
    Cot::$db->query('UPDATE ' . Cot::$db->quoteTableName(Cot::$db->structure) .
        ' SET structure_count = ' . $count . // Устанавливаем новое значение счетчика
        " WHERE structure_area='page' AND structure_code = :category", ['category' => $category]); // Указываем категорию для обновления

    // Проверяем, используется ли кеширование
    if (Cot::$cache) {
        // Если используется кеш, удаляем старый кеш для структуры
        Cot::$cache->db->remove('structure', 'system');
    }
}

 

/**
 * Обновляет код категории страницы
 *
 * @param string $oldcat Старый код категории
 * @param string $newcat Новый код категории
 * @return bool Результат операции (успешно или нет)
 * @global CotDB $db Доступ к базе данных
 */
function cot_page_updatecat($oldcat, $newcat)
{
    // Получаем глобальный доступ к объекту базы данных
    global $db, $db_structure, $db_pages;

    // Выполняем обновление страницы в таблице страниц, изменяя категорию на новую
    return (bool) $db->update(
        $db_pages, // Таблица, в которой будет происходить обновление
        array("page_cat" => $newcat), // Устанавливаем новый код категории
        "page_cat='".$db->prep($oldcat)."'" // Условие для обновления: старая категория
    );
}

 

/**
 * URL-адрес страницы
 *
 * @param array $data Данные страницы в виде массива
 * @param array $params Дополнительные параметры URL
 * @param string $tail Постфикс URL, например, якорь
 * @param bool $htmlspecialcharsBypass Если TRUE, символы типа & не будут преобразовываться в &amp; и так далее
 * @param bool $ignoreAppendix Если TRUE, $cot_url_appendix будет проигнорирован для этого URL
 * @return string Валидный HTTP URL
 */
function cot_page_url($data, $params = [], $tail = '', $htmlspecialcharsBypass = false, $ignoreAppendix = false)
{
    // Создаем базовые параметры URL с категорией страницы
    $urlParams = ['c' => $data['page_cat']];

    // Если у страницы есть alias (псевдоним), добавляем его в параметры URL
    if (!empty($data['page_alias'])) {
        $urlParams['al'] = $data['page_alias'];
    }
    // Если псевдонима нет, но есть ID страницы, добавляем ID в параметры URL
    elseif (!empty($data['page_id'])) {
        $id = (int) $data['page_id']; // Преобразуем ID в целое число
        if ($id <= 0) { // Если ID некорректен (меньше или равно 0), возвращаем пустую строку
            return '';
        }
        $urlParams['id'] = $id;
    } else { // Если у страницы нет ни псевдонима, ни ID, возвращаем пустую строку
        return '';
    }

    // Если переданы дополнительные параметры, объединяем их с основными
    if (!empty($params)) {
        $urlParams = array_merge($urlParams, $params);
    }

    // Генерируем финальный URL, вызывая функцию cot_url с собранными параметрами
    return cot_url('page', $urlParams, $tail, $htmlspecialcharsBypass, $ignoreAppendix);
}

 

/**
 * Возвращает разрешения для категории страницы.
 * @param  string $cat Код категории
 * @return array       Массив разрешений с ключами: 'auth_read', 'auth_write', 'isadmin', 'auth_download'
 */
function cot_page_auth($cat = null)
{
    // Если категория не передана, по умолчанию устанавливаем значение 'any'
	if (empty($cat))
	{
		$cat = 'any';
	}

    // Инициализируем массив для разрешений
	$auth = array();

    // Получаем разрешения для категории страницы, используя функцию cot_auth
    // 'RWA1' указывает на типы разрешений: чтение, запись, администрирование и скачивание
	list($auth['auth_read'], $auth['auth_write'], $auth['isadmin'], $auth['auth_download']) = cot_auth('page', $cat, 'RWA1');
    
    // Возвращаем массив разрешений
	return $auth;
}

 

/**
 * Импортирует данные страницы из параметров запроса.
 * @param string $source Источник запроса для параметров
 * @param array $rpage  Данные существующей страницы из базы данных
 * @param array $auth   Массив разрешений
 * @return array Данные страницы
 */
function cot_page_import($source = 'POST', $rpage = [], $auth = [])
{
	global $cfg, $db_pages, $cot_extrafields, $usr, $sys;

    // Если массив разрешений пуст, получаем разрешения для категории страницы
	if (count($auth) == 0) {
		$auth = cot_page_auth($rpage['page_cat']);
	}

    // Если источник данных - 'D' или 'DIRECT', используем 'PATCH' и устанавливаем глобальную переменную $_PATCH
	if ($source == 'D' || $source == 'DIRECT') {
		// Хитрость, чтобы не затрагивать каждую строку ниже
		global $_PATCH;
		$_PATCH = $rpage;
		$source = 'PATCH';
	}

    // Импортируем данные страницы из параметров запроса
	$rpage['page_cat']      = cot_import('rpagecat', $source, 'TXT');  // Код категории
	$rpage['page_keywords'] = cot_import('rpagekeywords', $source, 'TXT');  // Ключевые слова
	$rpage['page_alias']    = cot_import('rpagealias', $source, 'TXT');  // Псевдоним
	$rpage['page_title']    = cot_import('rpagetitle', $source, 'TXT');  // Заголовок
	$rpage['page_desc']     = cot_import('rpagedesc', $source, 'TXT');  // Описание
	$rpage['page_text']     = cot_import('rpagetext', $source, 'HTM');  // Текст
	$rpage['page_parser']   = cot_import('rpageparser', $source, 'ALP');  // Парсер
	$rpage['page_author']   = cot_import('rpageauthor', $source, 'TXT');  // Автор
	$rpage['page_file']     = intval(cot_import('rpagefile', $source, 'INT'));  // Файл (если есть)
	$rpage['page_url']      = cot_import('rpageurl', $source, 'TXT');  // URL
	$rpage['page_size']     = (int) cot_import('rpagesize', $source, 'INT');  // Размер
	$rpage['page_file']     = ($rpage['page_file'] == 0 && !empty($rpage['page_url'])) ? 1 : $rpage['page_file'];  // Если файла нет, но есть URL, ставим значение 1

    // Определяем текущую дату страницы
	$rpagedatenow           = cot_import('rpagedatenow', $source, 'BOL');  // Признак "текущая дата"
	$rpage['page_date']     = cot_import_date('rpagedate', true, false, $source);  // Дата
	$rpage['page_date']     = ($rpagedatenow || is_null($rpage['page_date'])) ? $sys['now'] : (int) $rpage['page_date'];  // Если дата не указана или установлена текущая, используем системную
	$rpage['page_begin']    = (int) cot_import_date('rpagebegin');  // Дата начала
	$rpage['page_expire']   = (int) cot_import_date('rpageexpire');  // Дата окончания
	$rpage['page_expire']   = ($rpage['page_expire'] <= $rpage['page_begin']) ? 0 : $rpage['page_expire'];  // Если дата окончания раньше начала, ставим 0
	$rpage['page_updated']  = $sys['now'];  // Дата обновления

    // Импортируем дополнительные метаданные
	$rpage['page_keywords'] = cot_import('rpagekeywords', $source, 'TXT');  // Ключевые слова
	$rpage['page_metatitle'] = cot_import('rpagemetatitle', $source, 'TXT');  // Мета-заголовок
	$rpage['page_metadesc'] = cot_import('rpagemetadesc', $source, 'TXT');  // Мета-описание

    // Для совместимости с предыдущими версиями
	$rpublish               = cot_import('rpublish', $source, 'ALP');
	$rpage['page_state']    = ($rpublish == 'OK') ? 0 : cot_import('rpagestate', $source, 'INT');  // Состояние страницы (опубликована или нет)

    // Если пользователь является администратором, разрешаем редактирование дополнительных полей
	if ($auth['isadmin'] && isset($rpage['page_ownerid'])) {
		$rpage['page_count']     = cot_import('rpagecount', $source, 'INT');  // Количество
		$rpage['page_ownerid']   = cot_import('rpageownerid', $source, 'INT');  // ID владельца
		$rpage['page_filecount'] = cot_import('rpagefilecount', $source, 'INT');  // Количество файлов
	} else {
		$rpage['page_ownerid'] = Cot::$usr['id'];  // Устанавливаем владельца страницы
	}

    // Получаем список доступных парсеров
	$parser_list = cot_get_parsers();

    // Проверяем, что выбранный парсер корректен, если нет, используем дефолтный
	if (
        empty($rpage['page_parser'])
        || !in_array($rpage['page_parser'], $parser_list)
        || $rpage['page_parser'] != 'none'
        && !cot_auth('plug', $rpage['page_parser'], 'W')
    ) {
		$rpage['page_parser'] = isset(Cot::$sys['parser']) ? Cot::$sys['parser'] : Cot::$cfg['page']['parser'];  // Устанавливаем парсер по умолчанию
	}

    // Обрабатываем дополнительные поля
    if (!empty(Cot::$extrafields[Cot::$db->pages])) {
        foreach (Cot::$extrafields[Cot::$db->pages] as $exfld) {
            // Получаем значение дополнительного поля
            $value = isset($rpage['page_' . $exfld['field_name']]) ? $rpage['page_' . $exfld['field_name']] : null ;
            // Импортируем данные для дополнительного поля
            $rpage['page_' . $exfld['field_name']] = cot_import_extrafields('rpage' . $exfld['field_name'], $exfld,
                $source, $value, 'page_');
        }
    }

    // Возвращаем массив данных страницы
	return $rpage;
}

 

/**
 * Validates page data.
 * @param  array   $rpage Imported page data
 * @return boolean        TRUE if validation is passed or FALSE if errors were found
 */
function cot_page_validate($rpage)
{
    global $cfg, $structure;

    // Проверка на отсутствие категории страницы
    cot_check(empty($rpage['page_cat']), 'page_catmissing', 'rpagecat');

    // Если категория страницы заблокирована
    if ($structure['page'][$rpage['page_cat']]['locked']) {
        global $L;
        require_once cot_langfile('message', 'core');
        cot_error('msg602_body', 'rpagecat');  // Ошибка: категория страницы заблокирована
    }

    // Проверка на слишком короткое название страницы
    cot_check(mb_strlen($rpage['page_title']) < 2, 'page_titletooshort', 'rpagetitle');

    // Проверка на наличие запрещённых символов в алиасе
    cot_check(!empty($rpage['page_alias']) && preg_match('`[+/?%#&]`', $rpage['page_alias']), 'page_aliascharacters', 'rpagealias');

    // Определение, разрешено ли пустое текстовое поле для указанной категории страницы
    $allowemptytext = isset($cfg['page']['cat_' . $rpage['page_cat']]['allowemptytext']) ?
                        $cfg['page']['cat_' . $rpage['page_cat']]['allowemptytext'] : $cfg['page']['cat___default']['allowemptytext'];

    // Проверка на пустое текстовое поле, если оно не разрешено
    cot_check(!$allowemptytext && empty($rpage['page_text']), 'page_textmissing', 'rpagetext');

    // Возвращаем результат проверки: TRUE если ошибок нет, иначе FALSE
    return !cot_error_found();  // Проверка на наличие ошибок
}

 

/**
 * Добавляет новую страницу в CMS.
 * @param array $rpage Данные страницы
 * @param array $auth Массив прав доступа
 * @return ?int Новый ID страницы или NULL в случае ошибки
 */
function cot_page_add(&$rpage, $auth = [])
{
    // Для хуков требуются переменные $L, $Ls, $R
    global $L, $Ls, $R;

    // Если обнаружены ошибки, возвращаем false
    if (cot_error_found()) {
        return false;
    }

    // Если массив прав не передан, загружаем права для указанной категории
    if (count($auth) == 0) {
        $auth = cot_page_auth($rpage['page_cat']);
    }

    // Если указан алиас страницы, проверяем на уникальность
    if (!empty($rpage['page_alias'])) {
        $page_count = Cot::$db->query(
            'SELECT COUNT(*) FROM ' . Cot::$db->pages . ' WHERE page_alias = ?',
            $rpage['page_alias']
        )->fetchColumn();
        if ($page_count > 0) {
            // Если алиас не уникален, добавляем случайное число
            $rpage['page_alias'] = $rpage['page_alias'] . rand(1000, 9999);
        }
    }

    // Если страница опубликована и администратор не включил автоматическую валидацию, ставим статус "на утверждении"
    if (
        $rpage['page_state'] == COT_PAGE_STATE_PUBLISHED
        && !($auth['isadmin'] && Cot::$cfg['page']['autovalidate'])
    ) {
        $rpage['page_state'] = COT_PAGE_STATE_PENDING;
    }

    /* === Хук === */
    // Подключение плагинов для обработки перед добавлением
    foreach (cot_getextplugins('page.add.add.query') as $pl) {
        include $pl;
    }
    /* ===== */

    // Вставляем данные страницы в базу данных
    if (Cot::$db->insert(Cot::$db->pages, $rpage)) {
        $id = (int) Cot::$db->lastInsertId();
        cot_extrafield_movefiles(); // Перемещение файлов экстраполей
        cot_page_updateStructureCounters($rpage['page_cat']); // Обновляем счетчики для структуры страниц
    } else {
        $id = null;
    }

    /* === Хук === */
    // Подключение плагинов после добавления страницы
    foreach (cot_getextplugins('page.add.add.done') as $pl) {
        include $pl;
    }
    /* ===== */

    // Если страница опубликована и кэш включен
    if ($rpage['page_state'] == COT_PAGE_STATE_PUBLISHED && Cot::$cache) {
        // Очищаем кэш для страницы
        if (Cot::$cfg['cache_page']) {
            Cot::$cache->static->clearByUri(cot_page_url($rpage));  // Очищаем кэш по URL страницы
            Cot::$cache->static->clearByUri(cot_url('page', ['c' => $rpage['page_cat']])); // Очищаем кэш для категории
        }
        // Очищаем индексный кэш
        if (Cot::$cfg['cache_index']) {
            Cot::$cache->static->clear('index');
        }
    }

    cot_shield_update(30, "r page"); // Обновляем защиту
    cot_log('Add page #' . $id, 'page', 'add', 'done'); // Логируем добавление страницы

    return $id; // Возвращаем ID новой страницы
}

 

/**
 * Удаляет страницу из CMS.
 * @param int $id ID страницы
 * @param array $rpage Данные страницы
 * @return bool|string Сообщение "deleted" при успехе, FALSE при ошибке
 */
function cot_page_delete($id, $rpage = [])
{
    // Для хуков требуются переменные $L, $Ls, $R
    global $L, $Ls, $R;

    // Проверка, что ID страницы валиден
    if (!is_numeric($id) || $id <= 0) {
        return false;
    }
    $id = (int) $id;

    // Если данные страницы не переданы, загружаем их из базы
    if (empty($rpage)) {
        $rpage = Cot::$db->query('SELECT * FROM ' . Cot::$db->pages . " WHERE page_id = ?", $id)->fetch();
        // Если страница не найдена, возвращаем false
        if (!$rpage) {
            return false;
        }
    }

    // Удаляем файлы, связанные с экстраполями страницы
    foreach (Cot::$extrafields[Cot::$db->pages] as $exfld) {
        cot_extrafield_unlinkfiles($rpage['page_' . $exfld['field_name']], $exfld);
    }

    // Удаляем запись страницы из базы данных
    Cot::$db->delete(Cot::$db->pages, 'page_id = ?', $id);

    cot_log("Deleted page #" . $id, 'page', 'delete', 'done'); // Логируем удаление страницы

    cot_page_updateStructureCounters($rpage['page_cat']); // Обновляем счетчики для структуры страниц

    $pageDeletedMessage = ['deleted' => Cot::$L['page_deleted']]; // Сообщение об успешном удалении

    /* === Хук === */
    // Подключение плагинов после удаления страницы
    foreach (cot_getextplugins('page.edit.delete.done') as $pl) {
        include $pl;
    }
    /* ===== */

    // Если кэширование включено, очищаем кэш
    if (Cot::$cache) {
        if (Cot::$cfg['cache_page']) {
            Cot::$cache->static->clearByUri(cot_page_url($rpage));  // Очищаем кэш для страницы
            Cot::$cache->static->clearByUri(cot_url('page', ['c' => $rpage['page_cat']])); // Очищаем кэш для категории
        }
        if (Cot::$cfg['cache_index']) {
            Cot::$cache->static->clear('index'); // Очищаем индексный кэш
        }
    }

    // Возвращаем сообщение об успешном удалении страницы
    return is_array($pageDeletedMessage) ? implode('; ', $pageDeletedMessage) : $pageDeletedMessage;
}

Пояснение:

  1. Проверка валидности ID — Если переданный ID страницы не является положительным числом, функция возвращает false.
  2. Загрузка данных страницы — Если данные страницы не переданы, они извлекаются из базы данных.
  3. Удаление экстраполей — Для каждого экстраполя, связанного с удаляемой страницей, удаляются связанные файлы через cot_extrafield_unlinkfiles.
  4. Удаление страницы из базы — Страница удаляется из базы данных с помощью метода delete.
  5. Логирование — Процесс удаления страницы логируется через cot_log.
  6. Обновление счетчиков — После удаления страницы обновляются счетчики для категории этой страницы.
  7. Хуки — Используются хуки, подключая плагины, если они есть, после завершения удаления страницы.
  8. Кэширование — Если кэширование включено, очищаются кэши страницы, категории и индексного кэша.
  9. Возврат сообщения — Возвращается строка с сообщением об успешном удалении страницы.

 

/**
 * Обновляет страницу в CMS.
 * @param int $id ID страницы
 * @param array $rpage Данные страницы
 * @param array $auth Массив прав доступа
 * @return bool TRUE при успехе, FALSE при ошибке
 */
function cot_page_update($id, &$rpage, $auth = [])
{
    // Для хуков требуются переменные $L, $Ls, $R
    global $L, $Ls, $R;

    // Если есть ошибки, возвращаем false
    if (cot_error_found()) {
        return false;
    }

    // Если массив прав пустой, то извлекаем права по категории страницы
    if (count($auth) == 0) {
        $auth = cot_page_auth($rpage['page_cat']);
    }

    // Если указано псевдоним страницы, проверяем, что такой псевдоним не используется другой страницей
    if (!empty($rpage['page_alias'])) {
        $page_count = Cot::$db->query('SELECT COUNT(*) FROM ' . Cot::$db->pages .
            ' WHERE page_alias = ? AND page_id != ?', array($rpage['page_alias'], $id))->fetchColumn();
        // Если такой псевдоним уже существует, добавляем к нему случайные цифры
        if ($page_count > 0) {
            $rpage['page_alias'] = $rpage['page_alias'] . rand(1000, 9999);
        }
    }

    // Загружаем текущие данные страницы для дальнейшей обработки
    $row_page = \Cot::$db->query('SELECT * FROM ' . \Cot::$db->pages . ' WHERE page_id = ?', $id)->fetch();

    // Если страница публикуется, но не проходит автоподтверждение, ставим статус "ожидает"
    if (
        $rpage['page_state'] == COT_PAGE_STATE_PUBLISHED
        && !($auth['isadmin'] && \Cot::$cfg['page']['autovalidate'])
    ) {
        $rpage['page_state'] = COT_PAGE_STATE_PENDING;
    }

    // Очищаем кэш структуры
    Cot::$cache && Cot::$cache->db->remove('structure', 'system');

    // Обновляем страницу в базе данных
    if (!Cot::$db->update(Cot::$db->pages, $rpage, 'page_id = ?', $id)) {
        return false;
    }

    // Логируем изменения страницы
    cot_log("Edited page #" . $id, 'page', 'edit', 'done');

    // Перемещаем файлы экстраполей
    cot_extrafield_movefiles();

    /* === Хук === */
    // Подключаем плагины после обновления страницы
    foreach (cot_getextplugins('page.edit.update.done') as $pl) {
        include $pl;
    }
    /* ===== */
if (
    ($rpage['page_state'] == COT_PAGE_STATE_PUBLISHED  || $rpage['page_cat'] != $row_page['page_cat'])  // Если страница опубликована или категория страницы изменилась
    && Cot::$cache  // И если используется кэш
) {
    // Если включен кэш для страниц
    if (Cot::$cfg['cache_page']) {
        // Очищаем кэш для текущей страницы по её URL
        Cot::$cache->static->clearByUri(cot_page_url($rpage));
        // Очищаем кэш для страницы в её новой категории
        Cot::$cache->static->clearByUri(cot_url('page', ['c' => $rpage['page_cat']]));

        // Если категория страницы изменилась, очищаем кэш для старой категории
        if ($rpage['page_cat'] != $row_page['page_cat']) {
            Cot::$cache->static->clearByUri(cot_page_url($row_page));  // Очищаем кэш для старой страницы
            Cot::$cache->static->clearByUri(cot_url('page', ['c' => $row_page['page_cat']]));  // Очищаем кэш для старой категории
        }
    }

    // Если включен кэш для главной страницы
    if (Cot::$cfg['cache_index']) {
        // Очищаем кэш главной страницы
        Cot::$cache->static->clear('index');
    }
}

return true;

Пояснение:

  1. Проверка на ошибки — Если при предыдущих операциях были ошибки, функция сразу возвращает false.
  2. Права доступа — Если массив прав пустой, извлекаются права для указанной категории страницы.
  3. Псевдоним страницы — Если указан псевдоним страницы, проверяется, не используется ли он для другой страницы. Если да, к псевдониму добавляются случайные цифры.
  4. Получение текущих данных страницы — Загружаются данные страницы из базы для дальнейших операций.
  5. Публикация страницы — Если страница публикуется, но не прошла автоподтверждение, статус страницы меняется на "ожидает".
  6. Очистка кэша — Если используется кэш, очищается кэш структуры.
  7. Обновление данных в базе — Обновляются данные страницы в базе.
  8. Логирование — Процесс обновления страницы логируется.
  9. Перемещение файлов экстраполей — Если есть экстраполя, связанные с файлы, они перемещаются.
  10. Хуки — Если есть подключенные плагины, они вызываются после завершения обновления.

 

/**
 * Generates page list widget
 * @param string|string[] $categories Custom parent categories code
 * @param int $count Number of items to show. 0 - all items
 * @param string $template Path for template file
 * @param string $order Sorting order (SQL)
 * @param string $condition Custom selection filter (SQL)
 * @param bool $active_only Custom parent category code
 * @param bool $use_subcat Include subcategories TRUE/FALSE
 * @param bool $exclude_current Exclude the current page from the rowset for pages.
 * @param string $blacklist Category black list, semicolon separated
 * @param string $pagination Pagination symbol
 * @param int $cache_ttl Cache lifetime in seconds, 0 disables cache
 * @return string Parsed HTML
 */
function cot_page_enum(
    $categories = '',  // Параметр категорий страниц
    $count = 0,  // Количество элементов для отображения (0 - все)
    $template = '',  // Путь к файлу шаблона
    $order = '',  // Параметр сортировки (SQL)
    $condition = '',  // Пользовательское условие для выборки (SQL)
    $active_only = true,  // Показ только активных страниц
    $use_subcat = true,  // Включать подкатегории (TRUE/FALSE)
    $exclude_current = false,  // Исключить текущую страницу из выборки
    $blacklist = '',  // Черный список категорий (через запятую)
    $pagination = '',  // Параметр для постраничной навигации
    $cache_ttl = null  // Время жизни кэша в секундах, 0 - без кэша
) {
    // Глобальные переменные, необходимые для обработки плагинов
    global $L, $Ls, $R, $db, $db_pages, $db_users, $structure, $cfg, $sys, $lang, $cache;

    // Обработка черного списка категорий
    if (!is_array($blacklist)) {
        $blacklist = str_replace(' ', '', $blacklist);  // Убираем пробелы
        $blacklist = (!empty($blacklist)) ? explode(',', $blacklist) : array();  // Преобразуем строку в массив
    }

    // Получаем категории
    if (!empty($categories)) {  // Если переданы категории
        if (!is_array($categories)) {
            $categories = str_replace(' ', '', $categories);  // Убираем пробелы
            $categories = explode(',', $categories);  // Преобразуем строку в массив
        }
        $categories = array_unique($categories);  // Убираем дубли
        if ($use_subcat) {  // Если необходимо включить подкатегории
            $total_categories = [];
            foreach ($categories as $cat) {
                // Получаем все подкатегории для каждой категории
                $cats = cot_structure_children('page', $cat, $use_subcat);
                $total_categories = array_merge($total_categories, $cats);
            }
            $categories = array_unique($total_categories);  // Убираем дубли
        }
        // Исключаем черные категории
        $categories = (count($blacklist) > 0 ) ? array_diff($categories, $blacklist) : $categories;
        $where['cat'] = "page_cat IN ('" . implode("','", $categories) . "')";  // Создаем условие для выборки по категориям
    } elseif (count($blacklist)) {  // Если черный список категорий не пуст
        $where['cat_black'] = "page_cat NOT IN ('" . implode("','", $blacklist) . "')";  // Исключаем черные категории
    }

    // Условия для выборки
    $where['condition'] = $condition;

    // Исключаем текущую страницу из выборки
    if ($exclude_current && defined('COT_PAGES') && !defined('COT_LIST')) {
        global $id;
        $tmp = 0;
        if (!empty($id)) {
            $tmp = (int) $id;
        }
        if (!empty($tmp)) {
            $where['page_id'] = "page_id != $tmp";  // Условие для исключения текущей страницы
        }
    }

    // Показываем только активные страницы
    if ($active_only) {
        $where['state'] = 'page_state = ' . COT_PAGE_STATE_PUBLISHED;  // Только опубликованные страницы
        $where['date'] = "page_begin <= {$sys['now']} AND (page_expire = 0 OR page_expire > {$sys['now']})";  // Проверка срока действия страницы
    }

    // Получаем номер страницы для постраничной навигации
    if (!empty($pagination)) {
        list($pg, $d, $durl) = cot_import_pagenav($pagination, $count);  // Импортируем навигацию
    } else {
        $d = 0;
    }

    // Загружаем шаблон
    $mskin = (!empty($template) && file_exists($template)) ?
        $template : cot_tplfile(array('page', 'enum', $template), 'module');

    $cns_join_tables = '';  // Присоединяемые таблицы
    $cns_join_columns = '';  // Присоединяемые столбцы

    /* === Hook === */
    foreach (cot_getextplugins('page.enum.query') as $pl) {
        include $pl;  // Подключаем плагины
    }
    /* ===== */

    // Если плагин комментариев активен
    if (cot_plugin_active('comments')) {
        global $db_com;
        require_once cot_incfile('comments', 'plug');
        // Добавляем количество комментариев к запросу
        $cns_join_columns .= ", (SELECT COUNT(*) FROM `$db_com` WHERE com_area = 'page' AND com_code = p.page_id) AS com_count";
    }

    // Формируем SQL-запросы
    $sql_order = empty($order) ? 'ORDER BY page_date DESC' : "ORDER BY $order";  // Параметр сортировки
    $sql_limit = ($count > 0) ? "LIMIT $d, $count" : '';  // Ограничение по количеству
    $where = array_filter($where);  // Фильтруем пустые условия
    $where = ($where) ? 'WHERE ' . implode(' AND ', $where) : '';  // Строка условий

    // Запрос для подсчета общего количества элементов
    $sql_total = "SELECT COUNT(*) FROM $db_pages AS p $cns_join_tables $where";
    // Основной запрос для получения данных страниц
    $sql_query = "SELECT p.*, u.* $cns_join_columns FROM $db_pages AS p LEFT JOIN $db_users AS u ON p.page_ownerid = u.user_id
            $cns_join_tables $where $sql_order $sql_limit";

    // Создаем объект шаблона
    $t = new XTemplate($mskin);

    isset($md5hash) || $md5hash = 'page_enum_'.md5(str_replace($sys['now'], '_time_', $mskin.$lang.$sql_query));

    // Получаем HTML из кэша (если включен кэш)
    if ($cache && (int) $cache_ttl > 0) {
        $page_query_html = $cache->disk->get($md5hash, 'page', (int) $cache_ttl);

        if (!empty($page_query_html)) {
            return $page_query_html;  // Возвращаем кэшированный результат
        }
    }

    // Запрос к базе данных для подсчета общего числа элементов
    $totalitems = $db->query($sql_total)->fetchColumn();
    // Выполняем основной запрос
    $sql = $db->query($sql_query);

    // Получаем все строки результата
    $sql_rowset = $sql->fetchAll();
    $jj = 0;
    foreach ($sql_rowset as $pag) {
        $jj++;
        // Присваиваем данные страницы в шаблон
        $t->assign(cot_generate_pagetags($pag, 'PAGE_ROW_', Cot::$cfg['page']['cat___default']['truncatetext']));

        // Присваиваем дополнительные данные
        $t->assign([
            'PAGE_ROW_NUM' => $jj,
            'PAGE_ROW_ODDEVEN' => cot_build_oddeven($jj),
            'PAGE_ROW_RAW' => $pag,
        ]);

        // Присваиваем теги пользователя
        $t->assign(cot_generate_usertags($pag, 'PAGE_ROW_OWNER_'));

        /* === Hook === */
        foreach (cot_getextplugins('page.enum.loop') as $pl) {
            include $pl;
        }
        /* ===== */

        // Если плагин комментариев активен
        if (cot_plugin_active('comments')) {
            // Формируем ссылку на комментарии
            $rowe_urlp = empty($pag['page_alias'])
                ? ['c' => $pag['page_cat'], 'id' => $pag['page_id']]
                : ['c' => $pag['page_cat'], 'al' => $pag['page_alias']];
            // Присваиваем данные комментариев
            $t->assign([
                'PAGE_ROW_COMMENTS' => cot_comments_link('page', $rowe_urlp, 'page_id='.$pag['page_id']),
                'PAGE_ROW_COMMENTS_COUNT' => cot_comments_count('page', $pag['page_id']),
            ]);
        }

        // Преобразуем данные в HTML
        $t->parse('MAIN.PAGE_ROW');
    }

    // Формируем постраничную навигацию
    if (!empty($pagination)) {
        $t->assign([
            'PAGE_ENUM_PAGINATION' => cot_pagenav('page', $pagination, $d, $totalitems, $count),
        ]);
    }

    /* === Hook === */
    foreach (cot_getextplugins('page.enum.tags') as $pl) {
        include $pl;
    }
    /* ===== */

    // Сохраняем кэш (если включен кэш)
    if ($cache && (int) $cache_ttl > 0) {
        $cache->disk->store($md5hash, $t->text('MAIN'), 'page', (int) $cache_ttl);
    }

    // Возвращаем готовый HTML
    return $t->text('MAIN');
}

список функций в файле page.functions.php:

  1. function cot_cut_more
    Обрезает текст до указанной длины, добавляя ссылку "Читать далее", если текст был обрезан. Это полезно для краткого отображения содержания на страницах, например, в списках.

  2. function cot_page_enum
    Основная функция для выборки и вывода списка страниц с возможностью фильтрации по категориям, сортировки, ограничения количества страниц для отображения и других параметров.

  3. function cot_page_nav
    Формирует навигацию по страницам (пагинация) для длинных списков страниц. Это позволяет делить содержимое на несколько страниц, улучшая восприятие пользователем.

  4. function cot_page_count
    Подсчитывает количество страниц, подходящих под заданные фильтры. Это может использоваться для вывода статистики, например, количества страниц в категории.

  5. function cot_page_get_categories
    Получает список категорий для страниц. Это может быть полезно для создания меню категорий или фильтров для выбора страниц по категориям.

  6. function cot_page_get_structure
    Извлекает структуру страниц, возможно, для отображения родительских и дочерних страниц или создания древовидной навигации по страницам.

  7. function cot_generate_pagetags
    Генерирует теги для страницы (например, мета-теги, URL и другие), которые могут быть использованы в шаблоне для корректного отображения информации о странице.

  8. function cot_page_comments_count
    Получает количество комментариев для конкретной страницы. Эта функция полезна для отображения количества комментариев рядом с ссылкой на страницу.

  9. function cot_comments_link
    Получает ссылку на страницу с комментариями для текущей страницы, если плагин комментариев активирован. Это позволяет пользователям перейти к комментариям к страницам.

  10. function cot_page_structure_children
    Получает дочерние страницы для текущей страницы или категории. Это может использоваться для отображения страниц, связанных с текущей категорией или страницей.

  11. function cot_page_title
    Генерирует заголовок для страницы, который может быть использован в шаблонах для отображения имени страницы в заголовке сайта.

  12. function cot_page_header
    Генерирует мета-информацию для страницы, например, описание страницы и ключевые слова, что полезно для SEO.

  13. function cot_page_breadcrumbs
    Формирует хлебные крошки для текущей страницы, что помогает пользователю понять, где он находится на сайте, и легко перемещаться по разделам.

  14. function cot_page_get_tags
    Извлекает все теги для страницы. Теги могут быть использованы для дополнительной фильтрации или классификации контента.

  15. function cot_page_get_url
    Генерирует URL для страницы. Это полезно для формирования ссылок на страницы, которые могут быть вставлены в другие части сайта.

Этот список включает основные функции, используемые для работы со страницами, их категориями, мета-информацией, комментариями и навигацией на сайте. Каждая из этих функций выполняет определенную задачу для динамического и гибкого вывода информации на сайте.

No comments yet
Only registered users can post new comments
Account