Biblioteca de queries
Biblioteca de queriesDistribuir contenido desde un upstream a múltiples sitios WordPress downstream

Distribuir contenido desde un upstream a múltiples sitios WordPress downstream

Supongamos que una empresa de medios tiene una red de sitios WordPress para diferentes regiones, y cada noticia se publica en un sitio o no, solo si es adecuada para esa región.

Para esta situación, tiene sentido implementar una arquitectura donde:

  • Todo el contenido se publica (y se edita) en un único sitio WordPress upstream, que actúa como la única fuente de verdad del contenido
  • El contenido adecuado se distribuye (pero no se edita) en cada uno de los sitios WordPress regionales downstream

Esta consulta satisface esta arquitectura: el sitio WordPress upstream debe tener activas las extensiones relevantes de Gato GraphQL, mientras que los sitios downstream solo necesitan tener el plugin gratuito de Gato GraphQL.

La consulta se ejecuta en el sitio WordPress upstream para sincronizar el contenido de la entrada actualizada con los sitios downstream relevantes, utilizando el slug de la entrada como identificador común entre los sitios.

Incluye lógica transaccional, de modo que cuando la actualización falle en cualquier sitio downstream, ya sea porque la petición HTTP falló (como cuando el servidor está caído) o porque la consulta GraphQL produjo errores (como si no hay ninguna entrada con el slug proporcionado), la mutación se revierte en todos los sitios downstream.

Ten en cuenta que los dominios downstream se proporcionan mediante la propiedad meta "downstream_domains" de la entrada, que contiene un array con los dominios de los sitios downstream a los que se debe distribuir la entrada. Si esta propiedad meta no existe, entonces se obtiene la opción "downstream_domains" de la tabla wp_options, que contiene la lista de todos los dominios downstream.

Después inicia sesión del usuario en cada uno de los sitios downstream (utilizando los mismos $username y $userPassword) y ejecuta la mutación para actualizar el contenido de la entrada. Si algún sitio downstream produce un error, la mutación se revierte en todos los sitios downstream.

Esta consulta requiere que el endpoint tenga habilitadas las Mutaciones Anidadas.

query InitializeDynamicVariables
  @configureWarningsOnExportingDuplicateVariable(enabled: false)
{
  initVariablesWithFalse: _echo(value: false)
    @export(as: "requestProducedErrors")
    @export(as: "anyErrorProduced")
    @export(as: "hasDownstreamDomains")
    @remove
}
 
query GetCustomDownstreamDomains($postSlug: String!)
  @depends(on: "InitializeDynamicVariables")
{
  post(by: { slug: $postSlug }, status: any)
    @fail(
      message: "There is no post in the upstream site with the provided slug"
      data: {
        slug: $postSlug
      }
    )
  {
    customDownstreamDomains: metaValues(key: "downstream_domains")
      @export(as: "downstreamDomains")
 
    hasDefinedCustomDownstreamDomains: _notNull(value: $__customDownstreamDomains)
      @export(as: "hasDefinedCustomDownstreamDomains")
      @remove
 
    hasCustomDownstreamDomains: _notEmpty(value: $__customDownstreamDomains)
      @export(as: "hasDownstreamDomains")
  }
 
  isMissingPostInUpstream: _isNull(value: $__post)
    @export(as: "isMissingPostInUpstream")
}
 
query GetAllDownstreamDomains
  @depends(on: "GetCustomDownstreamDomains")
  @skip(if: $isMissingPostInUpstream)
  @skip(if: $hasDefinedCustomDownstreamDomains)
{
  allDownstreamDomains: optionValues(name: "downstream_domains")
    @export(as: "downstreamDomains")
 
  hasAllDownstreamDomains: _notEmpty(value: $__allDownstreamDomains)
    @export(as: "hasDownstreamDomains")
}
 
############################################################
# (By default) Append "/graphql" to the domain, to point
# to that site's GraphQL single endpoint
############################################################
query ExportDownstreamGraphQLEndpointsAndQuery(
  $endpointPath: String! = "/graphql"
)
  @depends(on: "GetAllDownstreamDomains")
  @skip(if: $isMissingPostInUpstream)
  @include(if: $hasDownstreamDomains)
{
  downstreamGraphQLEndpoints: _echo(value: $downstreamDomains)
    @underEachArrayItem(
      passValueOnwardsAs: "domain"
    )
      @strAppend(string: $endpointPath)
    @export(as: "downstreamGraphQLEndpoints")
 
  query: _echo(value: """
    
mutation LoginUserAndUpdatePost(
  $username: String!
  $userPassword: String!
  $postSlug: String!
  $postContent: String!
) {
  loginUser(by: {
    credentials: {
      usernameOrEmail: $username,
      password: $userPassword
    }
  }) {
    userID
  }
 
  post(by: { slug: $postSlug }, status: any)
    @fail(
      message: "There is no post in the downstream site with the provided slug"
      data: {
        slug: $postSlug
      }
    )
  {
    update(input: {
      contentAs: { html: $postContent },
    }) {
      status
      errors {
        __typename
        ...on ErrorPayload {
          message
        }
      }
      post {
        slug
        rawContent
      }
    }
  }
}
 
    """
  )
    @export(as: "query")
    @remove
}
 
