Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions next/src/components/core/Query/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ const queryContentNodes = gql`
$notIn: [ID]
$search: String
$contentTypes: [ContentTypeEnum]
$categoryIn: [ID]
$tagIn: [ID]
${configs.isMultilang ? '$language: LanguageCodeFilterEnum' : ''}
) {
contentNodes(
Expand All @@ -63,6 +65,8 @@ const queryContentNodes = gql`
search: $search
stati: PUBLISH
contentTypes: $contentTypes
categoryIn: $categoryIn
tagIn: $tagIn
${configs.isMultilang ? 'language: $language' : ''}
}
) {
Expand Down Expand Up @@ -224,6 +228,12 @@ export const getData = async (
const postType = attrs?.query?.postType;
const contentTypes = postType ? [postType.toUpperCase()] : null;

// Scope the loop to the current term archive (Tag/Category page) when one is
// in context, so the query returns only that term's posts.
const term = context?.term ?? null;
const categoryIn = term?.taxonomy === 'category' ? [term.databaseId] : null;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@charl0tee Il faudrait avoir une constante qui défini les noms de nos catégories, extraire dans une fonction, + ajouter une doc dans le readme pour ça

const tagIn = term?.taxonomy === 'tag' ? [term.databaseId] : null;

const variables = {
first: perPage,
offset,
Expand All @@ -232,6 +242,8 @@ export const getData = async (
notIn,
search,
contentTypes,
categoryIn,
tagIn,
...(configs.isMultilang
? { language: lang ? lang.toUpperCase() : 'ALL' }
: {}),
Expand Down
18 changes: 18 additions & 0 deletions next/src/components/templates/Category/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { gql } from '@/utils';

import { languageFields, translationsFields } from '@/lib/fragments';

export const slug = 'category';

export const fragment = gql`
fragment categoryFragment on Category {
id: databaseId
title: name
uri
fseTemplate {
slug
}
${languageFields}
${translationsFields}
}
`;
18 changes: 18 additions & 0 deletions next/src/components/templates/Tag/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { gql } from '@/utils';

import { languageFields, translationsFields } from '@/lib/fragments';

export const slug = 'tag';

export const fragment = gql`
fragment tagFragment on Tag {
id: databaseId
title: name
uri
fseTemplate {
slug
}
${languageFields}
${translationsFields}
}
`;
4 changes: 3 additions & 1 deletion next/src/components/templates/data.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export * as archiveData from './Archive/data';
export * as categoryData from './Category/data';
export * as singlePageData from './SinglePage/data';
export * as singlePostData from './SinglePost/data';
export * as singlePostData from './SinglePost/data';
export * as tagData from './Tag/data';
1 change: 1 addition & 0 deletions next/src/lib/format-blocks-json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export default async function formatBlocksJSON(
lang?: string | null;
page?: number;
baseUri?: string;
term?: BlockDataContext['term'];
}
) {
/**
Expand Down
4 changes: 4 additions & 0 deletions next/src/lib/get-block-final-component-props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export default function getBlockFinalComponentProps(
lang?: string | null;
page?: number;
baseUri?: string;
term?: BlockDataContext['term'];
}
): Promise<BlockPropsType> {
return new Promise(async (res) => {
Expand Down Expand Up @@ -105,6 +106,7 @@ const getAttributes = (
lang?: string | null;
page?: number;
baseUri?: string;
term?: BlockDataContext['term'];
}
) =>
new Promise(async (res) => {
Expand Down Expand Up @@ -135,6 +137,7 @@ const getAttributes = (
getData(fetchAPI, attributes, options?.lang ?? null, {
page: options?.page,
baseUri: options?.baseUri,
term: options?.term,
innerBlocks,
}).then(
(data = {}) => {
Expand All @@ -157,6 +160,7 @@ const getInnerBlocks = (
lang?: string | null;
page?: number;
baseUri?: string;
term?: BlockDataContext['term'];
}
) =>
new Promise((res, rej) => {
Expand Down
54 changes: 49 additions & 5 deletions next/src/lib/get-node-by-uri.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import fseTemplatesData from '@/lib/fse/fse-templates-and-parts.json';

const templatesData: any = _templatesData;

const { archiveData, singlePageData, singlePostData } = templatesData;
const { archiveData, categoryData, singlePageData, singlePostData, tagData } =
templatesData;

/**
* NOTE: in preview, the `uri` could be in fact the ID (i.e. a draft doesn't have a slug/uri yet)
Expand Down Expand Up @@ -109,21 +110,26 @@ export default async function getNodeByURI(

node.fullUri = uri;

// On a term archive (Tag/Category), expose the current term so query loops
// inside the archive template scope their posts to it at request time.
const term = getTermContext(node);

if (blockEnrichment) {
const { blocksJSON, templateData, templateBlocks } =
await Promise.allSettled([
formatBlocksJSON(
previewDraft
? (node.preview?.node?.blocksJSON ?? '')
: (node?.blocksJSON ?? ''),
{ lang, page: routePage, baseUri: uri }
{ lang, page: routePage, baseUri: uri, term }
),
getTemplateData(node),
enrichTemplateBlocks(
getTemplateBlocks(node?.fseTemplate?.slug),
lang,
routePage,
uri
uri,
term
),
])
.then(([bProm, tProm, tbProm]) => ({
Expand Down Expand Up @@ -206,6 +212,18 @@ const types = [
fields: 'singlePageFragment',
translatable: true,
},
{
type: 'Category',
fragment: categoryData.fragment,
fields: 'categoryFragment',
translatable: true,
},
{
type: 'Tag',
fragment: tagData.fragment,
fields: 'tagFragment',
translatable: true,
},
{
type: 'Post',
fragment: singlePostData.fragment,
Expand Down Expand Up @@ -277,6 +295,26 @@ for (const key in templatesData) {
}
}

// Maps a resolved node's `__typename` to its WPGraphQL taxonomy handle. Only
// term archives (Tag/Category) qualify — single posts/pages and ContentType
// (post-type) archives have no current term to scope a query loop by.
const TERM_TAXONOMIES: Record<string, string> = {
Tag: 'tag',
Category: 'category',
};

const getTermContext = (node: any): BlockDataContext['term'] | undefined => {
const taxonomy = TERM_TAXONOMIES[node?.__typename];
if (!taxonomy) return undefined;

// The term fragments alias `id: databaseId`, so `node.id` is the WP DB id.
const databaseId =
typeof node?.id === 'number' ? node.id : Number.parseInt(node?.id, 10);
if (!Number.isFinite(databaseId)) return undefined;

return { taxonomy, databaseId };
};

const getTemplateData = async (node: any) => {
const type = `single-${node.__typename}`.toLowerCase();

Expand Down Expand Up @@ -340,13 +378,19 @@ const enrichTemplateBlocks = (
blocks: BlockPropsType[],
lang: string | null = null,
page = 1,
baseUri: string | undefined = undefined
baseUri: string | undefined = undefined,
term: BlockDataContext['term'] | undefined = undefined
): Promise<BlockPropsType[]> =>
blocks.length === 0
? Promise.resolve([])
: Promise.allSettled(
blocks.map((block) =>
getBlockFinalComponentProps(block, { lang, page, baseUri })
getBlockFinalComponentProps(block, {
lang,
page,
baseUri,
term,
})
)
).then(
(results) =>
Expand Down
10 changes: 10 additions & 0 deletions next/src/typings.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ type BlockDataContext = {
baseUri?: string;
/** The block's own `innerBlocks`, so `getData` can enrich/override children. */
innerBlocks?: Array<BlockPropsType>;
/**
* The taxonomy term being viewed on a term archive (Tag/Category), so query
* loops can scope their posts to the current term without a rebuild.
*/
term?: {
/** WPGraphQL taxonomy handle, e.g. "tag" | "category". */
taxonomy: string;
/** The term's WordPress database ID. */
databaseId: number;
};
};

type FseTemplateEntry = {
Expand Down
32 changes: 32 additions & 0 deletions wordpress/theme/includes/graphql/register-fse-templates.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,38 @@ function register_resolved_template_field() {
return ['slug' => $resolved->slug];
},
]);

register_graphql_field('Tag', 'fseTemplate', [
'type' => 'FseTemplateInfo',
'description' => _x('The FSE template used for this tag archive.', 'GraphQL field desc', 'supt'),
'resolve' => function ($source) {
$term = get_term($source->databaseId, 'post_tag');
if (! $term || is_wp_error($term)) return null;

$hierarchy = ["tag-{$term->slug}", "tag-{$term->term_id}", 'tag', 'archive'];
$resolved = resolve_block_template('tag', $hierarchy, '');

if (! $resolved) return null;

return ['slug' => $resolved->slug];
},
]);

register_graphql_field('Category', 'fseTemplate', [
'type' => 'FseTemplateInfo',
'description' => _x('The FSE template used for this category archive.', 'GraphQL field desc', 'supt'),
'resolve' => function ($source) {
$term = get_term($source->databaseId, 'category');
if (! $term || is_wp_error($term)) return null;

$hierarchy = ["category-{$term->slug}", "category-{$term->term_id}", 'category', 'archive'];
$resolved = resolve_block_template('category', $hierarchy, '');

if (! $resolved) return null;

return ['slug' => $resolved->slug];
},
]);
}

/**
Expand Down