Trabajando con
Trabajando conCustom Posts

Custom Posts

Usamos los campos customPost y customPosts para obtener datos de CPT, tanto para CPTs que están mapeados al esquema (como Post y Page) como para los que no (como un CPT de algún plugin). Como los resultados pueden incluir entidades de distintos tipos, estos campos devuelven el tipo CustomPostUnion.

Tipo CustomPostUnion

Campos de Custom Post en el esquema

Gato GraphQL hace una clara distinción entre cuándo un custom post es un "custom post", y no directamente un "post".

Por ejemplo, se puede añadir un comentario a un post, pero también a una página y a un CPT, por lo que el tipo Comment tiene el campo customPost: CustomPostUnion! para recuperar la entidad donde se añadió el comentario, en lugar del campo post: Post!.

Tipo Comment

Por eso también el campo customPosts recibe el argumento customPostTypes en lugar de postTypes.

CPTs mapeados al esquema

Hay CPTs que han sido mapeados al esquema (como Post y Page para representar los CPTs "post" y "page"). En este caso, la consulta se resolverá usando el tipo GraphQL correspondiente para ese CPT.

Al obtener resultados de un union type, necesitamos especificar los campos a recuperar mediante fragments. Estos pueden evaluarse sobre la interfaz CustomPost, que está implementada por todos los tipos de CPT, o sobre cada tipo individual, como Post o Page.

En la consulta de abajo, obtenemos custom posts con los CPTs "post" y "page". Mostramos sus campos a través de 3 fragments, que evalúan si la entidad implementa CustomPost, o es de tipo Post o 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
  }
}

CPTs no mapeados al esquema

Cuando un CPT aún no ha sido mapeado al esquema (como "attachment", "revision" o "nav_menu_item", o cualquier CPT instalado por algún plugin), seguimos usando los campos customPost y customPosts, y debemos pasar el nombre del CPT correspondiente bajo el argumento de campo filter.customPostTypes.

Como sus tipos no existen en el esquema, sus datos se recuperarán mediante el tipo GenericCustomPost, que contiene todas las propiedades comunes a los CPTs (title, content, excerpt, date, etc.).

Custom Post genérico

En la consulta de abajo, obtenemos custom posts para una variedad de CPTs:

query {
  customPosts(
    filter:{
      customPostTypes: [
        "page",
        "nav_menu_item",
        "wp_block",
        "wp_global_styles"
      ]
    }
  ) {
    ... on CustomPost {
      id
      title
      customPostType
      status
    }
    __typename
  }
}

Permitir el acceso a Custom Post Types

Los CPTs deben ser explícitamente autorizados para poder consultarse, como se explica en la guía Permitir el acceso a Custom Post Types.

Consultar custom posts

Los tipos GraphQL para CPTs que han sido mapeados al esquema (como "post" => Post y "page" => Page) se incorporan directamente en CustomPostUnion.

Para cualquier CPT que no haya sido modelado en el esquema (como "attachment", "revision" o "nav_menu_item", o cualquier CPT instalado por algún plugin), sus datos se accederán mediante el tipo GenericCustomPost.

Indicamos los CPTs a recuperar mediante el argumento de campo filter.customPostTypes, que recibe una lista de cadenas, con los nombres de CPT tal como están definidos en WordPress (como "post", "page", etc.). Por ejemplo:

query {
  customPosts(
    filter: { customPostTypes: ["some-custom-cpt"] }
  ) {
    ... on CustomPost {
      id
      title
    }
  }
}

Esta consulta recupera entradas de varios CPTs:

query {
  customPosts(
    filter: {
      customPostTypes: [
        "post",
        "page",
        "attachment",
        "nav_menu_item",
        "custom_css",
        "revision"
      ],
      status: [
        publish,
        inherit,
        auto_draft
      ]
    }
  ) {
    id
    title
    content
    status
    customPostType
    __typename
  }
}

Como todos los Custom Posts implementan la interfaz CustomPost, podemos recuperar datos de CustomPostUnion usando una referencia a un fragment o un inline fragment:

query {
  comments {
    id
    date
    content
    customPost {
      __typename
      ...on CustomPost {
        id
        title
        url
      }
    }
  }
}

Si sabemos que el comentario fue añadido a un post, también podemos consultar campos específicos del Post:

query {
  comments {
    id
    date
    content
    customPost {
      __typename
      ...on CustomPost {
        id
        title
        url
      }
      ...on Post {
        categoryNames
      }
    }
  }
}

Filtrar CPTs por una taxonomía personalizada

Un custom post type puede tener taxonomías personalizadas (etiquetas y categorías) asociadas. Por ejemplo, un CPT "product" puede tener asociadas la taxonomía de categoría "product-cat" y la taxonomía de etiqueta "product-tag".

Podemos filtrar resultados por estas taxonomías asociadas, mediante los inputs tags y categories en el input filter.

En la consulta de abajo, obtenemos custom posts filtrando por categoría:

query {
  customPosts(
    filter: {
      categories: {
        includeBy: {
          ids: [26, 28]
        }
        taxonomy: "product-cat"
      }
    }
  ) {
    ... on CustomPost {
      id
      title
    }
    ... on GenericCustomPost {
      categories(taxonomy: "product-cat") {
        id
      }
    }
  }
}

Obtener datos personalizados de CPT

Usando GenericCustomPost, solo podemos solicitar aquellos campos que son comunes a todos los CPTs; no se soporta obtener datos personalizados de algún CPT (como obtener los datos de precio para un CPT personalizado "product").

Para obtener datos personalizados de CPT, en su lugar, necesitamos crear los resolvers correspondientes, en código PHP, para mapear el CPT al esquema:

  • Crear un tipo Product
  • Adjuntarle un campo price

Ahora, el tipo CustomPostUnion (devuelto por Root.customPosts) resolverá todas las entradas de este CPT al tipo 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
    }
  }
}

Adicionalmente podemos crear el campo Root.products: [Product!], y usarlo directamente:

query {
  products {
    __typename # Product
    id
    title
    status
    price # custom field
  }
}

Mutar datos personalizados de CPT

En cuanto a los CPTs que no requieren campos adicionales sobre los del tipo Post, puedes usar tanto las mutaciones createCustomPost como updateCustomPost sin miedo ni reservas.

Por ejemplo, un CPT MyPortfolio que use los campos estándar title y content, y no tenga campos adicionales, puede gestionarse completamente mediante estas mutaciones.

Esta consulta crea una entrada para el 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
      }
    }
  }
}

Esta consulta actualiza el título y el contenido para ese mismo 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
      }
    }
  }
}

Los custom post types proporcionados por plugins de terceros pueden necesitar ser creados (y posiblemente actualizados también) únicamente por el plugin correspondiente.

Esto es porque pueden tener sus datos personalizados (ya sea en wp_postmeta o en una tabla propietaria) que también necesitan ser añadidos, y de los que Gato GraphQL no es consciente.

Para gestionar estos CPTs apropiadamente, debe crearse una integración correspondiente entre ese plugin y Gato GraphQL, para proporcionar el mapeo de todos los campos del CPT.

Por ejemplo, podemos usar el campo Root.updateCustomPost para traducir y actualizar el título y contenido de un producto de WooCommerce (es decir, del CPT Product). Sin embargo, no podemos crear un producto de WooCommerce; para eso, debemos usar la correspondiente extensión "WooCommerce for Gato GraphQL".