Custom Posts
Мы используем поля customPost и customPosts для получения данных CPT — как для CPT, отображённых в схеме (таких как Post и Page), так и для тех, которые ещё не отображены (например, CPT из какого-либо плагина). Поскольку результаты могут включать сущности разных типов, эти поля возвращают тип CustomPostUnion.

Поля Custom Post в схеме
Gato GraphQL чётко разграничивает, когда пользовательская запись является «custom post», а не просто «post».
Например, комментарий можно добавить к посту, но также к странице и к CPT, поэтому тип Comment имеет поле customPost: CustomPostUnion! для получения сущности, к которой был добавлен комментарий, вместо поля post: Post!.

Именно поэтому поле customPosts принимает аргумент customPostTypes, а не postTypes.
CPT, отображённые в схеме
Существуют CPT, которые были отображены в схеме (такие как Post и Page для представления CPT "post" и "page"). В этом случае запрос будет выполнен с использованием соответствующего типа GraphQL для этого CPT.
При получении результатов из union type необходимо указывать поля для извлечения с помощью фрагментов. Они могут быть вычислены по интерфейсу CustomPost, который реализуется всеми типами CPT, или по каждому отдельному типу, например Post или Page.
В запросе ниже мы получаем custom posts с CPT "post" и "page". Отображаем их поля через 3 фрагмента, которые проверяют, реализует ли сущность CustomPost, или является типом Post или Page:
query {
customPosts(filter: { customPostTypes: ["post", "page"] }) {
...CustomPostProps
...PostProps
...PageProps
}
}
fragment CustomPostProps on CustomPost {
__typename
title
excerpt
url
dateStr(format: "d/m/Y")
}
fragment PostProps on Post {
tags {
id
name
}
}
fragment PageProps on Page {
author {
id
name
}
}CPT, не отображённые в схеме
Когда CPT ещё не был отображён в схеме (например, "attachment", "revision" или "nav_menu_item", или любой CPT, установленный каким-либо плагином), мы по-прежнему используем поля customPost и customPosts, передавая соответствующее имя CPT в аргументе поля filter.customPostTypes.
Поскольку их типы отсутствуют в схеме, их данные будут получены через тип GenericCustomPost, который содержит все общие свойства CPT (title, content, excerpt, date и т.д.).

