Created
May 19, 2025 17:08
-
-
Save jasonbahl/7da8e27c5fb5dce4a1f11715ead79a3f to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { GraphQLClient, gql } from 'graphql-request'; | |
import { SEED_QUERY } from '@/components/WPTemplateRouter/SEED_QUERY'; | |
import templates from '@/wp-templates/wp-templates.js'; | |
/** | |
* Fetches the seed node data from WordPress using the SEED_QUERY. | |
* | |
* @param {object} context - The context object. | |
* @param {string} context.uri - The URI of the node to fetch. | |
* @param {boolean} [context.isPreview=false] - Whether this is a preview request. | |
* @param {object} [context.previewData={}] - Preview data containing token/id. | |
* @returns {Promise<object|null>} The seed node data or null if not found/error. | |
*/ | |
export async function fetchSeedNodeData({ uri, isPreview = false, previewData = {} }) { | |
const endpoint = process.env.NEXT_PUBLIC_WORDPRESS_URL; | |
if (!endpoint) { | |
console.error('NEXT_PUBLIC_WORDPRESS_URL environment variable is not set.'); | |
// Returning null or throwing an error are options here | |
return null; | |
} | |
// TODO: Refine how preview ID and token are obtained if needed | |
const id = isPreview ? previewData?.id : 0; | |
const headers = isPreview ? { 'authorization': `Bearer ${previewData?.token}` } : {}; | |
const graphQLClient = new GraphQLClient(endpoint, { headers }); | |
try { | |
const data = await graphQLClient.request(SEED_QUERY, { uri, id, asPreview: isPreview }); | |
const seedNodeData = isPreview ? data?.contentNode : data?.nodeByUri; | |
if (!seedNodeData) { | |
console.log(`Seed node not found via fetchSeedNodeData for URI: ${uri}, Preview: ${isPreview}`); | |
return null; | |
} | |
return seedNodeData; | |
} catch (error) { | |
console.error(`Error in fetchSeedNodeData for URI: ${uri}, Preview: ${isPreview}`, error); | |
// Returning null signifies an error or not found state to getStaticProps | |
return null; | |
} | |
} | |
// Function to determine the template hierarchy based on seed node data | |
// Moved from WPTemplateRouter - now runs server-side in getStaticProps | |
export const getPossibleTemplates = (seedNode) => { | |
const templatesList = []; | |
if (!seedNode) { | |
return ['index']; // Fallback | |
} | |
// Note: Ensure these fields are available in your SEED_QUERY results | |
const { __typename, databaseId, slug, contentType, template, hPageTemplates, isFrontPage, isPostsPage } = seedNode; | |
// TODO: Add logic for CPT Archives, Taxonomies, Author pages, Search, 404 if needed | |
if (isFrontPage) { | |
templatesList.push('front-page'); | |
} else if (isPostsPage) { | |
templatesList.push('home'); | |
} | |
// --- Custom Condition for hPageTemplates --- START | |
const customHPagesTemplateSlug = hPageTemplates?.nodes?.[0]?.slug; | |
if (customHPagesTemplateSlug) { | |
templatesList.push(`h-page-template-${customHPagesTemplateSlug}`); | |
console.log(`[getPossibleTemplates] Added custom hPageTemplate: h-page-template-${customHPagesTemplateSlug}`); | |
} | |
// --- Custom Condition for hPageTemplates --- END | |
// Handle specific WP Templates assigned in the editor (Less priority than hPageTemplates) | |
const wpTemplateName = template?.templateName?.toLowerCase().replace(' ', '-'); | |
if (wpTemplateName && wpTemplateName !== 'default') { | |
templatesList.push(wpTemplateName); | |
} | |
const customTemplateSlug = hPageTemplates?.nodes?.[0]?.slug; | |
if (customTemplateSlug) { | |
templatesList.push(`page-${customTemplateSlug}`); | |
} | |
if (seedNode.isContentNode) { | |
const contentTypeSlug = contentType?.node?.name?.toLowerCase(); | |
if (slug) { | |
templatesList.push(`${contentTypeSlug}-${slug}`); | |
} | |
if (databaseId) { | |
templatesList.push(`${contentTypeSlug}-${databaseId}`); | |
} | |
if (contentTypeSlug) { | |
templatesList.push(`single-${contentTypeSlug}`); | |
} | |
templatesList.push('singular'); | |
} | |
// Handle Content Type Archives | |
if (__typename === 'ContentType') { | |
const contentTypeName = seedNode.name?.toLowerCase(); | |
if (contentTypeName) { | |
templatesList.push(`archive-${contentTypeName}`); | |
} | |
templatesList.push('archive'); | |
} | |
if (seedNode.isTermNode) { | |
const taxonomySlug = seedNode.taxonomyName?.toLowerCase(); | |
if (slug) { | |
templatesList.push(`taxonomy-${taxonomySlug}-${slug}`); | |
} | |
if (databaseId) { | |
templatesList.push(`taxonomy-${taxonomySlug}-${databaseId}`); | |
} | |
if (taxonomySlug) { | |
templatesList.push(`taxonomy-${taxonomySlug}`); | |
} | |
templatesList.push('taxonomy'); | |
templatesList.push('archive'); | |
} | |
templatesList.push('index'); | |
return [...new Set(templatesList)]; | |
}; | |
/** | |
* Fetches seed data, resolves the template key, and executes template-specific queries. | |
* | |
* @param {object} context - The context object from getStaticProps. | |
* @returns {Promise<{seedNodeData: object|null, templateKey: string, queryResults: object, isPreview: boolean}>} | |
*/ | |
export async function resolveTemplateData(context) { | |
const { previewData } = context; | |
const uri = '/' + (context.params?.wordpressNode || []).join('/'); | |
const isPreview = !!previewData?.token; | |
const endpoint = process.env.NEXT_PUBLIC_WORDPRESS_URL; | |
const headers = isPreview ? { 'authorization': `Bearer ${previewData?.token}` } : {}; | |
const graphQLClient = new GraphQLClient(endpoint, { headers }); | |
console.log(`[resolveTemplateData] Calculated URI: ${uri}`); | |
// Fetch initial seed data | |
const seedNodeData = await fetchSeedNodeData({ uri, isPreview, previewData }); | |
if (!seedNodeData) { | |
// Return null seed data; template resolution will fallback to 'index' | |
// No footerData to return here anymore | |
return { seedNodeData: null, templateKey: 'index', queryResults: {}, isPreview }; | |
} | |
// Determine the prioritized list of template keys | |
const possibleTemplateKeys = getPossibleTemplates(seedNodeData); | |
console.log(`[resolveTemplateData] Possible keys for URI ${context.params?.wordpressNode?.join('/') || '/'}:`, possibleTemplateKeys); | |
// Find the first *component* that exists for the possible keys | |
let TemplateComponent = null; | |
let templateKey = 'index'; // Default fallback key | |
for (const key of possibleTemplateKeys) { | |
if (templates[key]) { | |
TemplateComponent = templates[key]; | |
templateKey = key; | |
console.log(`[resolveTemplateData] Matched component for key: ${templateKey}`); | |
break; | |
} | |
} | |
// If no specific component found, fallback to index | |
if (!TemplateComponent) { | |
TemplateComponent = templates.index; | |
templateKey = 'index'; | |
console.log('[resolveTemplateData] No specific template matched, falling back to index.'); | |
} | |
// --- Execute template-specific queries --- START | |
let queryResults = {}; | |
if (TemplateComponent && typeof TemplateComponent.queries === 'object') { | |
console.log(`[resolveTemplateData] Executing queries for template: ${templateKey}`); | |
// graphQLClient already initialized above | |
const queryPromises = Object.entries(TemplateComponent.queries).map(async ([queryKey, queryConfig]) => { | |
if (!queryConfig || !queryConfig.query || typeof queryConfig.variables !== 'function') { | |
console.warn(`[resolveTemplateData] Invalid query config for key: ${queryKey} in template: ${templateKey}`); | |
return [queryKey, null]; // Store null for invalid configs | |
} | |
try { | |
const variables = queryConfig.variables(seedNodeData); | |
console.log(`[resolveTemplateData] Executing query: ${queryKey} with variables:`, variables); | |
const result = await graphQLClient.request(queryConfig.query, variables); | |
return [queryKey, result]; | |
} catch (error) { | |
console.error(`[resolveTemplateData] Error executing query ${queryKey} for template ${templateKey}:`, error); | |
return [queryKey, null]; // Store null on error | |
} | |
}); | |
const results = await Promise.all(queryPromises); | |
queryResults = Object.fromEntries(results.filter(([, result]) => result !== undefined)); | |
console.log(`[resolveTemplateData] Query results for ${templateKey}:`, queryResults); | |
} else { | |
console.log(`[resolveTemplateData] No queries defined for template: ${templateKey}`); | |
} | |
// --- Execute template-specific queries --- END | |
// Return seed node, template key, and results from template queries | |
return { seedNodeData, templateKey, queryResults, isPreview }; | |
} | |
/** | |
* Fetches only the data required for the main layout (Header/Footer). | |
* | |
* @returns {Promise<object>} Object containing keys like 'header', 'footer' with their query results. | |
*/ | |
export async function fetchLayoutData() { | |
const endpoint = process.env.NEXT_PUBLIC_WORDPRESS_URL; | |
if (!endpoint) { | |
console.error('NEXT_PUBLIC_WORDPRESS_URL environment variable is not set.'); | |
return {}; // Return empty object on error | |
} | |
const graphQLClient = new GraphQLClient(endpoint); | |
// Import queries directly here or pass them in if preferred | |
const { HEADER_QUERY } = await import('@/components/Header/Header'); | |
const { FOOTER_QUERY } = await import('@/components/Footer/Footer'); | |
let layoutQueryResults = {}; | |
try { | |
const headerResult = await graphQLClient.request(HEADER_QUERY); | |
layoutQueryResults.header = headerResult; | |
} catch (error) { | |
console.error('[fetchLayoutData] Error fetching Header data:', error); | |
layoutQueryResults.header = null; // Indicate error | |
} | |
try { | |
const footerResult = await graphQLClient.request(FOOTER_QUERY); | |
layoutQueryResults.footer = footerResult; | |
} catch (error) { | |
console.error('[fetchLayoutData] Error fetching Footer data:', error); | |
layoutQueryResults.footer = null; // Indicate error | |
} | |
return layoutQueryResults; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment