Файл page.functions.php в Cotonti

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

Опубликовано в: Модуль Pages в Cotonti CMF

Описание файла "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 для страницы. Это полезно для формирования ссылок на страницы, которые могут быть вставлены в другие части сайта.

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

39 минут чтения Sodium Carbonate

Комментарии (0)

Комментарии отсутствуют
Добавление комментариев доступно только зарегистрированным пользователям

Автор контента

webitproff

Оффлайн

Sodium Carbonate

Последняя авторизация: 19.07.2026 01:57

  • Страница размещена: 02.02.2025 21:08
  • Последнее обновление: 11.02.2025 19:52

Похожие страницы

Файл "page.admin.home.php" модуль "Page" в Cotonti
1 Описание файла "page.admin.home.php" в Cotonti CMF Файл "page.admin.home.php" является частью
Файл page.php в Cotonti
2 описание файла page.php в Cotonti CMF Основное назначение и место в системе Cotonti Файл page.php — это главный
Файл page.setup.php в Cotonti
3 Основное назначение файла и его место в системе Cotonti Файл page.setup.php является конфигурационным файлом модуля
Файл page.header.php в Cotonti
4 описание файла page.header.php в Cotonti CMF  1. Основное назначение и место в системе Cotonti Файл page.header.php
Файл "page.extrafields.php" в Cotonti CMF
5 Файл "page.extrafields.php" в системе Cotonti CMF является частью модуля "page", и он отвечает за