From 13a79be1b49d1f327160408ea763d1387e7d5bc1 Mon Sep 17 00:00:00 2001 From: sigma-andex <77549848+sigma-andex@users.noreply.github.com> Date: Wed, 8 Oct 2025 21:18:52 +0100 Subject: [PATCH 1/4] Test --- src/service.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/service.ts b/src/service.ts index 4c31154..29d9ece 100644 --- a/src/service.ts +++ b/src/service.ts @@ -333,6 +333,8 @@ export const WordpressServiceLayer = Layer.effect( const searchParams = new URLSearchParams(); searchParams.set("slug", slug); searchParams.set("status", postStatus); + // Request edit context to get raw content (Gutenberg blocks) + searchParams.set("context", "edit"); if (tagIds) { searchParams.set("tags", tagIds.join(",")); @@ -353,6 +355,16 @@ export const WordpressServiceLayer = Layer.effect( Authorization: `Basic ${Redacted.value(WORDPRESS_API_KEY)}`, }, }); + if (response.status !== 200) { + yield* Effect.logError("Failed to fetch post detail", { + status: response.status, + }); + const text = yield* response.text; + yield* Effect.logError(text); + return yield* Effect.fail( + new WordpressError({ message: "Failed to fetch post detail" }) + ); + } const json = yield* response.json; const posts = WpPostDetail.array().safeParse(json); if (!posts.success) { From 0308b6edce6f3a7ede4951bafdc0c3fd254deae0 Mon Sep 17 00:00:00 2001 From: sigma-andex <77549848+sigma-andex@users.noreply.github.com> Date: Wed, 8 Oct 2025 21:34:23 +0100 Subject: [PATCH 2/4] Test --- src/service.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/service.ts b/src/service.ts index 29d9ece..b409987 100644 --- a/src/service.ts +++ b/src/service.ts @@ -350,6 +350,9 @@ export const WordpressServiceLayer = Layer.effect( const url = new URL( `${WORDPRESS_API_URL}/wp-json/wp/v2/posts?${seoParams.toString()}` ); + yield* Effect.logDebug("Requesting post detail", { + url: url.toString(), + }); const response = yield* httpClient.get(url, { headers: { Authorization: `Basic ${Redacted.value(WORDPRESS_API_KEY)}`, From db300152df44a682748e410f2dee4332d9a5660b Mon Sep 17 00:00:00 2001 From: sigma-andex <77549848+sigma-andex@users.noreply.github.com> Date: Thu, 9 Oct 2025 10:30:04 +0100 Subject: [PATCH 3/4] Add gutenberg blocks --- src/service.ts | 10 +++++----- src/types.ts | 7 +++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/service.ts b/src/service.ts index b409987..1309f7d 100644 --- a/src/service.ts +++ b/src/service.ts @@ -61,10 +61,10 @@ const buildSeoSearchParams = (baseParams: URLSearchParams): URLSearchParams => { "_yoast_wpseo_metadesc,_yoast_wpseo_title,_yoast_wpseo_canonical,_yoast_wpseo_meta-robots-noindex,_yoast_wpseo_meta-robots-nofollow,_yoast_wpseo_opengraph-title,_yoast_wpseo_opengraph-description,_yoast_wpseo_opengraph-image,_yoast_wpseo_twitter-title,_yoast_wpseo_twitter-description,_yoast_wpseo_twitter-image,_rank_math_title,_rank_math_description,_rank_math_canonical_url,_rank_math_robots,_rank_math_facebook_title,_rank_math_facebook_description,_rank_math_facebook_image,_rank_math_twitter_title,_rank_math_twitter_description,_rank_math_twitter_image" ); - // Include additional fields that might contain SEO data + // // Include additional fields that might contain SEO data baseParams.set( "_fields", - "id,date,date_gmt,guid,modified,modified_gmt,slug,status,type,link,title,content,excerpt,author,featured_media,comment_status,ping_status,sticky,template,format,meta,categories,tags,class_list,_links,_embedded" + "id,content.rendered,content.raw,block_data,has_blocks,date,date_gmt,guid,modified,modified_gmt,slug,status,type,link,title,excerpt,author,featured_media,comment_status,ping_status,sticky,template,format,meta,categories,tags,class_list,_links,_embedded" ); return baseParams; @@ -73,7 +73,9 @@ const buildSeoSearchParams = (baseParams: URLSearchParams): URLSearchParams => { export const WordpressServiceLayer = Layer.effect( WordpressService, Effect.gen(function* () { - const WORDPRESS_API_URL = yield* Config.url("WORDPRESS_API_URL"); + const WORDPRESS_API_URL = yield* Config.url("WORDPRESS_API_URL").pipe( + Effect.map((url) => url.toString().replace(/\/$/, "")) + ); const WORDPRESS_USERNAME = yield* Config.string("WORDPRESS_USERNAME"); const WORDPRESS_PASSWORD = yield* Config.redacted("WORDPRESS_PASSWORD"); const WORDPRESS_STATUS = yield* Config.string("WORDPRESS_STATUS"); @@ -333,8 +335,6 @@ export const WordpressServiceLayer = Layer.effect( const searchParams = new URLSearchParams(); searchParams.set("slug", slug); searchParams.set("status", postStatus); - // Request edit context to get raw content (Gutenberg blocks) - searchParams.set("context", "edit"); if (tagIds) { searchParams.set("tags", tagIds.join(",")); diff --git a/src/types.ts b/src/types.ts index 6a849ba..d43320d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -111,9 +111,13 @@ export const WpPostDetail = z.object({ rendered: z.string(), }), content: z.object({ + raw: z.string().optional(), rendered: z.string(), }), + block_data: z.array(z.unknown()).optional(), + has_blocks: z.boolean().optional(), excerpt: z.object({ + raw: z.string().optional(), rendered: z.string(), }), date: z.string(), @@ -203,9 +207,12 @@ export const WpPageDetail = WpPageOverview.extend({ modified: z.string(), modified_gmt: z.string(), content: z.object({ + raw: z.string().optional(), rendered: z.string(), protected: z.boolean(), }), + has_blocks: z.boolean().optional(), + block_data: z.array(z.unknown()).optional(), author: z.number(), featured_media: z.number(), comment_status: z.string(), From 87b923070953880b1b1d9adff1e455e8c82f7092 Mon Sep 17 00:00:00 2001 From: sigma-andex <77549848+sigma-andex@users.noreply.github.com> Date: Thu, 9 Oct 2025 10:40:05 +0100 Subject: [PATCH 4/4] Add explicit types --- src/types.ts | 201 +++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 194 insertions(+), 7 deletions(-) diff --git a/src/types.ts b/src/types.ts index d43320d..4ba34f5 100644 --- a/src/types.ts +++ b/src/types.ts @@ -256,13 +256,200 @@ export const WpTag = z.object({ seo_meta: WpSeoMeta.optional(), }); -export type WPSeoMeta = z.infer; -export type WPPostOverview = z.infer; -export type WPPostDetail = z.infer; -export type WPPageOverview = z.infer; -export type WPPageDetail = z.infer; -export type WPCategory = z.infer; -export type WPTag = z.infer; +export type WPSeoMeta = { + meta_title?: string; + meta_description?: string; + canonical_url?: string; + robots?: string; + og_title?: string; + og_description?: string; + og_image?: string; + og_image_alt?: string; + og_url?: string; + og_type?: string; + og_site_name?: string; + og_locale?: string; + twitter_card?: string; + twitter_title?: string; + twitter_description?: string; + twitter_image?: string; + twitter_image_alt?: string; + twitter_site?: string; + twitter_creator?: string; + schema_type?: string; + schema_json?: string; + focus_keyword?: string; + readability_score?: number; + seo_score?: number; + breadcrumbs?: Array<{ + text: string; + url: string; + }>; +}; + +export type WPPostOverview = { + id: number; + title: { + rendered: string; + }; + excerpt: { + rendered: string; + }; + date: string; + slug: string; + author?: number; + featured_media?: number; + seo_meta?: WPSeoMeta; + _embedded?: { + author?: Array<{ + id: number; + name: string; + url?: string; + description?: string; + avatar_urls?: Record; + }>; + "wp:featuredmedia"?: Array<{ + id: number; + source_url: string; + alt_text?: string; + media_details?: { + width?: number; + height?: number; + file?: string; + sizes?: Record; + }; + }>; + }; +}; + +export type WPPostDetail = { + id: number; + title: { + rendered: string; + }; + content: { + raw?: string; + rendered: string; + }; + block_data?: unknown[]; + has_blocks?: boolean; + excerpt: { + raw?: string; + rendered: string; + }; + date: string; + modified?: string; + slug: string; + author?: number; + featured_media?: number; + seo_meta?: WPSeoMeta; + reading_time?: number; + word_count?: number; + _embedded?: { + author?: Array<{ + id: number; + name: string; + url?: string; + description?: string; + avatar_urls?: Record; + }>; + "wp:featuredmedia"?: Array<{ + id: number; + source_url: string; + alt_text?: string; + media_details?: { + width?: number; + height?: number; + file?: string; + sizes?: Record; + }; + }>; + }; +}; + +export type WPPageOverview = { + id: number; + date: string; + slug: string; + status: string; + type: "page"; + link: string; + title: { + rendered: string; + }; + excerpt: { + rendered: string; + protected: boolean; + }; + parent: number; + menu_order: number; + categories: number[]; + tags: number[]; + class_list: string[]; + seo_meta?: WPSeoMeta; +}; + +export type WPPageDetail = WPPageOverview & { + date_gmt: string; + guid: { + rendered: string; + }; + modified: string; + modified_gmt: string; + content: { + raw?: string; + rendered: string; + protected: boolean; + }; + has_blocks?: boolean; + block_data?: unknown[]; + author: number; + featured_media: number; + comment_status: string; + ping_status: string; + template: string; + meta: { + footnotes: string; + }; + seo_meta?: WPSeoMeta; + reading_time?: number; + word_count?: number; +}; + +export type WPCategory = { + id: number; + count: number; + description: string; + link: string; + name: string; + slug: string; + taxonomy: "category"; + parent: number; + meta: unknown[]; + seo_meta?: WPSeoMeta; +}; + +export type WPTag = { + id: number; + count: number; + description: string; + link: string; + name: string; + slug: string; + taxonomy: "post_tag"; + meta: unknown[]; + seo_meta?: WPSeoMeta; +}; export const WpStatus = z.enum(["draft", "publish"]); export type WPStatus = z.infer;