From 7a21596320de13398b31af89287152cb6648545a Mon Sep 17 00:00:00 2001 From: soumojit-D48 Date: Mon, 19 Jan 2026 18:30:31 +0530 Subject: [PATCH 1/2] refactor: implement GraphQL fragments for WordPress API queries - Created centralized fragment library in graphql-fragments.ts - Refactored all API queries to use reusable fragments - Improved maintainability and consistency across queries --- lib/api.ts | 369 ++++++++------------------------------- lib/graphql-fragments.ts | 115 ++++++++++++ 2 files changed, 184 insertions(+), 300 deletions(-) create mode 100644 lib/graphql-fragments.ts diff --git a/lib/api.ts b/lib/api.ts index 53464470..8eba91b9 100644 --- a/lib/api.ts +++ b/lib/api.ts @@ -1,4 +1,13 @@ -export const maxDuration = 300; // This can run Vercel Functions for a maximum of 300 seconds +import { + AUTHOR_FIELDS_FRAGMENT, + POST_PREVIEW_FRAGMENT, + FULL_POST_FRAGMENT, + PAGINATION_INFO_FRAGMENT, + FEATURED_IMAGE_FRAGMENT, + CATEGORY_FIELDS_FRAGMENT, +} from './graphql-fragments'; + +export const maxDuration = 300; export const dynamic = 'force-dynamic'; const API_URL = process.env.WORDPRESS_API_URL || process.env.NEXT_PUBLIC_WORDPRESS_API_URL @@ -70,7 +79,7 @@ export async function getAllTags() { `, { variables: { - first: 100, // Adjust as needed + first: 100, after: endCursor, }, } @@ -88,32 +97,13 @@ export async function getAllTags() { export async function getAllPostsFromTags(tagName: String, preview) { const data = await fetchAPI( ` + ${POST_PREVIEW_FRAGMENT} + query AllPosts($tagName: String!) { posts(first: 100, where: { orderby: { field: DATE, order: DESC }, tag: $tagName }) { edges { node { - title - excerpt - slug - date - featuredImage { - node { - sourceUrl - } - } - author { - node { - name - } - } - ppmaAuthorName - categories { - edges { - node { - name - } - } - } + ...PostPreviewFields } } } @@ -139,35 +129,19 @@ export async function getAllPosts() { while (hasNextPage) { const data = await fetchAPI( ` + ${POST_PREVIEW_FRAGMENT} + ${PAGINATION_INFO_FRAGMENT} + query AllPosts($after: String) { posts(first: 50, after: $after, where: { orderby: { field: DATE, order: DESC } }) { edges { node { - title - excerpt - slug - date - postId - featuredImage { - node { - sourceUrl - } - } - author { - node { - name - } - } - ppmaAuthorName - categories { - edges { - node { - name - } - } - } + ...PostPreviewFields } } + pageInfo { + ...PaginationInfo + } } } `, @@ -210,15 +184,14 @@ export async function getContent(postId: number) { export async function getReviewAuthorDetails(authorName) { const data = await fetchAPI( ` + ${AUTHOR_FIELDS_FRAGMENT} + query AuthorDetailsByName($authorName: String!) { users(where: { search: $authorName }) { edges { node { - name + ...AuthorFields email - avatar { - url - } description } } @@ -241,47 +214,18 @@ export async function getReviewAuthorDetails(authorName) { export async function getAllPostsForTechnology(preview = false, after = null) { const data = await fetchAPI( ` + ${POST_PREVIEW_FRAGMENT} + ${PAGINATION_INFO_FRAGMENT} + query AllPostsForCategory($after: String) { posts(first: 22, after: $after, where: { orderby: { field: DATE, order: DESC }, categoryName: "technology" }) { edges { node { - title - excerpt - slug - date - postId - featuredImage { - node { - sourceUrl - } - } - author { - node { - name - firstName - lastName - avatar { - url - } - } - } - ppmaAuthorName - categories { - edges { - node { - name - } - } - } - seo { - metaDesc - title - } + ...PostPreviewFields } } pageInfo { - hasNextPage - endCursor + ...PaginationInfo } } } @@ -305,6 +249,9 @@ export async function getAllPostsForCommunity(preview = false, after = null) { try { const data = await fetchAPI( ` + ${POST_PREVIEW_FRAGMENT} + ${PAGINATION_INFO_FRAGMENT} + query CommunityPosts($after: String) { posts( first: 22, @@ -316,43 +263,11 @@ export async function getAllPostsForCommunity(preview = false, after = null) { ) { edges { node { - title - excerpt - slug - date - postId - featuredImage { - node { - sourceUrl - } - } - author { - node { - name - firstName - lastName - avatar { - url - } - } - } - ppmaAuthorName - categories { - edges { - node { - name - } - } - } - seo { - metaDesc - title - } + ...PostPreviewFields } } pageInfo { - hasNextPage - endCursor + ...PaginationInfo } } } @@ -386,6 +301,9 @@ export async function getAllAuthors() { while (hasNextPage) { const data = await fetchAPI( ` + ${AUTHOR_FIELDS_FRAGMENT} + ${PAGINATION_INFO_FRAGMENT} + query getAllAuthors($after: String) { posts(first: 50, after: $after) { edges { @@ -394,19 +312,13 @@ export async function getAllAuthors() { ppmaAuthorImage author { node { - name - firstName - lastName - avatar { - url - } + ...AuthorFields } } } } pageInfo { - hasNextPage - endCursor + ...PaginationInfo } } } @@ -432,6 +344,10 @@ export async function getPostsByAuthor() { while (hasNextPage) { const data = await fetchAPI( ` + ${FEATURED_IMAGE_FRAGMENT} + ${CATEGORY_FIELDS_FRAGMENT} + ${PAGINATION_INFO_FRAGMENT} + query getPostsByAuthor($after: String) { posts(first: 50, after: $after) { edges { @@ -440,23 +356,12 @@ export async function getPostsByAuthor() { title ppmaAuthorName slug - featuredImage { - node { - sourceUrl - } - } - categories { - edges { - node { - name - } - } - } + ...FeaturedImageFields + ...CategoryFields } } pageInfo { - hasNextPage - endCursor + ...PaginationInfo } } } @@ -481,6 +386,8 @@ export async function getMoreStoriesForSlugs(tags, slug) { let data; const queryWithTags = ` + ${POST_PREVIEW_FRAGMENT} + query Posts($tags: [String!]) { posts( first: 7, @@ -488,14 +395,7 @@ export async function getMoreStoriesForSlugs(tags, slug) { ) { edges { node { - title - excerpt - slug - date - featuredImage { node { sourceUrl } } - author { node { name firstName lastName avatar { url } } } - ppmaAuthorName - categories { edges { node { name } } } + ...PostPreviewFields } } } @@ -503,18 +403,13 @@ export async function getMoreStoriesForSlugs(tags, slug) { `; const fallbackQuery = ` + ${POST_PREVIEW_FRAGMENT} + query PostsWithoutTags { posts(first: 7, where: { orderby: { field: DATE, order: DESC } }) { edges { node { - title - excerpt - slug - date - featuredImage { node { sourceUrl } } - author { node { name firstName lastName avatar { url } } } - ppmaAuthorName - categories { edges { node { name } } } + ...PostPreviewFields } } } @@ -545,42 +440,14 @@ export async function getMoreStoriesForSlugs(tags, slug) { export async function getPostsByAuthorName(authorName: string) { const data = await fetchAPI( - `query PostsByAuthorName($authorName: String!) { + ` + ${POST_PREVIEW_FRAGMENT} + + query PostsByAuthorName($authorName: String!) { posts(where: { authorName: $authorName }) { edges { node { - title - excerpt - slug - date - postId - featuredImage { - node { - sourceUrl - } - } - author { - node { - name - firstName - lastName - avatar { - url - } - } - } - ppmaAuthorName - categories { - edges { - node { - name - } - } - } - seo { - metaDesc - title - } + ...PostPreviewFields } } } @@ -609,55 +476,12 @@ export async function getPostAndMorePosts(slug, preview, previewData) { const isRevision = isSamePost && postPreview?.status === "publish"; const data = await fetchAPI( ` - fragment AuthorFields on User { - name - firstName - lastName - avatar { - url - } - } - - fragment PostFields on Post { - title - excerpt - slug - date - ppmaAuthorName - featuredImage { - node { - sourceUrl - } - } - author { - node { - ...AuthorFields - } - } - categories { - edges { - node { - name - } - } - } - tags { - edges { - node { - name - } - } - } - seo{ - metaDesc - title - } - } + ${FULL_POST_FRAGMENT} + ${AUTHOR_FIELDS_FRAGMENT} query PostBySlug($id: ID!, $idType: PostIdType!) { post(id: $id, idType: $idType) { - ...PostFields - content + ...FullPostFields ${ // Only some of the fields of a revision are considered as there are some inconsistencies isRevision @@ -684,8 +508,7 @@ export async function getPostAndMorePosts(slug, preview, previewData) { posts(first: 3, where: { orderby: { field: DATE, order: DESC } }) { edges { node { - ...PostFields - + ...FullPostFields } } } @@ -726,6 +549,9 @@ export async function fetchMorePosts( const data = await fetchAPI( ` + ${POST_PREVIEW_FRAGMENT} + ${PAGINATION_INFO_FRAGMENT} + query MorePosts($after: String, $first: Int!, $category: String!) { posts( first: $first, @@ -737,43 +563,11 @@ export async function fetchMorePosts( ) { edges { node { - title - excerpt - slug - date - postId - featuredImage { - node { - sourceUrl - } - } - author { - node { - name - firstName - lastName - avatar { - url - } - } - } - ppmaAuthorName - categories { - edges { - node { - name - } - } - } - seo { - metaDesc - title - } + ...PostPreviewFields } } pageInfo { - hasNextPage - endCursor + ...PaginationInfo } } } @@ -799,38 +593,13 @@ export async function getAllPostsForSearch(preview = false) { // It only fetches fields needed for the MoreStories card const data = await fetchAPI( ` + ${POST_PREVIEW_FRAGMENT} + query AllPostsForSearch { posts(first: 100, where: { orderby: { field: DATE, order: DESC } }) { edges { node { - title - excerpt - slug - date - postId - featuredImage { - node { - sourceUrl - } - } - author { - node { - name - firstName - lastName - avatar { - url - } - } - } - ppmaAuthorName - categories { - edges { - node { - name - } - } - } + ...PostPreviewFields } } } diff --git a/lib/graphql-fragments.ts b/lib/graphql-fragments.ts new file mode 100644 index 00000000..bb8db5ae --- /dev/null +++ b/lib/graphql-fragments.ts @@ -0,0 +1,115 @@ + +// Fragment library for WPGraphQL queries +// Reusable field definitions to keep queries DRY and consistent + +export const AUTHOR_FIELDS_FRAGMENT = ` + fragment AuthorFields on User { + name + firstName + lastName + avatar { + url + } + } +`; + +export const FEATURED_IMAGE_FRAGMENT = ` + fragment FeaturedImageFields on Post { + featuredImage { + node { + sourceUrl + } + } + } +`; + +export const CATEGORY_FIELDS_FRAGMENT = ` + fragment CategoryFields on Post { + categories { + edges { + node { + name + } + } + } + } +`; + +export const SEO_FIELDS_FRAGMENT = ` + fragment SEOFields on Post { + seo { + metaDesc + title + } + } +`; + +export const POST_PREVIEW_FRAGMENT = ` + ${AUTHOR_FIELDS_FRAGMENT} + + fragment PostPreviewFields on Post { + title + excerpt + slug + date + postId + ppmaAuthorName + ...FeaturedImageFields + author { + node { + ...AuthorFields + } + } + ...CategoryFields + ...SEOFields + } + + ${FEATURED_IMAGE_FRAGMENT} + ${CATEGORY_FIELDS_FRAGMENT} + ${SEO_FIELDS_FRAGMENT} +`; + +export const TAG_FIELDS_FRAGMENT = ` + fragment TagFields on Post { + tags { + edges { + node { + name + } + } + } + } +`; + +export const FULL_POST_FRAGMENT = ` + ${AUTHOR_FIELDS_FRAGMENT} + ${FEATURED_IMAGE_FRAGMENT} + ${CATEGORY_FIELDS_FRAGMENT} + ${TAG_FIELDS_FRAGMENT} + ${SEO_FIELDS_FRAGMENT} + + fragment FullPostFields on Post { + title + excerpt + slug + date + content + ppmaAuthorName + ...FeaturedImageFields + author { + node { + ...AuthorFields + } + } + ...CategoryFields + ...TagFields + ...SEOFields + } +`; + +export const PAGINATION_INFO_FRAGMENT = ` + fragment PaginationInfo on WPPageInfo { + hasNextPage + endCursor + } +`; From 4fe6551e20f944a1ef7c9e9dc036803ef787adc4 Mon Sep 17 00:00:00 2001 From: soumojit-D48 Date: Mon, 6 Apr 2026 20:55:43 +0530 Subject: [PATCH 2/2] fix: address Copilot review feedback on GraphQL fragments --- lib/api.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/api.ts b/lib/api.ts index 8eba91b9..23aa8675 100644 --- a/lib/api.ts +++ b/lib/api.ts @@ -477,7 +477,6 @@ export async function getPostAndMorePosts(slug, preview, previewData) { const data = await fetchAPI( ` ${FULL_POST_FRAGMENT} - ${AUTHOR_FIELDS_FRAGMENT} query PostBySlug($id: ID!, $idType: PostIdType!) { post(id: $id, idType: $idType) { @@ -508,7 +507,7 @@ export async function getPostAndMorePosts(slug, preview, previewData) { posts(first: 3, where: { orderby: { field: DATE, order: DESC } }) { edges { node { - ...FullPostFields + ...PostPreviewFields } } } @@ -590,7 +589,7 @@ export async function fetchMorePosts( // --- ADDED THIS FUNCTION FOR SEARCH --- export async function getAllPostsForSearch(preview = false) { // This query fetches ALL posts (up to 100) without a category filter - // It only fetches fields needed for the MoreStories card + // Uses PostPreviewFields which includes author, categories, and SEO data const data = await fetchAPI( ` ${POST_PREVIEW_FRAGMENT}