Ottenere dati a struttura dinamica
In WordPress possiamo recuperare livelli annidati di dati, cioè entità che contengono elementi figli dello stesso tipo. Ad esempio, un menu contiene elementi che possono avere sottoelementi, e questi sottoelementi possono a loro volta contenere sottoelementi, e così via per diversi livelli. Allo stesso modo, un commento può avere risposte che possono, a loro volta, avere risposte.
Vediamo come lavorare con i menu in GraphQL. Il recupero dei dati del menu in GraphQL implica interrogare gli elementi all'interno del menu per tutti i diversi livelli. Ad esempio, nella query qui sotto, il menu ha 3 livelli, e usiamo il fragment MenuItemProps per recuperare gli stessi campi (id, label e url) per tutti gli elementi del menu a tutti i livelli:
query GetMenu {
menu(by: { id: 176 }) {
id
items {
...MenuItemProps
children {
...MenuItemProps
children {
...MenuItemProps
}
}
}
}
}
fragment MenuItemProps on MenuItem {
id
label
url
}Come si può notare, il numero di livelli si riflette nella query GraphQL. Poiché il menu dell'applicazione ha 3 livelli, la query GraphQL ha 3 livelli di annidamento.
Tuttavia, in WordPress la creazione del menu non è decisa in anticipo, ma viene configurata dall'amministratore del sito tramite la schermata Menu (cioè quando non si usa un "block theme"), e memorizzata nel database:

Questo presenta un problema: quando si aggiunge un livello extra al menu tramite l'interfaccia utente, dobbiamo aggiungere anche un livello extra alla query GraphQL, altrimenti il nuovo livello non verrà visualizzato sul sito.
Ci sono 2 modi per affrontare questo problema. Il più semplice consiste nel creare la query GraphQL recuperando più livelli di quelli necessari inizialmente, in modo da avere margine per continuare ad aggiungere livelli in seguito. Ad esempio, se l'applicazione ha bisogno di 3 livelli, la query GraphQL potrebbe comunque recuperare i dati per 6 (o 10 o 20) livelli, dandoci spazio sufficiente per espandere il menu fino a raggiungere il limite:
query GetMenu {
menu(by: { id: 176 }) {
id
items {
...MenuItemProps
children {
...MenuItemProps
children {
...MenuItemProps
children {
...MenuItemProps
children {
...MenuItemProps
children {
...MenuItemProps
}
}
}
}
}
}
}
}
fragment MenuItemProps on MenuItem {
id
label
url
}La seconda soluzione consiste nell'usare il campo Menu.itemDataEntries che produrrà un JSONObject strutturato con l'intero insieme dei dati del menu, inclusi tutti i livelli e sottolivelli:
query GetMenu {
menu(by: { id: 176 }) {
id
itemDataEntries
}
}La risposta a questa query è simile a questa:
{
"data": {
"menu": {
"id": 176,
"itemDataEntries": [
{
"id": 735,
"objectID": "6",
"parentID": null,
"label": "About The Tests",
"url": "https://mywpsite.com/about/",
"children": [
{
"id": 1451,
"objectID": "1133",
"parentID": "735",
"label": "Page Image Alignment",
"url": "https://mywpsite.com/about/page-image-alignment/",
"children": []
},
{
"id": 1452,
"objectID": "1134",
"parentID": "735",
"label": "Page Markup And Formatting",
"url": "https://mywpsite.com/about/page-markup-and-formatting/",
"children": []
}
]
},
{
"id": 739,
"objectID": "174",
"parentID": null,
"label": "Level 1",
"url": "https://mywpsite.com/level-1/",
"children": [
{
"id": 740,
"objectID": "173",
"parentID": "739",
"label": "Level 2",
"url": "https://mywpsite.com/level-1/level-2/",
"children": [
{
"id": 741,
"objectID": "172",
"parentID": "740",
"label": "Level 3",
"url": "https://mywpsite.com/level-1/level-2/level-3/",
"children": []
},
{
"id": 1453,
"objectID": "747",
"parentID": "740",
"label": "Level 3a",
"url": "https://mywpsite.com/level-1/level-2/level-3a/",
"children": []
},
{
"id": 1454,
"objectID": "748",
"parentID": "740",
"label": "Level 3b",
"url": "https://mywpsite.com/level-1/level-2/level-3b/",
"children": []
}
]
}
]
},
{
"id": 742,
"objectID": "146",
"parentID": null,
"label": "Lorem Ipsum",
"url": "https://mywpsite.com/lorem-ipsum/",
"children": []
}
]
}
}
}Questo metodo ha il vantaggio che i dati recuperati sono completamente guidati dall'interfaccia utente, riflettendo così com'è ciò che è memorizzato nel database, di modo che l'applicazione non avrebbe mai bisogno di essere aggiornata quando si aggiungono livelli extra al menu, che siano 2 o 20.
Tuttavia, questo metodo ha il chiaro svantaggio di farci perdere la tipizzazione forte di GraphQL: invece di ricevere un elemento di menu con campi fortemente tipizzati url come URL, label come String, objectID come ID, e così via, otteniamo un oggetto semplice che non verrà compreso dagli strumenti e dai client GraphQL, come Apollo client o Relay. Pertanto, non sfrutteremo realmente al massimo i vantaggi di GraphQL.
Recuperare i dati di configurazione di WordPress
Un altro problema si presenta quando dobbiamo recuperare entità che sono guidate dall'interfaccia utente e memorizzate nel database. È il caso delle opzioni in WordPress, dove i nomi delle opzioni vengono creati dinamicamente da temi e plugin, per cui non sono noti in anticipo al server GraphQL, e dei valori meta, che possono anche essere definiti da temi e plugin, e quindi non sono mappati per impostazione predefinita nello schema GraphQL.
Per questo motivo, lo schema prodotto da Gato GraphQL non codifica in modo rigido i nomi delle opzioni né i loro tipi, ma vi si accede tramite un campo optionValue (e anche optionValues e optionObjectValue) che riceve il nome dell'opzione e restituisce un valore di qualsiasi tipo integrato possibile (rappresentato da AnyBuiltInScalar):
type Root {
optionValue(name: String!): AnyBuiltInScalar
}Poiché non tutte le opzioni sono destinate a essere esposte tramite l'API, l'amministratore del sito deve aggiungerle esplicitamente alla lista di autorizzazione, sia tramite il loro nome completo sia tramite un'espressione regolare, nelle impostazioni del plugin:

Ora, la query può recuperare le opzioni presenti nella lista di autorizzazione:
{
siteURL: optionValue(name: "siteurl")
siteName: optionValue(name: "blogname")
siteDescription: optionValue(name: "blogdescription")
}Se c'è un'opzione aggiuntiva di cui l'applicazione ha bisogno, può essere resa immediatamente disponibile all'API semplicemente aggiungendo una voce corrispondente alla lista di autorizzazione nella pagina delle impostazioni.