wpheadless-lib 1.1.6 → 1.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import { createPageEndpoints } from "wpjsapi-lib";
2
- import { getAbsoluteUrl, getFeaturedMedia, getPlainTextExcerpt, getYoastHead, } from "../../utils";
2
+ import { getAbsoluteUrl, getFeaturedMedia, getPlainTextExcerpt, getYoastHead, buildYoastRobotsMeta, } from "../../utils";
3
3
  import { buildLanguageAlternatesPerLanguage, buildAbsoluteLangUrl, getEntityLanguageId, withXDefault, getTranslationKey, } from "../../utils/hreflang";
4
4
  import { mapPageEntity } from "../../api/mappers";
5
5
  async function getLegalParentId(baseApiUrl, lang, langId) {
@@ -120,9 +120,11 @@ export function buildLegalMetadata({ page, slug, canonicalBase, useYoast = true,
120
120
  return baseMetadata;
121
121
  const yoast = getYoastHead(page, { siteUrl, wpApiUrl });
122
122
  const yoastImageUrl = yoast?.og_image?.[0]?.url || imageUrl;
123
+ const robots = buildYoastRobotsMeta(yoast?.robots);
123
124
  return {
124
125
  title: yoast?.title || page.title.rendered,
125
126
  description: yoast?.description || fallbackDescription,
127
+ ...(robots ? { robots } : {}),
126
128
  alternates: {
127
129
  canonical: url,
128
130
  ...(languageAlternates ? { languages: languageAlternates } : {}),
@@ -1,4 +1,4 @@
1
- import { getFeaturedMedia, getOgImageUrl, getPlainTextExcerpt, getYoastHead, } from "../../utils";
1
+ import { getFeaturedMedia, getOgImageUrl, getPlainTextExcerpt, getYoastHead, buildYoastRobotsMeta, } from "../../utils";
2
2
  import { getPostBySlug as getPostBySlugApi, listPostStaticParams, listPostsByTranslationKey, } from "../../api/posts";
3
3
  import { withXDefault } from "../../utils/hreflang";
4
4
  export async function getPostStaticParams({ baseApiUrl, lang, langId, }) {
@@ -72,9 +72,11 @@ export function buildPostMetadata({ post, canonical, useYoast = true, siteName,
72
72
  const yoast = getYoastHead(post, { siteUrl, wpApiUrl });
73
73
  if (!yoast)
74
74
  return fallbackMeta;
75
+ const robots = buildYoastRobotsMeta(yoast.robots);
75
76
  return {
76
77
  title: yoast.title || post.title.rendered,
77
78
  description: yoast.description || fallbackDescription,
79
+ ...(robots ? { robots } : {}),
78
80
  alternates: {
79
81
  canonical,
80
82
  ...(languageAlternates ? { languages: languageAlternates } : {}),
@@ -21,6 +21,12 @@ export default async function Footer({ menuId, wpApiUrl, wpUsername, wpAppPasswo
21
21
  const t = getTranslator(locale);
22
22
  const logoData = logo?.src ? logo : null;
23
23
  const logoAlt = logoData?.alt || siteName;
24
+ const logoStyle = logoData
25
+ ? {
26
+ ...(logoData.height ? { height: logoData.height } : {}),
27
+ ...(logoData.width ? { width: logoData.width } : {}),
28
+ }
29
+ : undefined;
24
30
  try {
25
31
  const parsedMenuId = parseInt(menuId);
26
32
  const itemsResponse = await menusApi.items.list({
@@ -34,5 +40,5 @@ export default async function Footer({ menuId, wpApiUrl, wpUsername, wpAppPasswo
34
40
  catch (e) {
35
41
  console.error("Error obteniendo menú footer:", e);
36
42
  }
37
- return (_jsx("footer", { className: styles.footer, children: _jsx("div", { className: "container", children: _jsxs("div", { className: styles.wrapper, children: [_jsxs("div", { className: styles.grid, children: [_jsxs("div", { children: [_jsx("h3", { className: styles.siteName, children: logoData ? (_jsx("img", { src: logoData.src, alt: logoAlt, className: styles.logoImage, width: logoData.width, height: logoData.height })) : (siteName) }), _jsx("p", { className: `${styles.muted} text-muted`, children: t("footer.tagline") })] }), menuItems.length > 0 && (_jsxs("nav", { "aria-label": t("footer.navAria"), className: styles.nav, children: [_jsx("h4", { className: styles.navTitle, children: t("footer.navTitle") }), _jsx("ul", { className: styles.list, children: menuItems.map((item) => (_jsx("li", { children: _jsx(Link, { href: convertWpUrl(item.url, wpApiUrl), className: "footer-link", children: item.title.rendered }) }, item.id))) })] }))] }), _jsxs("div", { className: styles.bottomBar, children: [_jsxs("span", { children: ["\u00A9 ", new Date().getFullYear(), " ", siteName] }), _jsx("span", { children: t("footer.noCookies") })] })] }) }) }));
43
+ return (_jsx("footer", { className: styles.footer, children: _jsx("div", { className: "container", children: _jsxs("div", { className: styles.wrapper, children: [_jsxs("div", { className: styles.grid, children: [_jsxs("div", { children: [_jsx("h3", { className: styles.siteName, children: logoData ? (_jsx("img", { src: logoData.src, alt: logoAlt, className: styles.logoImage, width: logoData.width, height: logoData.height, style: logoStyle })) : (siteName) }), _jsx("p", { className: `${styles.muted} text-muted`, children: t("footer.tagline") })] }), menuItems.length > 0 && (_jsxs("nav", { "aria-label": t("footer.navAria"), className: styles.nav, children: [_jsx("h4", { className: styles.navTitle, children: t("footer.navTitle") }), _jsx("ul", { className: styles.list, children: menuItems.map((item) => (_jsx("li", { children: _jsx(Link, { href: convertWpUrl(item.url, wpApiUrl), className: "footer-link", children: item.title.rendered }) }, item.id))) })] }))] }), _jsxs("div", { className: styles.bottomBar, children: [_jsxs("span", { children: ["\u00A9 ", new Date().getFullYear(), " ", siteName] }), _jsx("span", { children: t("footer.noCookies") })] })] }) }) }));
38
44
  }
@@ -25,7 +25,7 @@
25
25
  }
26
26
 
27
27
  .logoImage {
28
- height: 44px;
28
+ height: 64px;
29
29
  width: auto;
30
30
  display: block;
31
31
  object-fit: contain;
@@ -23,7 +23,13 @@ export default function HeaderClient({ menuLinks, siteName, homeHref, labels, lo
23
23
  const menuLabel = isMenuOpen ? labels.closeMenu : labels.openMenu;
24
24
  const logoData = logo?.src ? logo : null;
25
25
  const logoAlt = logoData?.alt || siteName;
26
- return (_jsxs("div", { className: styles.inner, children: [_jsx(Link, { href: homeHref, className: styles.logo, children: logoData ? (_jsx("img", { src: logoData.src, alt: logoAlt, className: styles.logoImage, width: logoData.width, height: logoData.height })) : (siteName) }), menuLinks.length > 0 && (_jsxs("div", { className: styles.navWrapper, children: [_jsxs("button", { type: "button", className: styles.menuButton, "aria-expanded": isMenuOpen, "aria-controls": "primary-navigation", "aria-label": menuLabel, onClick: toggleMenu, children: [_jsxs("span", { className: styles.menuIcon, "aria-hidden": "true", children: [_jsx("span", {}), _jsx("span", {}), _jsx("span", {})] }), _jsx("span", { className: styles.menuText, children: menuLabel })] }), _jsx("nav", { id: "primary-navigation", "aria-label": labels.navAria, className: `${styles.nav} ${isMenuOpen ? styles.navOpen : ""}`, "aria-hidden": !isMenuOpen && isMobileView, hidden: !isMenuOpen && isMobileView, children: _jsx("ul", { className: styles.list, children: menuLinks.map((item) => (_jsx("li", { children: _jsx(Link, { href: item.href, className: "header-link", onClick: handleLinkClick, target: item.target || undefined, rel: item.target === "_blank"
26
+ const logoStyle = logoData
27
+ ? {
28
+ ...(logoData.height ? { height: logoData.height } : {}),
29
+ ...(logoData.width ? { width: logoData.width } : {}),
30
+ }
31
+ : undefined;
32
+ return (_jsxs("div", { className: styles.inner, children: [_jsx(Link, { href: homeHref, className: styles.logo, children: logoData ? (_jsx("img", { src: logoData.src, alt: logoAlt, className: styles.logoImage, width: logoData.width, height: logoData.height, style: logoStyle })) : (siteName) }), menuLinks.length > 0 && (_jsxs("div", { className: styles.navWrapper, children: [_jsxs("button", { type: "button", className: styles.menuButton, "aria-expanded": isMenuOpen, "aria-controls": "primary-navigation", "aria-label": menuLabel, onClick: toggleMenu, children: [_jsxs("span", { className: styles.menuIcon, "aria-hidden": "true", children: [_jsx("span", {}), _jsx("span", {}), _jsx("span", {})] }), _jsx("span", { className: styles.menuText, children: menuLabel })] }), _jsx("nav", { id: "primary-navigation", "aria-label": labels.navAria, className: `${styles.nav} ${isMenuOpen ? styles.navOpen : ""}`, "aria-hidden": !isMenuOpen && isMobileView, hidden: !isMenuOpen && isMobileView, children: _jsx("ul", { className: styles.list, children: menuLinks.map((item) => (_jsx("li", { children: _jsx(Link, { href: item.href, className: "header-link", onClick: handleLinkClick, target: item.target || undefined, rel: item.target === "_blank"
27
33
  ? "noopener noreferrer"
28
34
  : undefined, children: item.label }) }, item.id))) }) })] }))] }));
29
35
  }
@@ -32,7 +32,7 @@
32
32
  }
33
33
 
34
34
  .logoImage {
35
- height: 40px;
35
+ height: 64px;
36
36
  width: auto;
37
37
  display: block;
38
38
  object-fit: contain;
@@ -1,4 +1,4 @@
1
- import { rewriteYoastUrls } from "../../utils/seo";
1
+ import { buildYoastRobotsMeta, rewriteYoastUrls } from "../../utils/seo";
2
2
  const hasYoast = (entity) => {
3
3
  if (!entity || typeof entity !== "object")
4
4
  return false;
@@ -16,6 +16,7 @@ export const extractYoastMetadata = (entity, fallback = {}, opts = {}) => {
16
16
  const yoast = rewriteYoastUrls(yoastEntity?.yoast_head_json, opts);
17
17
  if (!yoast)
18
18
  return null;
19
+ const robots = buildYoastRobotsMeta(yoast.robots);
19
20
  const imageUrl = yoast.og_image?.[0]?.url || fallback.image;
20
21
  const title = yoast.title || fallback.title;
21
22
  const description = yoast.description || fallback.description;
@@ -23,6 +24,7 @@ export const extractYoastMetadata = (entity, fallback = {}, opts = {}) => {
23
24
  return {
24
25
  title,
25
26
  description,
27
+ ...(robots ? { robots } : {}),
26
28
  alternates: {
27
29
  canonical,
28
30
  },
@@ -1,3 +1,4 @@
1
+ import type { Metadata } from "next";
1
2
  import type { WPYoastHeadJson } from "wpjsapi-lib";
2
3
  type OgImage = {
3
4
  url?: string;
@@ -43,6 +44,8 @@ type RewriteOpts = {
43
44
  */
44
45
  export declare function rewriteYoastUrls<T extends WPYoastHeadJson | undefined>(yoast: T, opts?: RewriteOpts): T;
45
46
  export declare function getYoastHead(entity?: YoastHolder, opts?: RewriteOpts): WPYoastHeadJson | undefined;
47
+ export declare function buildYoastRobotsMeta(robots?: WPYoastHeadJson["robots"]): Metadata["robots"] | undefined;
48
+ export declare function isYoastNoindex(yoast?: WPYoastHeadJson): boolean;
46
49
  export declare function getYoastSchema(entity?: YoastSchemaHolder, opts?: RewriteOpts): import("wpjsapi-lib").WPYoastSchema;
47
50
  export declare function stripBreadcrumbsFromSchema(schema: unknown): unknown;
48
51
  export declare function getFeaturedMedia(entity?: WithEmbeddedMedia): FeaturedMedia | undefined;
package/dist/utils/seo.js CHANGED
@@ -44,6 +44,73 @@ export function getYoastHead(entity, opts) {
44
44
  const yoast = entity?.yoast_head_json;
45
45
  return rewriteYoastUrls(yoast, opts);
46
46
  }
47
+ const normalizeRobotsValue = (value) => {
48
+ if (!value)
49
+ return undefined;
50
+ const trimmed = value.trim().toLowerCase();
51
+ if (!trimmed)
52
+ return undefined;
53
+ const token = trimmed.includes(":") ? trimmed.split(":").pop() : trimmed;
54
+ return token?.trim() || undefined;
55
+ };
56
+ const parseRobotsFlag = (value, directive) => {
57
+ const token = normalizeRobotsValue(value);
58
+ if (!token)
59
+ return undefined;
60
+ const parts = token.split(/[,\s]+/).filter(Boolean);
61
+ if (parts.includes(`no${directive}`))
62
+ return false;
63
+ if (parts.includes(directive))
64
+ return true;
65
+ if (parts.includes("1"))
66
+ return true;
67
+ if (parts.includes("0"))
68
+ return false;
69
+ return undefined;
70
+ };
71
+ const parseRobotsNumber = (value) => {
72
+ const token = normalizeRobotsValue(value);
73
+ if (!token)
74
+ return undefined;
75
+ const parsed = Number(token);
76
+ return Number.isFinite(parsed) ? parsed : undefined;
77
+ };
78
+ const parseMaxImagePreview = (value) => {
79
+ const token = normalizeRobotsValue(value);
80
+ if (!token)
81
+ return undefined;
82
+ if (token === "none" || token === "standard" || token === "large") {
83
+ return token;
84
+ }
85
+ return undefined;
86
+ };
87
+ export function buildYoastRobotsMeta(robots) {
88
+ if (!robots)
89
+ return undefined;
90
+ const meta = {};
91
+ const index = parseRobotsFlag(robots.index, "index");
92
+ if (index !== undefined)
93
+ meta.index = index;
94
+ const follow = parseRobotsFlag(robots.follow, "follow");
95
+ if (follow !== undefined)
96
+ meta.follow = follow;
97
+ const maxSnippet = parseRobotsNumber(robots["max-snippet"]);
98
+ if (maxSnippet !== undefined)
99
+ meta.maxSnippet = maxSnippet;
100
+ const maxImagePreview = parseMaxImagePreview(robots["max-image-preview"]);
101
+ if (maxImagePreview)
102
+ meta.maxImagePreview = maxImagePreview;
103
+ const maxVideoPreview = parseRobotsNumber(robots["max-video-preview"]);
104
+ if (maxVideoPreview !== undefined)
105
+ meta.maxVideoPreview = maxVideoPreview;
106
+ return Object.keys(meta).length ? meta : undefined;
107
+ }
108
+ export function isYoastNoindex(yoast) {
109
+ const robots = buildYoastRobotsMeta(yoast?.robots);
110
+ if (!robots || typeof robots === "string")
111
+ return false;
112
+ return robots.index === false;
113
+ }
47
114
  export function getYoastSchema(entity, opts) {
48
115
  const yoast = getYoastHead(entity, opts);
49
116
  return yoast?.schema || null;
@@ -4,6 +4,7 @@ import { listPostsWithEmbeds } from "../api/posts";
4
4
  import { getCategoryPaginationStaticParams } from "../base";
5
5
  import { getHomePaginationStaticParams } from "../base/home/pagination";
6
6
  import { getAbsoluteUrl, ensureTrailingSlash } from "./routing";
7
+ import { isYoastNoindex } from "./seo";
7
8
  import { getTranslationKey, getEntityLanguageId, withXDefault, } from "./hreflang";
8
9
  const resolveWpApiUrl = (cfg) => cfg.wpApiUrl ?? process.env.WP_API_URL ?? "";
9
10
  const resolveSiteUrl = (cfg) => cfg.siteUrl ?? process.env.NEXT_PUBLIC_SITE_URL;
@@ -12,6 +13,8 @@ const buildHomeAlternates = (cfg) => withXDefault(cfg.languages.reduce((acc, lan
12
13
  acc[langCfg.code] = getAbsoluteUrl(basePath, resolveSiteUrl(cfg));
13
14
  return acc;
14
15
  }, {}));
16
+ const getYoastHeadJson = (entity) => entity.yoast_head_json;
17
+ const isNoindexEntity = (entity) => isYoastNoindex(getYoastHeadJson(entity));
15
18
  export function renderSitemap(entries) {
16
19
  const items = entries
17
20
  .map((entry) => {
@@ -108,11 +111,12 @@ export async function getCategoryEntries(cfg) {
108
111
  const { categoriesApi } = createWpClient({ baseUrl: wpApiUrl });
109
112
  const categories = await categoriesApi.listAll({
110
113
  ...(langCfg.langId ? { lang: langCfg.code } : {}),
111
- _fields: ["id", "slug", "name", "description", "meta"],
114
+ _fields: ["id", "slug", "name", "description", "meta", "yoast_head_json"],
112
115
  });
113
- categoriesPerLang[langCfg.code] = categories;
116
+ const indexableCategories = categories.filter((cat) => !isNoindexEntity(cat));
117
+ categoriesPerLang[langCfg.code] = indexableCategories;
114
118
  const basePath = ensureTrailingSlash(langCfg.basePath || "/");
115
- for (const cat of categories) {
119
+ for (const cat of indexableCategories) {
116
120
  const translationKey = getTranslationKey(cat);
117
121
  if (!translationKey)
118
122
  continue;
@@ -166,9 +170,10 @@ export async function getCategoryPaginationEntries(cfg) {
166
170
  const { categoriesApi } = createWpClient({ baseUrl: wpApiUrl });
167
171
  const categories = await categoriesApi.listAll({
168
172
  lang: langCfg.code,
169
- _fields: ["id", "slug"],
173
+ _fields: ["id", "slug", "yoast_head_json"],
170
174
  });
171
- catIdsBySlugByLang[langCfg.code] = Object.fromEntries(categories.map((c) => [c.slug, c.id]));
175
+ const indexableCategories = categories.filter((cat) => !isNoindexEntity(cat));
176
+ catIdsBySlugByLang[langCfg.code] = Object.fromEntries(indexableCategories.map((c) => [c.slug, c.id]));
172
177
  }
173
178
  for (const langCfg of languages) {
174
179
  const catPages = await getCategoryPaginationStaticParams({
@@ -181,22 +186,22 @@ export async function getCategoryPaginationEntries(cfg) {
181
186
  for (const page of catPages) {
182
187
  const url = getAbsoluteUrl(`${basePath}${page.category}/page/${page.page}/`, siteUrl);
183
188
  const catId = catIdsBySlugByLang[langCfg.code]?.[page.category];
189
+ if (!catId)
190
+ continue;
184
191
  let lastmod;
185
- if (catId) {
186
- const pagePosts = await listPostsWithEmbeds({
187
- baseApiUrl: wpApiUrl,
188
- categories: [catId],
189
- perPage: runtimeConfig.postsPerPagePagination,
190
- page: Number(page.page),
191
- langId: langCfg.langId,
192
- orderby: "date",
193
- order: "desc",
194
- });
195
- const latest = pagePosts.ok ? pagePosts.data?.items[0] : undefined;
196
- lastmod =
197
- latest?.modified ||
198
- latest?.date;
199
- }
192
+ const pagePosts = await listPostsWithEmbeds({
193
+ baseApiUrl: wpApiUrl,
194
+ categories: [catId],
195
+ perPage: runtimeConfig.postsPerPagePagination,
196
+ page: Number(page.page),
197
+ langId: langCfg.langId,
198
+ orderby: "date",
199
+ order: "desc",
200
+ });
201
+ const latest = pagePosts.ok ? pagePosts.data?.items[0] : undefined;
202
+ lastmod =
203
+ latest?.modified ||
204
+ latest?.date;
200
205
  entries.push({
201
206
  url,
202
207
  lastmod: lastmod ? new Date(lastmod).toISOString() : undefined,
@@ -221,17 +226,21 @@ export async function getPostEntriesForLang(langCode, cfg) {
221
226
  _embed: true,
222
227
  ...languageFilter,
223
228
  });
229
+ const indexablePosts = posts.filter((post) => !isNoindexEntity(post));
224
230
  const postAlternates = {};
225
231
  for (const l of languages) {
226
232
  const base = ensureTrailingSlash(l.basePath || "/");
227
233
  const langPosts = l.code === langCfg.code
228
- ? posts
234
+ ? indexablePosts
229
235
  : await postsApi.listAll({
230
236
  per_page: 100,
231
237
  _embed: true,
232
238
  ...(l.langId ? { taxonomies: { language: [l.langId] } } : {}),
233
239
  });
234
- for (const p of langPosts) {
240
+ const filteredLangPosts = l.code === langCfg.code
241
+ ? langPosts
242
+ : langPosts.filter((post) => !isNoindexEntity(post));
243
+ for (const p of filteredLangPosts) {
235
244
  const translationKey = getTranslationKey(p);
236
245
  if (!translationKey)
237
246
  continue;
@@ -246,7 +255,7 @@ export async function getPostEntriesForLang(langCode, cfg) {
246
255
  }
247
256
  }
248
257
  const basePath = ensureTrailingSlash(langCfg.basePath || "/");
249
- return posts
258
+ return indexablePosts
250
259
  .map((p) => {
251
260
  const category = p._embedded?.["wp:term"]?.[0]?.[0];
252
261
  const categorySlug = category?.slug;
@@ -294,12 +303,14 @@ export async function getLegalEntries(cfg) {
294
303
  "taxonomies",
295
304
  "parent",
296
305
  "language",
306
+ "yoast_head_json",
297
307
  ],
298
308
  });
299
309
  const filtered = pages.filter((p) => getEntityLanguageId(p)?.toString() === langCfg.langId?.toString());
300
- pagesPerLang[langCfg.code] = filtered;
310
+ const indexablePages = filtered.filter((page) => !isNoindexEntity(page));
311
+ pagesPerLang[langCfg.code] = indexablePages;
301
312
  const basePath = ensureTrailingSlash(langCfg.basePath || "/");
302
- for (const p of filtered) {
313
+ for (const p of indexablePages) {
303
314
  const translationKey = getTranslationKey(p);
304
315
  if (!translationKey)
305
316
  continue;
@@ -6,6 +6,7 @@ type PostViewProps = {
6
6
  categoryBasePath?: string;
7
7
  locale?: Locale;
8
8
  authorDescription?: string | null;
9
+ disclaimer?: string;
9
10
  };
10
- export declare function PostView({ post, dateLocale, categoryBasePath, locale, authorDescription, }: PostViewProps): import("react/jsx-runtime").JSX.Element;
11
+ export declare function PostView({ post, dateLocale, categoryBasePath, locale, authorDescription, disclaimer, }: PostViewProps): import("react/jsx-runtime").JSX.Element;
11
12
  export {};
@@ -9,7 +9,7 @@ function truncateLabel(label, max = 20) {
9
9
  const trimmed = label.trim();
10
10
  return trimmed.length > max ? `${trimmed.slice(0, max)}...` : trimmed;
11
11
  }
12
- export function PostView({ post, dateLocale = "en-US", categoryBasePath = "/", locale, authorDescription, }) {
12
+ export function PostView({ post, dateLocale = "en-US", categoryBasePath = "/", locale, authorDescription, disclaimer, }) {
13
13
  const t = getTranslator(locale);
14
14
  const author = getAuthor(post);
15
15
  const authorBio = authorDescription ?? author?.description;
@@ -27,5 +27,5 @@ export function PostView({ post, dateLocale = "en-US", categoryBasePath = "/", l
27
27
  { label: "Home", href: categoryBasePath },
28
28
  { label: stripTags(post.title.rendered) || post.title.rendered },
29
29
  ];
30
- return (_jsx("div", { className: `container ${styles.container}`, children: _jsxs("article", { className: styles.article, children: [_jsx(Breadcrumbs, { items: breadcrumbs }), _jsx("header", { className: styles.postHeader, children: _jsx("h1", { dangerouslySetInnerHTML: { __html: post.title.rendered }, className: styles.title }) }), featuredImage && (_jsxs("figure", { className: styles.figure, children: [primaryCategory && (_jsx("div", { className: styles.badgeOverlay, children: categoryUrl ? (_jsx("a", { href: categoryUrl, className: "badge", title: primaryCategory.name, children: truncateLabel(primaryCategory.name, 20) })) : (_jsx("span", { className: "badge", title: primaryCategory.name, children: truncateLabel(primaryCategory.name, 20) })) })), _jsx(Image, { src: featuredImage.src, alt: featuredImage.alt, width: featuredImage.width, height: featuredImage.height, className: styles.image, priority: true, sizes: "(max-width: 900px) 100vw, 900px" })] })), _jsxs("div", { className: styles.meta, children: [author && (_jsx("span", { className: styles.authorLabel, children: t("post.authorPrefix", { name: author.name }) })), _jsx("span", { children: "\u2022" }), _jsx("time", { dateTime: post.date, children: publishedDate })] }), _jsx("div", { dangerouslySetInnerHTML: { __html: post.content.rendered }, className: `post-content ${styles.content}` }), author && (_jsx("aside", { className: `card ${styles.authorCard}`, children: _jsxs("address", { className: styles.authorAddress, children: [_jsx("strong", { className: styles.authorName, children: author.name }), authorBio && (_jsx("p", { className: styles.authorBio, children: authorBio }))] }) }))] }) }));
30
+ return (_jsx("div", { className: `container ${styles.container}`, children: _jsxs("article", { className: styles.article, children: [_jsx(Breadcrumbs, { items: breadcrumbs }), _jsx("header", { className: styles.postHeader, children: _jsx("h1", { dangerouslySetInnerHTML: { __html: post.title.rendered }, className: styles.title }) }), featuredImage && (_jsxs("figure", { className: styles.figure, children: [primaryCategory && (_jsx("div", { className: styles.badgeOverlay, children: categoryUrl ? (_jsx("a", { href: categoryUrl, className: "badge", title: primaryCategory.name, children: truncateLabel(primaryCategory.name, 20) })) : (_jsx("span", { className: "badge", title: primaryCategory.name, children: truncateLabel(primaryCategory.name, 20) })) })), _jsx(Image, { src: featuredImage.src, alt: featuredImage.alt, width: featuredImage.width, height: featuredImage.height, className: styles.image, priority: true, sizes: "(max-width: 900px) 100vw, 900px" })] })), _jsxs("div", { className: styles.meta, children: [author && (_jsx("span", { className: styles.authorLabel, children: t("post.authorPrefix", { name: author.name }) })), _jsx("span", { children: "\u2022" }), _jsx("time", { dateTime: post.date, children: publishedDate })] }), _jsx("div", { dangerouslySetInnerHTML: { __html: post.content.rendered }, className: `post-content ${styles.content}` }), disclaimer && (_jsx("div", { className: styles.disclaimer, role: "note", children: disclaimer })), author && (_jsx("aside", { className: `card ${styles.authorCard}`, children: _jsxs("address", { className: styles.authorAddress, children: [_jsx("strong", { className: styles.authorName, children: author.name }), authorBio && (_jsx("p", { className: styles.authorBio, children: authorBio }))] }) }))] }) }));
31
31
  }
@@ -62,6 +62,18 @@
62
62
  color: var(--foreground);
63
63
  }
64
64
 
65
+ .disclaimer {
66
+ margin-top: var(--spacing-md);
67
+ padding: 0.9rem 1.1rem;
68
+ border-radius: 10px;
69
+ border: 1px dashed var(--border);
70
+ background: #f1f5f9;
71
+ color: var(--foreground-light);
72
+ font-size: 0.95rem;
73
+ line-height: 1.6;
74
+ font-style: italic;
75
+ }
76
+
65
77
  .authorCard {
66
78
  margin-top: var(--spacing-lg);
67
79
  margin-left: auto;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wpheadless-lib",
3
- "version": "1.1.6",
3
+ "version": "1.1.9",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "dist/index.js",