Discussion of querying internal links in Sanity and using routes to separate pages for flexibility.

59 replies
Last updated: Apr 7, 2021
What I am hoping for is an object like this...
{
  "_key": "c371572bc417",
  "_type": "internalLink",
  "item": {
    "_ref": "532b3294-5c63-42bd-9157-174796b2f706",
    "_type": "reference"
  },
  "slug": "new-revolutionary-product"
}
Apr 7, 2021, 12:59 AM
i think you are overcomplicating it,
_type == "internalLink" => {
            ...,
            "slug": *[_type == "route" && page._ref == ^.item._ref]{slug}
          }
could simply be

_type == "internalLink" => {
            ...,
            "slug": item->slug.current
          }

Apr 7, 2021, 1:02 AM
theres no need to do ^ inside of a reference expansion here
Apr 7, 2021, 1:02 AM
unless i am missing part of your data structure somewhere
Apr 7, 2021, 1:02 AM
Thank you, I'll try this too.
Apr 7, 2021, 1:04 AM
This returns NULL for the value.
Apr 7, 2021, 1:05 AM
what does your internal link object look like in your text block?
Apr 7, 2021, 1:06 AM
[
  {
    "_key": "2fc431634c3b",
    "_type": "link",
    "href": "<https://bryanklein.com>"
  },
  {
    "_key": "c371572bc417",
    "_type": "internalLink",
    "item": {
      "_ref": "532b3294-5c63-42bd-9157-174796b2f706",
      "_type": "reference"
    },
    "slug": null
  }
]
Apr 7, 2021, 1:07 AM
i mean in like the text block in sanity not the query
Apr 7, 2021, 1:07 AM
        annotations: [
          {
            name: 'internalLink',
            type: 'object',
            icon: AiOutlineLink,
            title: 'Internal link',
            fields: [
              {
                name: 'reference',
                type: 'reference',
                title: 'Reference',
                to: [
                  { type: 'page' },
                  { type: 'product' }
                ]
              },
              {
                name: 'linkType',
                title: 'Link Type',
                type: "string",
                options: {
                  list: [
                    { title: "Button", value: "button" },
                    { title: "Text", value: "text" },
                    { title: "Text + Arrow", value: "text-arrow" }
                  ],
                  layout: "dropdown"
                }
              }
            ]
          }, 
Apr 7, 2021, 1:07 AM
example
Apr 7, 2021, 1:07 AM
The schema for it?
Apr 7, 2021, 1:07 AM
yeah the text schema
Apr 7, 2021, 1:08 AM
import React from 'react';

const InternalLinkRender = ({ children }) =&gt; &lt;span style={{backgroundColor:'lightblue'}}&gt;{children}&lt;/span&gt;;

export default {
  title: 'Internal Link',
  name: 'internalLink',
  type: 'object',
  description: 'Locate a document you want to link to',
  fields: [
    {
      name: 'item',
      type: 'reference',
      to: [{ type: 'page' }]
    }
  ],
  blockEditor: {
    icon: () =&gt; '🔗',
    render: InternalLinkRender,
  },
};
Apr 7, 2021, 1:09 AM
what happens when you just try item-&gt; without the additional notation
Apr 7, 2021, 1:09 AM
It returns the page object that the 'item' refers to, but it doesn't have a slug value.
Apr 7, 2021, 1:10 AM
"slug":{
  "_createdAt": "2019-03-15T13:53:45Z",
  "_id": "532b3294-5c63-42bd-9157-174796b2f706",
  "_rev": "45Isps23253Yjlaq27Gb6c",
  "_type": "page",
  "_updatedAt": "2021-03-25T17:35:31Z",
  "content": [
    {
      "_key": "e37000e4aea5",
      "_type": "hero",
      "backgroundImage": {
        "_type": "image",
        "asset": {
          "_ref": "image-99daef03a3557b742dd9de05e3b75aba0ad2a402-1350x900-png",
          "_type": "reference"
        }
      },
      "heading": "We change industries!",
      "tagline": [
        {
          "_key": "2f2895682c0b",
          "_type": "block",
          "children": [
            {
              "_key": "2f2895682c0b0",
              "_type": "span",
              "marks": [],
              "text": "Disruptive implementations for the unknown future."
            }
          ],
          "markDefs": [],
          "style": "normal"
        }
      ]
    }
  ],
  "description": "This will change how you think about technology. We just need to figure out what it is first.",
  "openGraphImage": {
    "_type": "image",
    "asset": {
      "_ref": "image-99daef03a3557b742dd9de05e3b75aba0ad2a402-1350x900-png",
      "_type": "reference"
    }
  },
  "title": "Our upcoming groundbreaking service"
}
Apr 7, 2021, 1:11 AM
does that page… have a slug in the system?
Apr 7, 2021, 1:11 AM
Because in this example the slugs are stored in the 'routes' and not in the page.
Apr 7, 2021, 1:11 AM
gotcha so theres another level going on here
Apr 7, 2021, 1:12 AM
so you put all your pages in routes, and in the route you have a slug referencing the linked page
Apr 7, 2021, 1:12 AM
Exactly.
Apr 7, 2021, 1:12 AM
for stuff like this truthfully
 *[_type == “route” &amp;&amp; page._ref == ^.item._ref]
Apr 7, 2021, 1:13 AM
stick that in vision
Apr 7, 2021, 1:13 AM
with the proper item ref string
Apr 7, 2021, 1:13 AM
if it doesn’t work there something else might be going on
Apr 7, 2021, 1:13 AM
also i believe the ^ now fetches the proper parent and isn’t sub local anymore?
Apr 7, 2021, 1:14 AM
but i could be wrong depending on your api version
Apr 7, 2021, 1:14 AM
Apr 7, 2021, 1:14 AM
Apr 7, 2021, 1:14 AM
I was getting messed up with the {} thinking that I needed to wrap the projection with them.
Apr 7, 2021, 1:15 AM
(I am day 2 with groq, so please excuse my ignorance)
Apr 7, 2021, 1:15 AM
you’re doing something with routes i’ve never seen
Apr 7, 2021, 1:16 AM
so kudos to whatever is going on there interested to see the why/how of it all
Apr 7, 2021, 1:16 AM
Yeah, it's a bit funky. That's what they are doing in the Sanity+Next.js+Netlify starter.
Apr 7, 2021, 1:16 AM
i wonder how they handled typed routes for like products/blogs etc there but i guess i’ve never used that starter
Apr 7, 2021, 1:17 AM
dang that’s like super interesting, I’ll have to harass knut about this
Apr 7, 2021, 1:19 AM
this is potentially solving a like large complex data structure issue i have with a few projects. huge fan of hoping into this thread.
Apr 7, 2021, 1:20 AM
I was adding internal links into the rendering of the website and ran into this nested relationship. https://github.com/sanity-io/sanity-template-nextjs-landing-pages/blob/master/template/web/pages/LandingPage.js
Apr 7, 2021, 1:21 AM
yeah i mean this pattern absolutely adds complexity
Apr 7, 2021, 1:21 AM
but if wrangled seems very powerful
Apr 7, 2021, 1:22 AM
Where I have to start by querying the route and through it to the page I am on, then on down through the content/text/etc. to the links.
Apr 7, 2021, 1:22 AM
yeah you’ll need to ensure you have the reference type too
Apr 7, 2021, 1:22 AM
the example currently only has a page* but imagining other routes that needed different nested structure
Apr 7, 2021, 1:22 AM
Yep, I think you would need different queries for each datatype.
Apr 7, 2021, 1:23 AM
Right now it is using the
pageQuery
for page data. But I could see something like that for different elements.
Apr 7, 2021, 1:24 AM
so this:

"slug": *[_type == "route" &amp;&amp; page._ref == ^.item._ref][0].slug.current

Apr 7, 2021, 1:25 AM
you could open up to graph the type of the reference which is a deeper further nested query
Apr 7, 2021, 1:25 AM
Yeah, I would need to be careful with
page._ref
Apr 7, 2021, 1:25 AM
(depending on what you are after your life might be easier adding slugs to the page content type)
Apr 7, 2021, 1:27 AM
Yeah, I assume that this separation of the routes from the pages was to allow for some flexibility in what was presented in the sitemap, menus, etc.
Apr 7, 2021, 1:28 AM
Because there are toggles for that.
Apr 7, 2021, 1:29 AM
yeah
Apr 7, 2021, 1:29 AM
Thank you for jumping in to help on this. I spent too much time running into dead ends before I reached out.
Apr 7, 2021, 1:29 AM
Now I can do this in my serializer.
const serializers = {
  types: {
    embedHTML: EmbedHTML,
    figure: Figure
  },
  marks: {
    internalLink: ({mark, children}) =&gt; {
      const href = `/${mark.slug}`
      return &lt;a href={href}&gt;{children}&lt;/a&gt;
    },
    link: ({mark, children}) =&gt; {
      // Read <https://css-tricks.com/use-target_blank/>
      const { blank, href } = mark
      return blank ?
        &lt;a href={href} target="_blank" rel="noopener noreferer"&gt;{children}&lt;/a&gt;
        : &lt;a href={href}&gt;{children}&lt;/a&gt;
    }
  }
}
Apr 7, 2021, 1:33 AM
Works like a charm. 😄
Apr 7, 2021, 1:34 AM

Sanity– build remarkable experiences at scale

The Sanity Composable Content Cloud is the headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.

Was this answer helpful?