(Gutenberg) blokları
Gutenberg blok verilerini bu şekilde alabilirsiniz.
GraphQL şeması, tüm CustomPost türlerine (örneğin Post ve Page) aşağıdaki alanları ekler:
blocksblockDataItemsblockFlattenedDataItems
Classic Editor eklentisi etkinse bu alanlar kullanılamaz.
blocks
CustomPost.blocks: [BlockUnion!] alanı, custom post içinde yer alan tüm blokların listesini getirir.
blocks, GraphQL şemasına eşlenmiş Block türlerinin bir listesini döndürür. Bu Block türleri BlockUnion türünün parçasıdır ve Block arayüzünü uygular.
Eklenti, GenericBlock adlı tek bir Block türü uygular; bu tür herhangi bir bloğun verilerini almak için (attributes: JSONObject alanı aracılığıyla) yeterlidir.
Bu query:
{
post(by: { id: 1 }) {
blocks {
...on Block {
name
attributes
innerBlocks {
...on Block {
name
attributes
innerBlocks {
...on Block {
name
attributes
}
}
}
}
}
}
}
}
}...şu yanıtı üretecektir:
{
"data": {
"post": {
"blocks": [
{
"name": "core/gallery",
"attributes": {
"linkTo": "none",
"className": "alignnone",
"images": [
{
"url": "https://d.pr/i/zd7Ehu+",
"alt": "",
"id": "1706"
},
{
"url": "https://d.pr/i/jXLtzZ+",
"alt": "",
"id": "1705"
}
],
"ids": [],
"shortCodeTransforms": [],
"imageCrop": true,
"fixedHeight": true,
"sizeSlug": "large",
"allowResize": false
},
"innerBlocks": null
},
{
"name": "core/heading",
"attributes": {
"content": "List Block",
"level": 2
},
"innerBlocks": null
},
{
"name": "core/list",
"attributes": {
"ordered": false,
"values": "<li>List item 1</li><li>List item 2</li><li>List item 3</li><li>List item 4</li>"
},
"innerBlocks": null
},
{
"name": "core/heading",
"attributes": {
"className": "has-top-margin",
"content": "Columns Block",
"level": 2
},
"innerBlocks": null
},
{
"name": "core/columns",
"attributes": {
"isStackedOnMobile": true
},
"innerBlocks": [
{
"name": "core/column",
"attributes": {},
"innerBlocks": [
{
"name": "core/image",
"attributes": {
"id": 1701,
"className": "layout-column-1",
"url": "https://d.pr/i/fW6V3V+",
"alt": ""
},
"innerBlocks": null
}
]
},
{
"name": "core/column",
"attributes": {},
"innerBlocks": [
{
"name": "core/paragraph",
"attributes": {
"className": "layout-column-2",
"content": "Phosfluorescently morph intuitive relationships rather than customer directed human capital.",
"dropCap": false
},
"innerBlocks": null
}
]
}
]
},
{
"name": "core/heading",
"attributes": {
"content": "Columns inside Columns (nested inner blocks)",
"level": 2
},
"innerBlocks": null
},
{
"name": "core/columns",
"attributes": {
"isStackedOnMobile": true
},
"innerBlocks": [
{
"name": "core/column",
"attributes": {},
"innerBlocks": [
{
"name": "core/image",
"attributes": {
"id": 1701,
"className": "layout-column-1",
"url": "https://d.pr/i/fW6V3V+",
"alt": ""
},
"innerBlocks": null
},
{
"name": "core/columns",
"attributes": {
"isStackedOnMobile": true
},
"innerBlocks": [
{
"name": "core/column",
"attributes": {
"width": "33.33%"
},
"innerBlocks": [
{
"name": "core/heading",
"attributes": {
"fontSize": "large",
"content": "Life is so rich",
"level": 2
},
"innerBlocks": null
},
{
"name": "core/heading",
"attributes": {
"level": 3,
"content": "Life is so dynamic"
},
"innerBlocks": null
}
]
},
{
"name": "core/column",
"attributes": {
"width": "66.66%"
},
"innerBlocks": [
{
"name": "core/paragraph",
"attributes": {
"content": "This rhyming poem is the spark that can reignite the fires within you. It challenges you to go out and live your life in the present moment as a \u201chero\u201d and leave your mark on this world.",
"dropCap": false
},
"innerBlocks": null
},
{
"name": "core/columns",
"attributes": {
"isStackedOnMobile": true
},
"innerBlocks": [
{
"name": "core/column",
"attributes": {},
"innerBlocks": [
{
"name": "core/image",
"attributes": {
"id": 361,
"sizeSlug": "large",
"linkDestination": "none",
"url": "https://gato-graphql.lndo.site/wp-content/uploads/2022/05/graphql-voyager-public-1024x622.jpg",
"alt": ""
},
"innerBlocks": null
}
]
},
{
"name": "core/column",
"attributes": {},
"innerBlocks": null
},
{
"name": "core/column",
"attributes": {},
"innerBlocks": [
{
"name": "core/image",
"attributes": {
"id": 362,
"sizeSlug": "large",
"linkDestination": "none",
"url": "https://gato-graphql.lndo.site/wp-content/uploads/2022/05/namespaced-interactive-schema-1024x598.webp",
"alt": ""
},
"innerBlocks": null
}
]
}
]
}
]
}
]
}
]
}
]
}
]
}
}
}Block türleri için GraphQL şeması şu şekilde görünür:
interface Block {
name: String!
attributes: JSONObject
innerBlocks: [BlockUnion!]
contentSource: HTML!
}
type GenericBlock implements Block {
name: String!
attributes: JSONObject
innerBlocks: [BlockUnion!]
contentSource: HTML!
}
union BlockUnion = GenericBlockBlock alanları
Block arayüzü (ve dolayısıyla GeneralBlock türü) şu alanları içerir:
name, bloğun adını getirir:"core/paragraph","core/heading","core/image"vb.attributes, bloktan tüm öznitelikleri içeren bir JSON nesnesi getirir.innerBlocks,[BlockUnion!]değerini getirir; bu sayede iç bloklar içeren blok hiyerarşisinde gezinerek içeriğimizde kaç seviye derinlik varsa hepsinin verisini çekebiliriz.contentSource, bloğun (Gutenberg) HTML kaynak kodunu, öznitelikleri içeren yorum sınırlayıcıları dahil olmak üzere getirir. Ancak bu alan, veritabanında saklandığı haliyle aynı veriyi getirmez (bkz. #2346), dolayısıyla bu alanı dikkatli kullanın.
GeneralBlock türünü doğrudan getirme (BlockUnion yerine)
Şu anda blokları eşleyen yalnızca tek bir Block türü olduğundan (GeneralBlock), CustomPost.blocks (ve aynı şekilde Block.innerBlocks) bu türü BlockUnion türü yerine doğrudan getirmesi mantıklıdır.
Bunu, Settings sayfasındaki Blocks sekmesinde Use single type instead of union type? seçeneğini işaretleyerek yapabilirsiniz:

Ardından GraphQL query'si basitleşir:
{
post(by: { id: 1 }) {
blocks {
name
attributes
innerBlocks {
name
attributes
}
}
}
}Yanıt türünü BlockUnion olarak korumanın ileriye dönük uyumluluk açısından yararlı olduğunu unutmayın: Şemaya bloğa özgü türler eklemeye karar verirsek (aşağıdaki bölüme bakın), kırıcı değişiklik olmayacaktır.
Bloğa özgü türleri eşleme
JSONObject türü (Block.attributes tarafından getirilen) katı biçimde tiplenmemiştir: Özellikleri herhangi bir tür ve kardinaliteye sahip olabilir (String, Int, [Boolean!] vb.), bu nedenle her blok için bu bilgiyi bilmemiz ve her durumu istemci tarafında ele almamız gerekir.
Katı tipleme gerekiyorsa, PHP kodu aracılığıyla GraphQL şemasını genişletmemiz, bloğa özgü öznitelikleri alan olarak eşleyen bloğa özgü türler eklememiz ve bunları BlockUnion'ın bir parçası haline getirmemiz gerekir.
Örneğin, core/paragraph bloğunu String türünde content alanıyla eşleyen CoreParagraphBlock türünü ekleyebiliriz.
GraphQL şemasını nasıl genişleteceğinizi öğrenmek için GatoGraphQL/GatoGraphQL deposundaki belgelere bakın (şu an hazırlanmaktadır).
Blokları filtreleme
CustomPost.blocks alanı, include ve exclude olmak üzere iki özelliğe sahip filterBy bağımsız değişkenini içerir. Bunları, getirilen blokları blok adına göre filtrelemek için kullanabiliriz:
{
post(by: { id: 1 }) {
id
blocks(
filterBy: {
include: [
"core/heading",
"core/gallery"
]
}
) {
name
attributes
}
}
}Bu şunu üretecektir:
{
"data": {
"post": {
"blocks": [
{
"name": "core/gallery",
"attributes": {
"linkTo": "none",
"className": "alignnone",
"images": [
{
"url": "https://d.pr/i/zd7Ehu+",
"alt": "",
"id": "1706"
},
{
"url": "https://d.pr/i/jXLtzZ+",
"alt": "",
"id": "1705"
}
],
"ids": [],
"shortCodeTransforms": [],
"imageCrop": true,
"fixedHeight": true,
"sizeSlug": "large",
"allowResize": false
},
"innerBlocks": null
},
{
"name": "core/heading",
"attributes": {
"content": "List Block",
"level": 2
},
"innerBlocks": null
},
{
"name": "core/heading",
"attributes": {
"className": "has-top-margin",
"content": "Columns Block",
"level": 2
},
"innerBlocks": null
},
{
"name": "core/heading",
"attributes": {
"content": "Columns inside Columns (nested inner blocks)",
"level": 2
},
"innerBlocks": null
}
]
}
}
}core/heading türündeki tüm blokların dahil edilmediğine dikkat edin: core/column altına yerleştirilmiş olanlar, kendileri de hariç tutulan core/columns ve core/column bloklarından geçilmeden ulaşılamayacağından hariç tutulmuştur.
blocks alanının dezavantajları
blocks alanı şu dezavantajı beraberinde getirir: custom post içindeki tüm blok verilerini, iç blokların verilerini, onların iç bloklarını vb. almak için içerikte kaç iç içe blok seviyesi olduğunu bilmemiz ve bu bilgiyi GraphQL query'sine yansıtmamız gerekir.
Ya da bilmiyorsak, tüm verilerin çekileceğinden emin olmak için yeterli sayıda seviyeyle query'yi oluşturmamız gerekir.
Örneğin bu query, 7 seviyeye kadar iç blok iç içe geçmesini getirir:
{
post(by: { id: 1 }) {
blocks {
...BlockData
}
}
}
fragment BlockData on Block {
name
attributes
innerBlocks {
...on Block {
name
attributes
innerBlocks {
...on Block {
name
attributes
innerBlocks {
...on Block {
name
attributes
innerBlocks {
...on Block {
name
attributes
innerBlocks {
...on Block {
name
attributes
innerBlocks {
...on Block {
name
attributes
innerBlocks {
...on Block {
name
attributes
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}blockDataItems
blocks alanının tüm verileri (iç blokların verisi ve onların iç blokları dahil) getirme biçiminden kaynaklanan dezavantajı gidermek için CustomPost.blockDataItems alanı mevcuttur.
Bu alan, [BlockUnion] döndürmek yerine [JSONObject!] döndürür:
type CustomPost {
blockDataItems: [JSONObject!]
}Başka bir deyişle, varlıkların birbirleriyle ilişkilendirilip aralarında gezildiği tipik GraphQL yaklaşımını izlemek yerine, üst düzeydeki her Block varlığı kendi verilerini ve tüm alt öğelerinin verilerini tek bir JSONObject sonucu olarak üretir.
JSON nesnesi, bloğun özelliklerini (name ve attributes girdileri altında) ve iç bloklarının özelliklerini (innerBlocks girdisi altında) özyinelemeli biçimde içerir.
Örneğin şu query:
{
post(by: { id: 1 }) {
blockDataItems
}
}...şunu üretecektir:
{
"data": {
"post": {
"blockDataItems": [
{
"name": "core/gallery",
"attributes": {
"linkTo": "none",
"className": "alignnone",
"images": [
{
"url": "https://d.pr/i/zd7Ehu+",
"alt": "",
"id": "1706"
},
{
"url": "https://d.pr/i/jXLtzZ+",
"alt": "",
"id": "1705"
}
],
"ids": [],
"shortCodeTransforms": [],
"imageCrop": true,
"fixedHeight": true,
"sizeSlug": "large",
"allowResize": false
}
},
{
"name": "core/heading",
"attributes": {
"content": "List Block",
"level": 2
}
},
{
"name": "core/list",
"attributes": {
"ordered": false,
"values": "<li>List item 1</li><li>List item 2</li><li>List item 3</li><li>List item 4</li>"
}
},
{
"name": "core/heading",
"attributes": {
"className": "has-top-margin",
"content": "Columns Block",
"level": 2
}
},
{
"name": "core/columns",
"attributes": {
"isStackedOnMobile": true
},
"innerBlocks": [
{
"name": "core/column",
"attributes": {},
"innerBlocks": [
{
"name": "core/image",
"attributes": {
"id": 1701,
"className": "layout-column-1",
"url": "https://d.pr/i/fW6V3V+",
"alt": ""
}
}
]
},
{
"name": "core/column",
"attributes": {},
"innerBlocks": [
{
"name": "core/paragraph",
"attributes": {
"className": "layout-column-2",
"content": "Phosfluorescently morph intuitive relationships rather than customer directed human capital.",
"dropCap": false
}
}
]
}
]
},
{
"name": "core/heading",
"attributes": {
"content": "Columns inside Columns (nested inner blocks)",
"level": 2
}
},
{
"name": "core/columns",
"attributes": {
"isStackedOnMobile": true
},
"innerBlocks": [
{
"name": "core/column",
"attributes": {},
"innerBlocks": [
{
"name": "core/image",
"attributes": {
"id": 1701,
"className": "layout-column-1",
"url": "https://d.pr/i/fW6V3V+",
"alt": ""
}
},
{
"name": "core/columns",
"attributes": {
"isStackedOnMobile": true
},
"innerBlocks": [
{
"name": "core/column",
"attributes": {
"width": "33.33%"
},
"innerBlocks": [
{
"name": "core/heading",
"attributes": {
"fontSize": "large",
"content": "Life is so rich",
"level": 2
}
},
{
"name": "core/heading",
"attributes": {
"level": 3,
"content": "Life is so dynamic"
}
}
]
},
{
"name": "core/column",
"attributes": {
"width": "66.66%"
},
"innerBlocks": [
{
"name": "core/paragraph",
"attributes": {
"content": "This rhyming poem is the spark that can reignite the fires within you. It challenges you to go out and live your life in the present moment as a \u201chero\u201d and leave your mark on this world.",
"dropCap": false
}
},
{
"name": "core/columns",
"attributes": {
"isStackedOnMobile": true
},
"innerBlocks": [
{
"name": "core/column",
"attributes": {},
"innerBlocks": [
{
"name": "core/image",
"attributes": {
"id": 361,
"sizeSlug": "large",
"linkDestination": "none",
"url": "https://gato-graphql.lndo.site/wp-content/uploads/2022/05/graphql-voyager-public-1024x622.jpg",
"alt": ""
}
}
]
},
{
"name": "core/column",
"attributes": {}
},
{
"name": "core/column",
"attributes": {},
"innerBlocks": [
{
"name": "core/image",
"attributes": {
"id": 362,
"sizeSlug": "large",
"linkDestination": "none",
"url": "https://gato-graphql.lndo.site/wp-content/uploads/2022/05/namespaced-interactive-schema-1024x598.webp",
"alt": ""
}
}
]
}
]
}
]
}
]
}
]
}
]
}
]
}
}
}Blok veri öğelerini filtreleme
blocks'a benzer şekilde, blockDataItems de filterBy bağımsız değişkeni aracılığıyla getirilen blokların filtrelenmesine olanak tanır.
Bu query:
{
post(by: { id: 1 }) {
id
blockDataItems(
filterBy: {
include: [
"core/heading"
]
}
)
}
}...şunu üretecektir:
{
"data": {
"post": {
"blockDataItems": [
{
"name": "core/heading",
"attributes": {
"content": "List Block",
"level": 2
},
"innerBlocks": null
},
{
"name": "core/heading",
"attributes": {
"className": "has-top-margin",
"content": "Columns Block",
"level": 2
},
"innerBlocks": null
},
{
"name": "core/heading",
"attributes": {
"content": "Columns inside Columns (nested inner blocks)",
"level": 2
},
"innerBlocks": null
}
]
}
}
}blocks'a benzer şekilde, core/heading türündeki tüm blokların dahil edilmediğine dikkat edin: core/column altına yerleştirilmiş olanlar, kendileri de hariç tutulan core/columns ve core/column bloklarından geçilmeden ulaşılamayacağından hariç tutulmuştur.
blockFlattenedDataItems
blocks ve blockDataItems alanlarının her ikisi de filterBy bağımsız değişkeni aracılığıyla getirilen blokların filtrelenmesine olanak tanır. Her iki durumda da bir blok dahil etme koşulunu karşılıyorsa ancak karşılamayan bir bloğun içine yerleştirilmişse dışarıda bırakılır.
Ancak bazı durumlarda, bu blokların hiyerarşi içinde nerede olduğundan bağımsız olarak belirli bir türdeki tüm blokları custom post'tan almamız gerekir. Örneğin, bir blog gönderisindeki tüm görüntüleri almak için core/image türündeki tüm blokları dahil etmek isteyebiliriz.
Bu ihtiyacı karşılamak için CustomPost.blockFlattenedDataItems alanı mevcuttur. blocks ve blockDataItems alanlarından farklı olarak, blok hiyerarşisini tek bir seviyeye düzleştirir.
Bu query:
{
post(by: { id: 1 }) {
blockFlattenedDataItems
}
}...şunu üretecektir:
{
"data": {
"post": {
"blockFlattenedDataItems": [
{
"name": "core/gallery",
"attributes": {
"linkTo": "none",
"className": "alignnone",
"images": [
{
"url": "https://d.pr/i/zd7Ehu+",
"alt": "",
"id": "1706"
},
{
"url": "https://d.pr/i/jXLtzZ+",
"alt": "",
"id": "1705"
}
],
"ids": [],
"shortCodeTransforms": [],
"imageCrop": true,
"fixedHeight": true,
"sizeSlug": "large",
"allowResize": false
},
"innerBlockPositions": null,
"parentBlockPosition": null
},
{
"name": "core/heading",
"attributes": {
"content": "List Block",
"level": 2
},
"innerBlockPositions": null,
"parentBlockPosition": null
},
{
"name": "core/list",
"attributes": {
"ordered": false,
"values": "<li>List item 1</li><li>List item 2</li><li>List item 3</li><li>List item 4</li>"
},
"innerBlockPositions": null,
"parentBlockPosition": null
},
{
"name": "core/heading",
"attributes": {
"className": "has-top-margin",
"content": "Columns Block",
"level": 2
},
"innerBlockPositions": null,
"parentBlockPosition": null
},
{
"name": "core/columns",
"attributes": {
"isStackedOnMobile": true
},
"innerBlockPositions": [
5,
7
],
"parentBlockPosition": null
},
{
"name": "core/column",
"attributes": {},
"parentBlockPosition": 4,
"innerBlockPositions": [
6
]
},
{
"name": "core/image",
"attributes": {
"id": 1701,
"className": "layout-column-1",
"url": "https://d.pr/i/fW6V3V+",
"alt": ""
},
"parentBlockPosition": 5,
"innerBlockPositions": null
},
{
"name": "core/column",
"attributes": {},
"parentBlockPosition": 4,
"innerBlockPositions": [
8
]
},
{
"name": "core/paragraph",
"attributes": {
"className": "layout-column-2",
"content": "Phosfluorescently morph intuitive relationships rather than customer directed human capital.",
"dropCap": false
},
"parentBlockPosition": 7,
"innerBlockPositions": null
},
{
"name": "core/heading",
"attributes": {
"content": "Columns inside Columns (nested inner blocks)",
"level": 2
},
"innerBlockPositions": null,
"parentBlockPosition": null
},
{
"name": "core/columns",
"attributes": {
"isStackedOnMobile": true
},
"innerBlockPositions": [
11
],
"parentBlockPosition": null
},
{
"name": "core/column",
"attributes": {},
"parentBlockPosition": 10,
"innerBlockPositions": [
12,
13
]
},
{
"name": "core/image",
"attributes": {
"id": 1701,
"className": "layout-column-1",
"url": "https://d.pr/i/fW6V3V+",
"alt": ""
},
"parentBlockPosition": 11,
"innerBlockPositions": null
},
{
"name": "core/columns",
"attributes": {
"isStackedOnMobile": true
},
"parentBlockPosition": 11,
"innerBlockPositions": [
14,
17
]
},
{
"name": "core/column",
"attributes": {
"width": "33.33%"
},
"parentBlockPosition": 13,
"innerBlockPositions": [
15,
16
]
},
{
"name": "core/heading",
"attributes": {
"fontSize": "large",
"content": "Life is so rich",
"level": 2
},
"parentBlockPosition": 14,
"innerBlockPositions": null
},
{
"name": "core/heading",
"attributes": {
"level": 3,
"content": "Life is so dynamic"
},
"parentBlockPosition": 14,
"innerBlockPositions": null
},
{
"name": "core/column",
"attributes": {
"width": "66.66%"
},
"parentBlockPosition": 13,
"innerBlockPositions": [
18,
19
]
},
{
"name": "core/paragraph",
"attributes": {
"content": "This rhyming poem is the spark that can reignite the fires within you. It challenges you to go out and live your life in the present moment as a \u201chero\u201d and leave your mark on this world.",
"dropCap": false
},
"parentBlockPosition": 17,
"innerBlockPositions": null
},
{
"name": "core/columns",
"attributes": {
"isStackedOnMobile": true
},
"parentBlockPosition": 17,
"innerBlockPositions": [
20,
22,
23
]
},
{
"name": "core/column",
"attributes": {},
"parentBlockPosition": 19,
"innerBlockPositions": [
21
]
},
{
"name": "core/image",
"attributes": {
"id": 361,
"sizeSlug": "large",
"linkDestination": "none",
"url": "https://gato-graphql.lndo.site/wp-content/uploads/2022/05/graphql-voyager-public-1024x622.jpg",
"alt": ""
},
"parentBlockPosition": 20,
"innerBlockPositions": null
},
{
"name": "core/column",
"attributes": {},
"parentBlockPosition": 19,
"innerBlockPositions": null
},
{
"name": "core/column",
"attributes": {},
"parentBlockPosition": 19,
"innerBlockPositions": [
24
]
},
{
"name": "core/image",
"attributes": {
"id": 362,
"sizeSlug": "large",
"linkDestination": "none",
"url": "https://gato-graphql.lndo.site/wp-content/uploads/2022/05/namespaced-interactive-schema-1024x598.webp",
"alt": ""
},
"parentBlockPosition": 23,
"innerBlockPositions": null
}
]
}
}
}Bloklar artık iç içe geçmediğinden innerBlocks özniteliğinin ortadan kalktığına dikkat edin. Bunun yerine yanıt, blok hiyerarşisini yeniden oluşturmamıza olanak tanıyan iki öznitelik daha içerir:
parentBlockPosition: Döndürülen dizi içindeki üst bloğun konumu ya da üst düzey bir bloksanullinnerBlockPositions: Bloğun iç bloklarının döndürülen dizi içindeki konumlarını içeren bir dizi
Düzleştirilmiş blok veri öğelerini filtreleme
Blok hiyerarşisi düzleştirildiğine göre, core/heading ile filtreleme yapmak bu blokların tümünü üretecektir (başlangıçta hariç tutulan bir bloğun altına yerleştirilmiş olsalar bile).
Bu query:
{
post(by: { id: 1 }) {
id
blockFlattenedDataItems(
filterBy: {
include: [
"core/heading"
]
}
)
}
}...şunu üretecektir:
{
"data": {
"post": {
"blockFlattenedDataItems": [
{
"name": "core/heading",
"attributes": {
"content": "List Block",
"level": 2
}
},
{
"name": "core/heading",
"attributes": {
"className": "has-top-margin",
"content": "Columns Block",
"level": 2
}
},
{
"name": "core/heading",
"attributes": {
"content": "Columns inside Columns (nested inner blocks)",
"level": 2
}
},
{
"name": "core/heading",
"attributes": {
"fontSize": "large",
"content": "Life is so rich",
"level": 2
}
},
{
"name": "core/heading",
"attributes": {
"level": 3,
"content": "Life is so dynamic"
}
}
]
}
}
}Filtreleme yapılırken parentBlockPosition ve innerBlockPositions ek özniteliklerinin artık anlamlı olmadığından kaldırıldığına dikkat edin.