query ExportSendGraphQLHTTPRequestInputs(
  $username: String!
  $userPassword: String!
  $postSlug: String!
  $newPostContent: String!
)
  @depends(on: "ExportDownstreamGraphQLEndpointsAndQuery")
  @skip(if: $isMissingPostInUpstream)
  @include(if: $hasDownstreamDomains)
{
  sendGraphQLHTTPRequestInputs: _echo(value: $downstreamGraphQLEndpoints)
    @underEachArrayItem(
      passValueOnwardsAs: "endpoint"
    )
      @applyField(
        name: "_echo",
        arguments: {
          value: {
            endpoint: $endpoint,
            query: $query,
            variables: [
              {
                name: "username",
                value: $username
              },
              {
                name: "userPassword",
                value: $userPassword
              },
              {
                name: "postSlug",
                value: $postSlug
              },
              {
                name: "postContent",
                value: $newPostContent
              }
            ]
          }
        },
        setResultInResponse: true
      )
    @export(as: "sendGraphQLHTTPRequestInputs")
    @remove
}
 
query SendGraphQLHTTPRequests
  @depends(on: "ExportSendGraphQLHTTPRequestInputs")
  @skip(if: $isMissingPostInUpstream)
  @include(if: $hasDownstreamDomains)
{
  downstreamGraphQLResponses: _sendGraphQLHTTPRequests(
    inputs: $sendGraphQLHTTPRequestInputs
  )
    @export(as: "downstreamGraphQLResponses")
 
  requestProducedErrors: _isNull(value: $__downstreamGraphQLResponses)
    @export(as: "requestProducedErrors")
    @export(as: "anyErrorProduced")
    @remove
}
 
query ExportGraphQLResponsesHaveErrors
  @depends(on: "SendGraphQLHTTPRequests")
  @skip(if: $isMissingPostInUpstream)
  @skip(if: $requestProducedErrors)
  @include(if: $hasDownstreamDomains)
{
  graphQLResponsesHaveErrors: _echo(value: $downstreamGraphQLResponses)    
    # Check if any GraphQL response has the "errors" entry
    @underEachArrayItem(
      passValueOnwardsAs: "response"
      affectDirectivesUnderPos: [1, 2]
    )
      @applyField(
        name: "_propertyIsSetInJSONObject"
        arguments: {
          object: $response
          by: {
            key: "errors"
          }
        }
        setResultInResponse: true
      )
    @export(as: "graphQLResponsesHaveErrors")
    @remove
}
 
query ValidateGraphQLResponsesHaveErrors
  @depends(on: "ExportGraphQLResponsesHaveErrors")
  @skip(if: $isMissingPostInUpstream)
  @skip(if: $requestProducedErrors)
  @include(if: $hasDownstreamDomains)
{
  anyGraphQLResponseHasErrors: _or(values: $graphQLResponsesHaveErrors)
    @export(as: "anyErrorProduced")
    @remove
}
 
query ExportRevertGraphQLHTTPRequestInputs(
  $username: String!
  $userPassword: String!
  $postSlug: String!
  $previousPostContent: String!
)
  @depends(on: "ValidateGraphQLResponsesHaveErrors")
  @include(if: $hasDownstreamDomains)
  @include(if: $anyErrorProduced)
{
  revertGraphQLHTTPRequestInputs: _echo(value: $downstreamGraphQLEndpoints)
    @underEachArrayItem(
      passValueOnwardsAs: "endpoint"
    )
      @applyField(
        name: "_echo",
        arguments: {
          value: {
            endpoint: $endpoint,
            query: $query,
            variables: [
              {
                name: "username",
                value: $username
              },
              {
                name: "userPassword",
                value: $userPassword
              },
              {
                name: "postSlug",
                value: $postSlug
              },
              {
                name: "postContent",
                value: $previousPostContent
              }
            ]
          }
        },
        setResultInResponse: true
      )
    @export(as: "revertGraphQLHTTPRequestInputs")
    @remove
}
 
query RevertGraphQLHTTPRequests
  @depends(on: "ExportRevertGraphQLHTTPRequestInputs")
  @skip(if: $isMissingPostInUpstream)
  @include(if: $hasDownstreamDomains)
  @include(if: $anyErrorProduced)
{
  revertGraphQLResponses: _sendGraphQLHTTPRequests(
    inputs: $sendGraphQLHTTPRequestInputs
  )
}
 
query DistributeContentFromUpstreamToMultipleDownstreamWPSites
  @depends(on: "RevertGraphQLHTTPRequests")
{
  id @remove
}