Skip to content

Commit

Permalink
Make resolvers async to resolve internal links correctly (Fixed #193) (
Browse files Browse the repository at this point in the history
…#205)

* Make resolvers async to resolve internal links correctly
  • Loading branch information
mobeigi authored Oct 24, 2024
1 parent f6fc91d commit 65239ff
Show file tree
Hide file tree
Showing 14 changed files with 73 additions and 56 deletions.
34 changes: 18 additions & 16 deletions app/src/app/(frontend)/blog/[...slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ const getPayloadPostFromParams = ({ params }: { params: { slug: string[] } }) =>
const transformPostToBlogPostProps = (post: PayloadPost) =>
unstable_cache_safe(
async (): Promise<BlogPostProps | null> => {
const postMeta = mapPostToPostMeta(post);
const postMeta = await mapPostToPostMeta(post);
if (!postMeta) {
console.warn('postMeta should not be null.');
return null;
Expand Down Expand Up @@ -167,21 +167,23 @@ export const generateStaticParams = async () => {
pagination: false,
});

return payloadPosts.docs
.map((payloadPost) => {
let resolvedPostsUrl = resolvePostsUrl(payloadPost);
if (!resolvedPostsUrl) {
return null;
}
const stripPrefix = '/blog/';
if (resolvedPostsUrl.startsWith(stripPrefix)) {
resolvedPostsUrl = resolvedPostsUrl.slice(stripPrefix.length);
}
return {
slug: resolvedPostsUrl.split('/'),
};
})
.filter((obj) => obj !== null);
return (
await Promise.all(
payloadPosts.docs.map(async (payloadPost) => {
let resolvedPostsUrl = await resolvePostsUrl(payloadPost);
if (!resolvedPostsUrl) {
return null;
}
const stripPrefix = '/blog/';
if (resolvedPostsUrl.startsWith(stripPrefix)) {
resolvedPostsUrl = resolvedPostsUrl.slice(stripPrefix.length);
}
return {
slug: resolvedPostsUrl.split('/'),
};
}),
)
).filter((obj) => obj !== null);
};

/**
Expand Down
2 changes: 1 addition & 1 deletion app/src/app/(frontend)/blog/category/[...slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ const getData = (payloadCategory: PayloadCategory) =>
const blogPostMetas = (
await Promise.all(
payloadPosts.docs.map(async (post) => {
const postMeta = mapPostToPostMeta(post);
const postMeta = await mapPostToPostMeta(post);
if (!postMeta) {
console.warn('postMeta should not be null.');
return null;
Expand Down
2 changes: 1 addition & 1 deletion app/src/app/(frontend)/blog/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const getAllBlogPostMetas = unstable_cache_safe(
return (
await Promise.all(
posts.docs.map(async (post) => {
const postMeta = mapPostToPostMeta(post);
const postMeta = await mapPostToPostMeta(post);
if (!postMeta) {
console.warn('postMeta should not be null.');
return null;
Expand Down
2 changes: 1 addition & 1 deletion app/src/app/(frontend)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const Home = async () => {
const blogPostMetas = (
await Promise.all(
posts.docs.map(async (post) => {
const postMeta = mapPostToPostMeta(post);
const postMeta = await mapPostToPostMeta(post);
if (!postMeta) {
console.warn('postMeta should not be null.');
return null;
Expand Down
37 changes: 20 additions & 17 deletions app/src/app/sitemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,27 @@ const sitemap = async (): Promise<MetadataRoute.Sitemap> => {
pagination: false,
});

const blogPostSitemapEntries: MetadataRoute.Sitemap = payloadPosts.docs
.map((post) => {
const postUrl = resolvePostsUrl(post);
if (!postUrl) {
console.warn(`sitemap: postUrl for post ${post.id} should not be null.`);
return null;
}
const singleSiteMapEntry: MetadataRoute.Sitemap = [
{
url: joinUrl([BASE_URL, postUrl]),
lastModified: new Date(post.updatedAt),
changeFrequency: 'weekly',
priority: 0.7,
},
];
const blogPostSitemapEntries: MetadataRoute.Sitemap = (
await Promise.all(
payloadPosts.docs.map(async (post) => {
const postUrl = await resolvePostsUrl(post);
if (!postUrl) {
console.warn(`sitemap: postUrl for post ${post.id} should not be null.`);
return null;
}
const singleSiteMapEntry: MetadataRoute.Sitemap = [
{
url: joinUrl([BASE_URL, postUrl]),
lastModified: new Date(post.updatedAt),
changeFrequency: 'weekly',
priority: 0.7,
},
];

return singleSiteMapEntry;
})
return singleSiteMapEntry;
}),
)
)
.filter((obj) => obj !== null)
.flat();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const emailAfterNewCommentHook: CollectionAfterChangeHook = async ({ doc,

const textContent = extractTextContent(comment.content) || '';

const relativeCommentUrl = resolveCommentsUrl(comment);
const relativeCommentUrl = await resolveCommentsUrl(comment);
// TODO: Join the url below
const absoluteCommentUrl = BASE_URL + relativeCommentUrl;

Expand Down
11 changes: 8 additions & 3 deletions app/src/payload/collections/Comments/resolveUrl.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
import { Comment, Post } from '@/payload-types';
import { CollectionSlug, DataFromCollectionSlug } from 'payload';
import { resolvePostsUrl } from '@payload/collections/Posts/resolveUrl';
import { getCachedDocumentById } from '@/payload/utils/docs';

export const resolveCommentsUrl = (doc: DataFromCollectionSlug<CollectionSlug>): string | null => {
export const resolveCommentsUrl = async (doc: DataFromCollectionSlug<CollectionSlug>): Promise<string | null> => {
const comment = doc as Comment;
if (!comment) {
return null;
}

let post: Post;
if (typeof comment.post === 'number') {
return null;
const cachedPost = await getCachedDocumentById('posts', comment.post);
if (!cachedPost) {
return null;
}
post = cachedPost as Post;
} else {
post = comment.post;
}

const postUrl = resolvePostsUrl(post);
const postUrl = await resolvePostsUrl(post);
if (!postUrl) {
return null;
}
Expand Down
8 changes: 4 additions & 4 deletions app/src/payload/collections/Posts/hooks/revalidatePost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { resolvePostsUrl } from '../resolveUrl';
import { getDocByIdOrObject } from '@/utils/payload';
import { revalidateCategoryDetailPage } from '@payload/collections/Category/hooks/revalidateCategory';

export const revalidatePostPage = (req: PayloadRequest, doc: Post) => {
const postUrl = resolvePostsUrl(doc);
export const revalidatePostPage = async (req: PayloadRequest, doc: Post) => {
const postUrl = await resolvePostsUrl(doc);
if (postUrl) {
req.payload.logger.info(`Revalidating: ${postUrl}`);
revalidatePath(postUrl);
Expand Down Expand Up @@ -43,7 +43,7 @@ export const revalidatePost = async (req: PayloadRequest, doc: Post) => {
...doc,
category: docCategory,
};
revalidatePostPage(req, docWithCategory);
await revalidatePostPage(req, docWithCategory);

// Revalidate the last published post if it exists.
// This version is used instead of 'previousDoc' which may not be the last published version.
Expand All @@ -70,7 +70,7 @@ export const revalidatePost = async (req: PayloadRequest, doc: Post) => {
revalidateCategoryDetailPage(req, lastPublishedDocCategory);

// Previous blog post
revalidatePostPage(req, lastPublishedDoc);
await revalidatePostPage(req, lastPublishedDoc);
} else {
req.payload.logger.error(`Failed getting last published doc category for post with id: ${lastPublishedDoc.id}`);
}
Expand Down
9 changes: 7 additions & 2 deletions app/src/payload/collections/Posts/resolveUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,21 @@ import { Category, Post } from '@/payload-types';
import { CollectionSlug, DataFromCollectionSlug } from 'payload';
import { getCategorySlugComponents } from '@payload/collections/Category/resolveUrl';
import { joinUrl } from '@/utils/url';
import { getCachedDocumentById } from '@/payload/utils/docs';

export const resolvePostsUrl = (doc: DataFromCollectionSlug<CollectionSlug>): string | null => {
export const resolvePostsUrl = async (doc: DataFromCollectionSlug<CollectionSlug>): Promise<string | null> => {
const post = doc as Post;
if (!post.category || !post.slug) {
return null;
}

let category: Category;
if (typeof post.category === 'number') {
return null;
const cachedCategory = await getCachedDocumentById('category', post.category);
if (!cachedCategory) {
return null;
}
category = cachedCategory as Category;
} else {
category = post.category;
}
Expand Down
8 changes: 4 additions & 4 deletions app/src/payload/converter/customUrlResolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import { resolveCommentsUrl } from '@payload/collections/Comments/resolveUrl';
*/
export const customUrlResolvers: Record<
CollectionSlug,
(doc: DataFromCollectionSlug<CollectionSlug>) => string | null
(doc: DataFromCollectionSlug<CollectionSlug>) => Promise<string | null>
> = {
posts: (doc) => resolvePostsUrl(doc),
category: (doc) => resolveCategoryUrl(doc),
comments: (doc) => resolveCommentsUrl(doc),
posts: async (doc) => await resolvePostsUrl(doc),
category: (doc) => Promise.resolve(resolveCategoryUrl(doc)),
comments: async (doc) => await resolveCommentsUrl(doc),
users: () => {
throw new Error('Function not implemented.');
},
Expand Down
4 changes: 2 additions & 2 deletions app/src/payload/converter/reactnode/link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { customUrlResolvers } from '../customUrlResolvers';
import { CollectionSlug, DataFromCollectionSlug } from 'payload';

export const LinkReactNodeConverter: ReactNodeConverter<SerializedLinkNode> = {
converter({ converters, node, parent }) {
async converter({ converters, node, parent }) {
const children = convertLexicalNodesToReactNode({
converters,
lexicalNodes: node.children,
Expand Down Expand Up @@ -36,7 +36,7 @@ export const LinkReactNodeConverter: ReactNodeConverter<SerializedLinkNode> = {

if (doc && relationTo && relationTo in customUrlResolvers) {
const resolveUrl = customUrlResolvers[relationTo];
const url = resolveUrl(doc);
const url = await resolveUrl(doc);
if (!url) {
return <span>Failed to resolve url for collection: {relationTo}</span>;
}
Expand Down
2 changes: 2 additions & 0 deletions app/src/payload/utils/docs/getDocument.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use server';

import { getPayloadHMR } from '@payloadcms/next/utilities';
import { CollectionSlug } from 'payload';
import config from '@payload-config';
Expand Down
4 changes: 2 additions & 2 deletions app/src/payload/utils/redirects/payloadRedirect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,9 @@ export const payloadRedirect = async ({ currentUrl }: PayloadRedirectProps): Pro
}
const resolveUrlFn = customUrlResolvers[redirect.to.reference.relationTo];

let targetDocUrl = null;
let targetDocUrl: string | null = null;
try {
targetDocUrl = resolveUrlFn(doc);
targetDocUrl = await resolveUrlFn(doc);
} catch (e) {
const error = e as Error;
console.error(`Redirect for url '${absoluteUrl}' encountered error during resolveUrl. ${error.message}`);
Expand Down
4 changes: 2 additions & 2 deletions app/src/utils/payload/mapPostToPostMeta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { BlogPostPostMeta, Category } from '@/types/blog';
/**
* Maps Payload blog post to post meta.
*/
export const mapPostToPostMeta = (payloadPost: PayloadPost): BlogPostPostMeta | null => {
export const mapPostToPostMeta = async (payloadPost: PayloadPost): Promise<BlogPostPostMeta | null> => {
if (!payloadPost.publishedAt || !payloadPost.category || !payloadPost.slug) {
console.warn('Required blog post fields are not provided or are invalid.', payloadPost);
return null;
Expand All @@ -26,7 +26,7 @@ export const mapPostToPostMeta = (payloadPost: PayloadPost): BlogPostPostMeta |
url: categoryUrl,
};

const blogPostUrl = resolvePostsUrl(payloadPost);
const blogPostUrl = await resolvePostsUrl(payloadPost);
if (!blogPostUrl) {
return null;
}
Expand Down

0 comments on commit 65239ff

Please sign in to comment.