eddev
Snippets

Querying Specific Blocks

Select, split, and render only the block content you need

Use these patterns when a view or block needs a targeted block selection instead of every contentBlocks item.

For the broader data model, see Block Data, View Data, and Template Parts.

Pull One Block Type From Another Post

Use contentBlocks(include: [...]) when you want a specific block from related posts. Sol People uses this shape for a hero block that pulls only services/service-card blocks from Service posts.

query ServicesHero {
  block {
    hero_services_hero {
      theme
    }
  }
  services(where: { orderby: [{ field: MENU_ORDER, order: ASC }] }) {
    nodes {
      contentBlocks(include: ["services/service-card"], limit: 1)
    }
  }
}
import { ContentBlocks, defineBlock } from "eddev/blocks"

export default defineBlock("hero/services-hero", (props) => {
  const cards =
    props.services?.nodes
      .flatMap((service) => service?.contentBlocks ?? [])
      .filter(Boolean) ?? []

  return <ContentBlocks blocks={cards} />
})

include accepts block names, tags, flags, and wildcards. Add limit: 1 when you only expect one matching block per post.

Use exclude when related posts should render their body content but skip the block that is used somewhere else.

query ServicesArchive($postId: ID!) {
  page(id: $postId, idType: DATABASE_ID) {
    contentBlocks
  }
  services(where: { orderby: [{ field: MENU_ORDER, order: ASC }] }) {
    nodes {
      contentBlocks(exclude: ["services/service-card"])
    }
  }
}
import { ContentBlocks } from "eddev/blocks"
import { defineView } from "eddev/views"

export default defineView("archive-services", (props) => {
  return (
    <>
      <ContentBlocks blocks={props.page?.contentBlocks} />
      {props.services?.nodes.map((service, index) => (
        <ContentBlocks key={index} blocks={service?.contentBlocks} />
      ))}
    </>
  )
})

Pull One Page Header From A Known Page

When an archive or app-like route has a fixed CMS page backing its intro content, query that page by URI and include just the header block.

query ArchiveBlog {
  blogPosts(first: 9999, where: { orderby: [{ field: DATE, order: DESC }] }) {
    nodes {
      title
      uri
    }
  }
  page(id: "blog", idType: URI) {
    title
    contentBlocks(include: ["page/page-header"], limit: 1)
  }
}
import { ContentBlocks } from "eddev/blocks"
import { defineView } from "eddev/views"

export default defineView("archive-blog", (props) => {
  return (
    <>
      <ContentBlocks blocks={props.page?.contentBlocks} />
      {/* Render the listing UI below the page header. */}
    </>
  )
})

Split A Hero From The Rest

If the current page stores the hero in normal contentBlocks, find it in React and render the remainder separately.

import { ContentBlocks, SingleContentBlock } from "eddev/blocks"
import { defineView } from "eddev/views"

export default defineView("template-home", (props) => {
  const blocks = props.page?.contentBlocks ?? []
  const hero = blocks.find((block) => block.slug === "homepage/homepage-carousel")
  const rest = blocks.filter((block) => block.slug !== "homepage/homepage-carousel")

  return (
    <>
      {hero && <SingleContentBlock block={hero} />}
      <ContentBlocks blocks={rest} />
    </>
  )
})

Use this when the split is mostly presentational. If the split affects payload size or repeated related posts, prefer include and exclude in GraphQL.

Query A Template Part Subset

Use aliases plus contentBlocks filters when _app.graphql needs both a whole template part and a small subset.

query CommonData {
  templateParts {
    siteHeader {
      contentBlocks
    }
    headerButtons: siteHeader {
      contentBlocks(flattenExcluded: true, include: ["parts/header-button"])
    }
    siteFooter {
      contentBlocks
    }
  }
}
import { ContentBlocks } from "eddev/blocks"
import { useAppData } from "eddev/hooks"

export function MobileMenuButtons() {
  const blocks = useAppData((data) => data.templateParts?.headerButtons?.contentBlocks)

  return <ContentBlocks blocks={blocks} />
}

flattenExcluded: true is useful when the matching blocks may sit inside layout wrappers that you do not want to render.

On this page