Перейти к содержанию

Компоненты SEO и учебных ресурсов

Оглавление серии

Компонент объединяет несколько полей внутри документа. В отличие от отдельной коллекции, он не представляет самостоятельную запись каталога, к которой все статьи обращаются по общему адресу. Для «Редакционного дома» компонент удобен у SEO-настроек статьи и у списка учебных ресурсов: их значения принадлежат конкретному тексту и редактируются вместе с ним.

После этого урока Article получит один компонент seo и повторяемый компонент resources. Автор Анна Лесная и раздел «Вёрстка» останутся отношениями. Такое соседство полезно: на одном документе видно, почему два внешне похожих набора полей требуют разных моделей. Состояние Article после изменения хранится в states/lesson-04/.

Компонент или связанная коллекция

У Анны есть собственная биография, и она может написать много статей. Поэтому Author — отдельная коллекция. У SEO-title конкретной статьи нет самостоятельной редакционной судьбы: он объясняет именно эту страницу в другом контексте. Создание коллекции «SEO-заголовки» заставило бы редактора выбирать отдельный объект там, где достаточно заполнить два связанных поля внутри Article.

В Builder создайте компонент категории editorial с именем seo. Добавьте title длиной до семидесяти символов и description длиной до ста шестидесяти. Эти числа — внутренние ограничения нашей учебной редакции, а не гарантированные границы показа всеми поисковыми системами. Разная ширина букв и условия интерфейса не позволяют обещать, что определённое число символов всегда помещается без сокращения.

Полный файл src/components/editorial/seo.json имеет следующую структуру.

{
  "collectionName": "components_editorial_seos",
  "info": {
    "displayName": "SEO"
  },
  "options": {},
  "attributes": {
    "title": {
      "type": "string",
      "maxLength": 70
    },
    "description": {
      "type": "text",
      "maxLength": 160
    }
  }
}

Затем в Article добавьте Component field seo, выберите созданный компонент и отключите repeatable. Ожидаемая форма статьи должна содержать один блок из двух полей. Наличие компонента не означает, что сайт уже использует его: клиенту ещё потребуется запросить вложенные сведения и определить, куда они попадут в HTML.

Для первой статьи задайте SEO-title «Сетка карточек CSS Grid» и description «Учебная библиотека: три карточки в адаптивной сетке». Название документа остаётся в title Article. Если позже появится более короткий SEO-title, обычный H1 страницы не обязан изменяться. Разделение полей позволяет сформулировать такую политику явно, а не подменять основное название метаданными.

Повторяемый список ресурсов

Статья может ссылаться на несколько материалов. Каждой ссылке нужны подпись и адрес. Если хранить их в одной строке, клиенту придётся разбирать разделители, а редактору — помнить специальный формат. Компонент Resource определяет понятную пару label/url; repeatable позволяет иметь несколько таких пар в одной статье.

Полный src/components/editorial/resource.json не зависит от количества ресурсов.

{
  "collectionName": "components_editorial_resources",
  "info": {
    "displayName": "Resource"
  },
  "options": {},
  "attributes": {
    "label": {
      "type": "string",
      "required": true
    },
    "url": {
      "type": "string",
      "required": true
    }
  }
}

Добавьте в Article поле resources, выберите Resource и включите repeatable. В первом документе создайте один элемент: label «CSS Grid на MDN», URL https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_layout. Для дополнительного элемента можно использовать другой официальный материал, но сначала убедитесь, что адрес действительно относится к теме статьи. Схема проверяет наличие строки, а не смысл назначения.

Порядок элементов полезен для читателя. Сначала разместите материал, который помогает повторить основной пример, затем справочный источник для дополнительного изучения. Случайное расположение по времени добавления не всегда удачно. Компонент даёт возможность передать последовательность; редакционная задача — сделать её объяснимой.

В API компоненты не получают собственных стандартных endpoints наподобие /api/resources. Они читаются как часть Article, обычно с явным populate. Это отличает их от Author и Category. Если в будущем один ресурс должен иметь общий статус, владельца и список статей, где он используется, можно пересмотреть модель и выделить Resource в коллекцию. Такое изменение потребует переноса существующих значений, а не только переключателя в панели.

Значения и поведение клиента

Рассмотрим две статьи с одинаковой ссылкой на MDN. При нашей модели у каждой свой элемент resources. Исправление URL в первой статье не исправляет вторую. Это разумно для маленькой библиотеки с редкими ссылками, но неудобно для централизованного справочника из тысяч источников. Выбор модели зависит от того, нужно ли совместное управление, а не от привлекательности интерфейса.

Повторяемые компоненты имеют внутренние идентификаторы при хранении и обновлении. Когда позже начнёте изменять их через API, различайте замену набора и изменение существующего элемента. Не выкидывайте служебные сведения из ответа, если они нужны выбранной операции обновления. В этой серии редактор работает с компонентами в панели, а импорт создаёт их заново только в пустой базе; мы не выдаём пример создания за универсальный алгоритм синхронизации.

Также нельзя считать строковое поле url безопасной ссылкой автоматически. Если сайт решит показывать ресурсы, ему следует разрешить ожидаемые схемы адресов, например https:, и экранировать label. Значение javascript: должно быть отклонено логикой отображения, даже если редактор сумел сохранить его как обычную строку. Границы модели и renderer нужно рассматривать совместно.

В текущем минимальном потребителе будущего урока body остаётся обычным текстом, а SEO и resources сначала будут запрашиваться для демонстрации контракта. Их полноценный показ — отдельное расширение. Такая явная граница помогает не спутать «поле создано», «данные получены» и «данные используются посетителем». Официальное устройство компонентов описано в моделях Strapi.

Для SEO-компонента определите fallback до построения сайта. Если seo.title пуст, логично использовать обычный title Article; если seo.description пуст, можно выбрать summary или вовсе не выводить соответствующий metadata. Такое правило принадлежит клиенту, который знает назначение HTML, а не компоненту, хранящему значения. Обязательная непустая строка во всех полях иногда заставляет редактора копировать текст без смысла. В нашей модели SEO-поля необязательны, чтобы показать эту границу явно. При расширении renderer запишите fallback в одном месте и проверьте страницу с заполненным компонентом и документ, у которого он отсутствует.

Ожидаемое состояние после ваших действий — сохранённый черновик с одним SEO-компонентом и одним ресурсом, связанным с прежними Author и Category. Эти окна не запускались при подготовке курса. Для проверки смысла модели объясните, что произойдёт при изменении биографии Анны и при изменении URL в resources: первое значение общее для связанных статей, второе принадлежит только выбранному документу. Эта разница пригодится в следующем уроке, где появится ещё один вид объектов — файл обложки и его редакционная подпись.