Add published user products to the storefront sitemap.
Expose /sitemap-user-products.xml when customer_products is enabled, invalidate on listing mutations, and proxy the new path from nginx provision scripts. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
fb04425df7
commit
0d9c2fd8ea
@@ -18,6 +18,7 @@ export type ResolvedSitemapConfig = {
|
||||
| 'video'
|
||||
| 'instruction'
|
||||
| 'workshop'
|
||||
| 'userProduct'
|
||||
>
|
||||
>;
|
||||
};
|
||||
|
||||
@@ -111,6 +111,9 @@ export function resolveSitemapConfig(
|
||||
DEFAULT_SITEMAP_PATH_TEMPLATES.instruction,
|
||||
workshop:
|
||||
stored?.templates?.workshop ?? DEFAULT_SITEMAP_PATH_TEMPLATES.workshop,
|
||||
userProduct:
|
||||
stored?.templates?.userProduct ??
|
||||
DEFAULT_SITEMAP_PATH_TEMPLATES.userProduct,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ export const DEFAULT_SITEMAP_PATH_TEMPLATES = {
|
||||
video: '/videos/{slug}',
|
||||
instruction: '/instructions/{slug}',
|
||||
workshop: '/workshops/{slug}',
|
||||
userProduct: '/user-products/{slug}',
|
||||
} as const;
|
||||
|
||||
export const WEBSITE_SITEMAP_CONFIG_PATH = '/meshkee/sitemap-config.json';
|
||||
@@ -27,6 +28,7 @@ export const SITEMAP_DYNAMIC_SECTIONS = [
|
||||
'videos',
|
||||
'instructions',
|
||||
'workshops',
|
||||
'userProducts',
|
||||
] as const;
|
||||
|
||||
export type SitemapDynamicSection = (typeof SITEMAP_DYNAMIC_SECTIONS)[number];
|
||||
|
||||
@@ -59,6 +59,15 @@ export class SitemapController {
|
||||
await this.sendDynamic(host, 'workshops', res);
|
||||
}
|
||||
|
||||
@Get('sitemap-user-products.xml')
|
||||
@Header('Cache-Control', 'public, max-age=900')
|
||||
async getUserProductsSitemap(
|
||||
@Param('host') host: string,
|
||||
@Res() res: Response,
|
||||
) {
|
||||
await this.sendDynamic(host, 'userProducts', res);
|
||||
}
|
||||
|
||||
@Get('robots.txt')
|
||||
@Header('Cache-Control', 'public, max-age=900')
|
||||
async getRobots(@Param('host') host: string, @Res() res: Response) {
|
||||
|
||||
@@ -41,6 +41,7 @@ const SECTION_MODULE: Record<SitemapDynamicSection, BusinessModuleId> = {
|
||||
videos: 'videos',
|
||||
instructions: 'instructions',
|
||||
workshops: 'workshops',
|
||||
userProducts: 'customer_products',
|
||||
};
|
||||
|
||||
const SECTION_FILE: Record<SitemapDynamicSection, string> = {
|
||||
@@ -50,6 +51,7 @@ const SECTION_FILE: Record<SitemapDynamicSection, string> = {
|
||||
videos: '/sitemap-videos.xml',
|
||||
instructions: '/sitemap-instructions.xml',
|
||||
workshops: '/sitemap-workshops.xml',
|
||||
userProducts: '/sitemap-user-products.xml',
|
||||
};
|
||||
|
||||
@Injectable()
|
||||
@@ -258,6 +260,14 @@ export class SitemapService {
|
||||
config.templates.workshop,
|
||||
),
|
||||
);
|
||||
case 'userProducts':
|
||||
return buildSitemapXml(
|
||||
await this.loadPublishedUserProducts(
|
||||
businessId,
|
||||
config.baseUrl,
|
||||
config.templates.userProduct,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -458,6 +468,33 @@ export class SitemapService {
|
||||
);
|
||||
}
|
||||
|
||||
private async loadPublishedUserProducts(
|
||||
businessId: bigint,
|
||||
baseUrl: string,
|
||||
template: string,
|
||||
): Promise<SitemapUrlEntry[]> {
|
||||
const rows = await this.prisma.userProduct.findMany({
|
||||
where: {
|
||||
businessId,
|
||||
status: ContentStatus.published,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
slug: true,
|
||||
updatedAt: true,
|
||||
},
|
||||
orderBy: [{ updatedAt: 'desc' }, { id: 'desc' }],
|
||||
});
|
||||
|
||||
return rows.map((row) =>
|
||||
this.toEntry(baseUrl, template, {
|
||||
id: row.id,
|
||||
slug: row.slug,
|
||||
updatedAt: row.updatedAt,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
private toEntry(
|
||||
baseUrl: string,
|
||||
template: string,
|
||||
|
||||
Reference in New Issue
Block a user