✨Discover storytelling in the AI age with Pixar's Matthew Luhn at Sanity Connect, May 8th—register now

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 }) => <span style={{backgroundColor:'lightblue'}}>{children}</span>;

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: () => '🔗',
    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” && 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" && 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}) => {
      const href = `/${mark.slug}`
      return <a href={href}>{children}</a>
    },
    link: ({mark, children}) => {
      // Read <https://css-tricks.com/use-target_blank/>
      const { blank, href } = mark
      return blank ?
        <a href={href} target="_blank" rel="noopener noreferer">{children}</a>
        : <a href={href}>{children}</a>
    }
  }
}
Apr 7, 2021, 1:33 AM
Works like a charm. 😄
Apr 7, 2021, 1:34 AM

Sanity– build remarkable experiences at scale

Sanity is a modern 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?