Skip to content

Querying single pages

When we are querying a single page instead of a modular page, we do know which information we need exactly for that page and we will need to query it specifically.

To this end we use another barrel file that determines which single query should be added to the main query:

src/service/query/single/index.js
export const singles = ({ type, language, langParam }) => {
let singleToFetch;
switch (type) {
case "webinars":
singleToFetch = `{${webinar({ language, langParam })}}`;
break;
case "blogs":
singleToFetch = `{ ${blogs({ language })}}`;
break;
...
}
}

And this is how a single query file looks like:

src/service/query/single/security_concepts.js
import { asset, wysiwyg_simple } from "@utilities/groq";
import { cybersec_resource } from "@utilities/groq/reference";
import wysiwyg from "@utilities/groq/wysiwyg.js";
export const security_concepts = ({ language }) => {
return `
'typeName': *[_type == 'cybersecurity_glossary_names'][0]{'title' : security_concepts.${language} },
'title' : title.${language},
'hero_description': {${wysiwyg_simple({ name: "hero_description", language })}},
'description': {${wysiwyg("wysiwyg", language)}},
'related_resources': {
'title': *[_type == 'global_singles'][0]{'title':security_concepts_related_resources.${language} },
'resources' : *[_type == 'security_concepts' && _id != ^._id] | order(_createdAt desc)[0...5]{
${cybersec_resource({ language, isReference: false })}
}
},
'cybersec_breadcrumb': *[_type == 'cybersecurity_glossary_names'][0]{
'text' : cybersecurity_glossary.${language},
'url': cybersecurity_glossary_url->attributes.slug
},
'security_concepts_breadcrumb': *[_type == 'cybersecurity_glossary_names'][0]{
'text' : security_concepts.${language},
'url': security_concepts_url->attributes.slug
},
'share_on': *[_type == 'global_texts'][0]{'text' : share_on.${language} },
'to_top': *[_type == 'global_texts'][0]{'text' : to_top_text.${language} },
'socials_texts': {
'email_subject': *[_type == 'global_texts'][0]{'text' : share_email_subject.${language} },
'email_text': *[_type == 'global_texts'][0]{'text' : share_email_text.${language} },
'share_text': *[_type == 'global_singles'][0]{'text' : security_share_title.${language} },
},
'sidebar_titles' : *[_type == 'global_singles'][0]{
'cybersecurity_sidebar_title_anchors' : cybersecurity_sidebar_title_anchors.${language} ,
},
'featured_image': attributes{${asset({ localized: false, name: "featured_image", language })}}
`;
};

So we get specifically the information we need for each single page.

When we have our data, we will pass it on to a single page that will look something like this:

src/pages/[lang]/[preSlug]/security-concepts/[slug].astro
---
const searchParams = Astro.url.searchParams;
const isDraft = validatePreviewToken(searchParams.get('preview'));
const content = await the_query({ type:'security_concepts', language: lang, slug: `${preSlug}/security-concepts/${slug}` , isDraft});
const single = content?.general?.single;
if(!content){
return Astro.redirect('/404')
}
...
---
<Layout payload={{contentSeo : content?.general?.attributes?.settings, seo : content?.general?.siteSettings, language: lang, productSolutionName: content?.general?.product_code, pageTitle: content?.title}}>
<section>
<div class="f--container">
<div class="f--row">
<!-- CONTENT -->
<article class="f--col-7 f--col-desktop-9 f--col-tabletm-12 f--offset-1 f--offset-desktop-0 c--border-b c--border-b--tabletm-none u--pb-10 u--pb-tablets-8 u--pr-15 u--pr-desktop-2">
<HeroD
payload={{
language: lang,
customClass: 'c--hero-d--eighth',
breadcrumb: [
{
label: single?.cybersec_breadcrumb?.text,
option: 'target_self',
slug: single?.cybersec_breadcrumb?.url,
},
{
label: single?.security_concepts_breadcrumb?.text,
option: 'target_self',
slug: single?.security_concepts_breadcrumb?.url,
},
{
label: single?.title,
}
],
title: single?.title,
content: single?.hero_description
}}
/>
{ single?.featured_image?.url &&
<Asset
payload={{
...single.featured_image,
type: "Image",
decodingAsync: single.featured_image.decoding,
customClass: "c--media-a c--media-a--fifth u--mt-4 u--mb-2",
sizes: "(max-width: 580px) 95vw, (max-width: 1024px) 90vw, 75vw",
}}
/>
}
{
content?.general?.single?.description &&
<Content payload={{ content : content?.general?.single?.description, customClass : 'c--content-a u--pt-5 u--pt-tablets-4 u--pb-7 u--pb-tablets-5' }}></Content>
}
<div class="c--border-a c--hlist-a c--hlist-a--third u--pt-3 u--pb-8">
<p class="c--hlist-a__item f--font-f f--color-f">{single?.share_on.text}</p>
<Social01
payload={ socialShare }
/>
</div>
...
</div>
</section>
<BackTopA
payload={{
text: single?.to_top?.text || 'TO top'
}}
/>
</Layout>

Notice how we send our type and slug here to retrieve the single page we need:

const content = await the_query({
type: "security_concepts",
language: lang,
slug: `${preSlug}/security-concepts/${slug}`,
isDraft,
});

So each piece of data goes directly from content.general.single into the HTML template.