Работа с
Работа сCustom Posts

Custom Posts

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

Тип CustomPostUnion

Поля Custom Post в схеме

Gato GraphQL чётко разграничивает, когда пользовательская запись является «custom post», а не просто «post».

Например, комментарий можно добавить к посту, но также к странице и к CPT, поэтому тип Comment имеет поле customPost: CustomPostUnion! для получения сущности, к которой был добавлен комментарий, вместо поля post: Post!.

Тип Comment

Именно поэтому поле 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 Post

В запросе ниже мы получаем 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».