В запросе ниже мы получаем custom posts для различных CPT:
query {
customPosts(
filter:{
customPostTypes: [
"page",
"nav_menu_item",
"wp_block",
"wp_global_styles"
]
}
) {
... on CustomPost {
id
title
customPostType
status
}
__typename
}
}Разрешение доступа к Custom Post Types
CPT должны быть явно разрешены для возможности запроса, как описано в руководстве Разрешение доступа к Custom Post Types.
Запрос custom posts
Типы GraphQL для CPT, отображённых в схеме (например, "post" => Post и "page" => Page), включаются непосредственно в CustomPostUnion.
Для любого CPT, не смоделированного в схеме (например, "attachment", "revision" или "nav_menu_item", или любого CPT, установленного каким-либо плагином), его данные будут доступны через тип GenericCustomPost.
Мы указываем CPT для получения через аргумент поля filter.customPostTypes, который принимает список строк с именами CPT в том виде, в каком они определены в WordPress (например, "post", "page" и т.д.). Например:
query {
customPosts(
filter: { customPostTypes: ["some-custom-cpt"] }
) {
... on CustomPost {
id
title
}
}
}Этот запрос извлекает записи из нескольких CPT:
query {
customPosts(
filter: {
customPostTypes: [
"post",
"page",
"attachment",
"nav_menu_item",
"custom_css",
"revision"
],
status: [
publish,
inherit,
auto_draft
]
}
) {
id
title
content
status
customPostType
__typename
}
}Поскольку все Custom Posts реализуют интерфейс CustomPost, мы можем получать данные из CustomPostUnion с помощью ссылки на фрагмент или встроенного фрагмента:
query {
comments {
id
date
content
customPost {
__typename
...on CustomPost {
id
title
url
}
}
}
}Если мы знаем, что комментарий был добавлен к посту, можно также запросить поля, специфичные для Post:
query {
comments {
id
date
content
customPost {
__typename
...on CustomPost {
id
title
url
}
...on Post {
categoryNames
}
}
}
}Фильтрация CPT по пользовательской таксономии
Пользовательский тип записи может иметь связанные с ним пользовательские таксономии (теги и категории). Например, CPT "product" может иметь связанную таксономию категорий "product-cat" и таксономию тегов "product-tag".
Мы можем фильтровать результаты по этим связанным таксономиям с помощью входных параметров tags и categories в поле filter.
В запросе ниже мы получаем custom posts с фильтрацией по категории:
query {
customPosts(
filter: {
categories: {
includeBy: {
ids: [26, 28]
}
taxonomy: "product-cat"
}
}
) {
... on CustomPost {
id
title
}
... on GenericCustomPost {
categories(taxonomy: "product-cat") {
id
}
}
}
}Получение пользовательских данных CPT
Используя GenericCustomPost, мы можем запрашивать только те поля, которые являются общими для всех CPT; получение пользовательских данных конкретного CPT не поддерживается (например, получение данных о цене для пользовательского CPT "product").
Чтобы получать пользовательские данные CPT, необходимо создать соответствующие резолверы в PHP-коде для отображения CPT в схеме:
- Создать тип
Product - Добавить к нему поле
price
Теперь тип CustomPostUnion (возвращаемый Root.customPosts) будет преобразовывать все записи этого CPT в тип Product.
query {
customPosts(
filter: {
customPostTypes: "product"
}
) {
__typename
...on CustomPost { # interface implemented by all CPT types
id
title
customPostType
status
}
...on Product { # custom CPT type
price # custom field
}
}
}Дополнительно можно создать поле Root.products: [Product!] и использовать его напрямую:
query {
products {
__typename # Product
id
title
status
price # custom field
}
}Мутации данных пользовательских CPT
Для CPT, которые не требуют никаких дополнительных полей сверх полей типа Post, вы можете без опасений использовать мутации createCustomPost и updateCustomPost.
Например, CPT MyPortfolio, использующий стандартные поля title и content и не имеющий дополнительных полей, может полностью управляться с помощью этих мутаций.
Этот запрос создаёт запись для CPT "my-portfolio":
mutation {
createCustomPost(
input: {
customPostType: "my-portfolio"
title: "My photograph"
contentAs: { html: "This is my photo, check it out." }
}
) {
status
errors {
__typename
...on ErrorPayload {
message
}
...on GenericErrorPayload {
code
}
}
customPost {
__typename
...on CustomPost {
id
title
content
}
}
}
}Этот запрос обновляет заголовок и содержимое для того же CPT:
mutation {
updateCustomPost(input: {
id: 1
customPostType: "my-portfolio"
title: "Updated title"
contentAs: { html: "Updated content" }
}) {
status
errors {
__typename
...on ErrorPayload {
message
}
}
customPost {
__typename
...on CustomPost {
id
title
content
}
}
}
}Пользовательские типы записей, предоставляемые сторонними плагинами, возможно, потребуют создания (а также обновления) только через соответствующий плагин.
Это связано с тем, что они могут иметь собственные пользовательские данные (как в wp_postmeta, так и в проприетарной таблице), которые также необходимо добавить, но о которых Gato GraphQL не осведомлён.
Для надлежащего управления этими CPT необходимо создать соответствующую интеграцию между этим плагином и Gato GraphQL, обеспечивающую сопоставление всех полей CPT.
Например, мы можем использовать поле Root.updateCustomPost для перевода и обновления заголовка и содержимого продукта WooCommerce (то есть из CPT Product). Однако создать продукт WooCommerce таким образом нельзя — для этого необходимо использовать соответствующее расширение «WooCommerce for Gato GraphQL».