Разработчикам
Запросы к контенту
Руководство разработчика PageCharm
Полный набор приемов IPageCharmContentQuery: несколько блоков и шаблонов, поиск по полям, сортировка, пейджинг, картинки и файлы.
Зачем нужен IPageCharmContentQuery
IPageCharmContentQuery — публичный способ читать CMS-данные из Razor, сервисов сайта или виджетов. Реализация sample работает поверх EF Core, но код сайта зависит от контракта PageCharm, а не от конкретной базы.
Фильтры контекста
Active()оставляет активный и уже опубликованный контент. Если у шаблона включено управление датой публикации, материалы с пустой или будущей датой скрываются.Active(false)выбирает неактивный контент; если метод не вызывать, вернутся оба состояния без проверки расписания.FromBlocks("pages", "news")выбирает один или несколько блоков.WithTemplates("article", "product")выбирает один или несколько шаблонов.ChildrenOf(parentId)выбирает дочерний контент конкретного родителя.FindByIdAsync(id),FindByUrlAsync(url),FirstOrDefaultAsync(),ToListAsync()иCountAsync()завершают запрос.
Поиск и фильтры по полям
Search(text) ищет по всем текстовым и JSON-значениям атрибутов. Он не ищет по URL и системному Name, потому что Name нужен админке, а публичные заголовки лучше хранить в полях шаблона. SearchFields(text, "summary", "body") ищет только в указанных полях. На PostgreSQL и MySQL поиск использует отдельную read-модель и provider-specific full-text индексы; на SQLite остается fallback через LIKE. Для точной фильтрации есть WhereFieldContains, WhereFieldEquals для строк, чисел, bool, дат и времени, range-методы: WhereIntegerFieldBetween, WhereDecimalFieldBetween, WhereDateFieldBetween, WhereDateTimeFieldBetween, а также фильтры по тегам: WithAnyTags, WithAllTags и WhereTagsContain.
Сортировка и пейджинг
Для даты из пользовательского поля используйте OrderByFieldOrCreatedAt(alias, sortType, descending). Метод принимает CalendarDate или Instant и подставляет CreatedAt, если поле пустое.
Если сортировку не указать, PageCharm сортирует по ручному порядку CMS: Order, затем Id. OrderByField(alias, type, descending) переопределяет это и сортирует по значению поля. Типы сортировки: Text, WholeNumber, DecimalNumber, Flag, CalendarDate, ClockTime, Instant. Для новостных лент используйте OrderByPublishAt(descending: true): при отсутствии системной даты запасным значением служит CreatedAt. Для страниц списка используйте Skip(count) и Take(count).
Словари, теги и списки
Раздел «Словари» хранит наборы значений с Name и Alias. Поля и настройки типа Tags редактируются как chips с автодополнением по выбранному словарю. Если в настройках поля включено «Разрешить новые значения», редактор может набрать новое значение прямо в форме контента или настройки; если выключено — можно выбрать только уже существующее значение словаря.
Тип Select тоже может брать варианты из словаря. В этом режиме в базе хранится alias выбранного значения, а список вариантов управляется централизованно в разделе «Словари». Это удобно для категорий, брендов, статусов и любых повторяемых справочников, которые нужны сразу в нескольких шаблонах или настройках.
Для вывода поля Tags используйте GetTags(alias); для выборок по тегам — WithAnyTags("news"), WithAllTags("news", "featured") или WhereTagsContain("topics", "news"). Это методы именно для множественных тегов и join-таблицы CmsContentTag. Для Select со словарным источником хранится один alias значения, поэтому фильтруйте его как обычное поле: WhereFieldEquals("brand", "jetbrains"). Сами словари и значения во view можно получить через IPageCharmDictionaryQuery.
Картинки, видео и файлы из полей
Медиа может быть привязано к самому контенту или к конкретному полю. В публичных запросах PageCharm загружает и Content.MediaAssets, и Attributes[].MediaAssets. Для Razor есть helpers: GetMedia() для файлов контента без поля, GetMedia("gallery"), GetFirstMedia("cover"), GetImages("gallery"), GetFiles("downloads"). В разметке используйте Url, Alt, FileName и ContentType. Для локального storage Url хранится без схемы и домена, например /uploads/file.jpg; для CDN/S3 он может быть абсолютным.
Пресеты изображений настраиваются в разделе «Медиа» через кнопку настроек. В настройках поля или настройки типа Image/Images можно выбрать допустимые пресеты и пресет по умолчанию. Если пресеты не заданы или не выбраны, CMS работает с оригинальным изображением без ресайза. Для вывода варианта используйте image.GetPresetUrl("card"); первый запрос лениво создаст файл по публичному пути /_pagecharm/images/....
Для видео используйте поля Video/Videos. В админке вставляется ссылка на youtube.com, vk.com, vkvideo.ru или rutube.ru, а CMS сохраняет объект CmsVideo: публичная ссылка лежит в video.Url, картинка предпросмотра берется через video.GetPreviewUrl(), embed-ссылка — через video.GetEmbedUrl(). Если провайдер не отдал картинку серверному запросу, URL превью можно указать вручную.
Хлебные крошки
Для хлебных крошек используйте GetBreadcrumbsAsync(content). Метод идет вверх по ParentId, защищен от циклов и возвращает активных родителей, если вызван после Active(). Если у шаблона есть отдельное поле публичного заголовка, используйте его, а Name оставьте запасным значением для админки.
Практическое правило
В админке PageCharm работает с EF напрямую, потому что там нужны транзакции, права и массовые операции. В публичном сайте читайте данные через IPageCharmContentQuery: так представления остаются переносимыми и не знают деталей хранилища.
Полный список методов, параметров и возвращаемых типов собран в справочнике Razor API.
Пример
@model PageCharmPageModel
@inject IPageCharmContentQuery Content
@{
var baseQuery = Content.Active()
.FromBlocks("catalog", "special-offers")
.WithTemplates("product", "promo-card")
.SearchFields("ноутбук", "title", "description")
.WhereDecimalFieldBetween("price", min: 1000m, max: 250000m);
var total = await baseQuery.CountAsync();
var items = await baseQuery
.OrderByField("price", CmsContentFieldSortType.DecimalNumber)
.Skip(0)
.Take(12)
.ToListAsync();
var breadcrumbs = await Content.Active().GetBreadcrumbsAsync(Model.Content);
}
<nav aria-label="Хлебные крошки">
<a href="/">Главная</a>
@foreach (var parent in breadcrumbs)
{
var title = parent.Get<string>("title") ?? parent.Name;
<span>/</span>
<a href="@parent.Url">@title</a>
}
<span>/</span>
<span>@(Model.Content.Get<string>("title") ?? Model.Content.Name)</span>
</nav>
<p>Найдено: @total</p>
@foreach (var item in items)
{
var title = item.Get<string>("title") ?? item.Name;
var description = item.Get<string>("description");
var price = item.Get<decimal>("price");
var cover = item.GetFirstMedia("cover");
var downloads = item.GetFiles("downloads");
var video = item.GetVideo("video");
var tags = item.GetTags("topics");
<article>
@if (cover is not null)
{
<img src="@cover.GetPresetUrl("kartochka-tovara")" alt="@cover.Alt">
}
<h2><a href="@item.Url">@title</a></h2>
<p>@description</p>
<strong>@price</strong>
@foreach (var file in downloads)
{
<a href="@file.Url">@file.FileName</a>
}
@if (video is not null)
{
<a href="@video.Url">
@if (video.GetPreviewUrl() is { } previewUrl)
{
<img src="@previewUrl" alt="@video.Title">
}
Смотреть видео
</a>
}
@foreach (var tag in tags)
{
<span>@tag.Name</span>
}
</article>
}
Тип сортировки
Для строковых полей используйте Text. Для Decimal-полей используйте DecimalNumber: в SQLite PageCharm сортирует такие значения через double, как и админка, чтобы не зависеть от культуры процесса.