wpheadless-lib 1.0.0
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.
- package/dist/api/categories.d.ts +29 -0
- package/dist/api/categories.js +91 -0
- package/dist/api/index.d.ts +6 -0
- package/dist/api/index.js +6 -0
- package/dist/api/mappers.d.ts +5 -0
- package/dist/api/mappers.js +30 -0
- package/dist/api/posts.d.ts +44 -0
- package/dist/api/posts.js +104 -0
- package/dist/api/translations.d.ts +16 -0
- package/dist/api/translations.js +28 -0
- package/dist/api/types.d.ts +30 -0
- package/dist/api/types.js +1 -0
- package/dist/api/wpClient.d.ts +31 -0
- package/dist/api/wpClient.js +23 -0
- package/dist/app/config.d.ts +5 -0
- package/dist/app/config.js +28 -0
- package/dist/app/globals.css +326 -0
- package/dist/base/category/index.d.ts +38 -0
- package/dist/base/category/index.js +104 -0
- package/dist/base/category/pagination.d.ts +44 -0
- package/dist/base/category/pagination.js +114 -0
- package/dist/base/home/index.d.ts +13 -0
- package/dist/base/home/index.js +20 -0
- package/dist/base/home/pagination.d.ts +36 -0
- package/dist/base/home/pagination.js +83 -0
- package/dist/base/index.d.ts +7 -0
- package/dist/base/index.js +7 -0
- package/dist/base/layout/RootLayoutBase.d.ts +22 -0
- package/dist/base/layout/RootLayoutBase.js +15 -0
- package/dist/base/legal/index.d.ts +31 -0
- package/dist/base/legal/index.js +167 -0
- package/dist/base/post/index.d.ts +31 -0
- package/dist/base/post/index.js +97 -0
- package/dist/components/Breadcrumbs/index.d.ts +9 -0
- package/dist/components/Breadcrumbs/index.js +11 -0
- package/dist/components/Breadcrumbs/index.module.css +39 -0
- package/dist/components/Paginator/index.d.ts +10 -0
- package/dist/components/Paginator/index.js +16 -0
- package/dist/components/Paginator/index.module.css +13 -0
- package/dist/components/Paginator/index.utils.d.ts +7 -0
- package/dist/components/Paginator/index.utils.js +19 -0
- package/dist/components/PostCard/index.d.ts +10 -0
- package/dist/components/PostCard/index.js +22 -0
- package/dist/components/PostCard/index.module.css +56 -0
- package/dist/components/PostCard/index.types.d.ts +7 -0
- package/dist/components/PostCard/index.types.js +1 -0
- package/dist/components/PostCard/index.utils.d.ts +8 -0
- package/dist/components/PostCard/index.utils.js +23 -0
- package/dist/components/index.d.ts +5 -0
- package/dist/components/index.js +5 -0
- package/dist/components/layout/Footer/index.d.ts +12 -0
- package/dist/components/layout/Footer/index.js +36 -0
- package/dist/components/layout/Footer/index.module.css +61 -0
- package/dist/components/layout/Header/index.d.ts +13 -0
- package/dist/components/layout/Header/index.js +36 -0
- package/dist/components/layout/Header/index.module.css +48 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/plugins/index.d.ts +1 -0
- package/dist/plugins/index.js +1 -0
- package/dist/plugins/yoast/index.d.ts +16 -0
- package/dist/plugins/yoast/index.js +44 -0
- package/dist/utils/hreflang.d.ts +37 -0
- package/dist/utils/hreflang.js +95 -0
- package/dist/utils/html.d.ts +4 -0
- package/dist/utils/html.js +8 -0
- package/dist/utils/i18n.d.ts +12 -0
- package/dist/utils/i18n.js +161 -0
- package/dist/utils/index.d.ts +6 -0
- package/dist/utils/index.js +6 -0
- package/dist/utils/routing.d.ts +40 -0
- package/dist/utils/routing.js +84 -0
- package/dist/utils/seo.d.ts +75 -0
- package/dist/utils/seo.js +97 -0
- package/dist/utils/sitemap.d.ts +26 -0
- package/dist/utils/sitemap.js +327 -0
- package/dist/views/CategoryListView/index.d.ts +12 -0
- package/dist/views/CategoryListView/index.js +17 -0
- package/dist/views/CategoryListView/index.module.css +39 -0
- package/dist/views/CategoryListView/index.utils.d.ts +5 -0
- package/dist/views/CategoryListView/index.utils.js +14 -0
- package/dist/views/CategoryPaginationView/index.d.ts +13 -0
- package/dist/views/CategoryPaginationView/index.js +18 -0
- package/dist/views/CategoryPaginationView/index.module.css +39 -0
- package/dist/views/CategoryPaginationView/index.utils.d.ts +5 -0
- package/dist/views/CategoryPaginationView/index.utils.js +4 -0
- package/dist/views/HomePaginationView/index.d.ts +13 -0
- package/dist/views/HomePaginationView/index.js +9 -0
- package/dist/views/HomePaginationView/index.module.css +38 -0
- package/dist/views/HomePaginationView/index.utils.d.ts +7 -0
- package/dist/views/HomePaginationView/index.utils.js +10 -0
- package/dist/views/HomeView/index.d.ts +13 -0
- package/dist/views/HomeView/index.js +21 -0
- package/dist/views/HomeView/index.module.css +78 -0
- package/dist/views/HomeView/index.utils.d.ts +23 -0
- package/dist/views/HomeView/index.utils.js +44 -0
- package/dist/views/LegalPageView/index.d.ts +8 -0
- package/dist/views/LegalPageView/index.js +12 -0
- package/dist/views/LegalPageView/index.module.css +39 -0
- package/dist/views/LegalPageView/index.utils.d.ts +11 -0
- package/dist/views/LegalPageView/index.utils.js +16 -0
- package/dist/views/PostView/index.d.ts +10 -0
- package/dist/views/PostView/index.js +26 -0
- package/dist/views/PostView/index.module.css +80 -0
- package/dist/views/PostView/index.types.d.ts +2 -0
- package/dist/views/PostView/index.types.js +1 -0
- package/dist/views/PostView/index.utils.d.ts +15 -0
- package/dist/views/PostView/index.utils.js +22 -0
- package/dist/views/index.d.ts +6 -0
- package/dist/views/index.js +6 -0
- package/package.json +45 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
const defaultMessages = {
|
|
2
|
+
en: {
|
|
3
|
+
paginator: {
|
|
4
|
+
prev: "Previous",
|
|
5
|
+
next: "Next",
|
|
6
|
+
aria: "Pagination",
|
|
7
|
+
},
|
|
8
|
+
header: {
|
|
9
|
+
navAria: "Main navigation",
|
|
10
|
+
},
|
|
11
|
+
site: {
|
|
12
|
+
title: "Site title",
|
|
13
|
+
description: "Site description",
|
|
14
|
+
paginationTitle: "Site title",
|
|
15
|
+
paginationDescription: "Site pagination description",
|
|
16
|
+
},
|
|
17
|
+
errors: {
|
|
18
|
+
generic: "Unknown error",
|
|
19
|
+
fetchPosts: "Error fetching posts:",
|
|
20
|
+
fetchCategories: "Error fetching categories:",
|
|
21
|
+
fetchCategory: "Error fetching category:",
|
|
22
|
+
fetchCategoryPosts: "Error fetching category posts:",
|
|
23
|
+
fetchPost: "Error fetching post:",
|
|
24
|
+
fetchStaticRoutes: "Error generating static routes:",
|
|
25
|
+
fetchLegalPages: "Error generating legal static routes:",
|
|
26
|
+
fetchLegalPage: "Error fetching legal page:",
|
|
27
|
+
},
|
|
28
|
+
home: {
|
|
29
|
+
title: "Latest articles",
|
|
30
|
+
error: "Error",
|
|
31
|
+
errorHint: "Make sure your WordPress site URL is configured.",
|
|
32
|
+
empty: "No posts found.",
|
|
33
|
+
loadError: "Error loading posts: {error}",
|
|
34
|
+
pageLabel: "Page {page}",
|
|
35
|
+
},
|
|
36
|
+
post: {
|
|
37
|
+
authorPrefix: "By {name}",
|
|
38
|
+
featuredAlt: "Featured image: {title}",
|
|
39
|
+
articleAlt: "Article image: {title}",
|
|
40
|
+
aboutAuthor: "About the author",
|
|
41
|
+
},
|
|
42
|
+
category: {
|
|
43
|
+
empty: "No posts in this category.",
|
|
44
|
+
emptyPage: "No posts on this page.",
|
|
45
|
+
pageLabel: "Page {page}",
|
|
46
|
+
countOne: "{count} article",
|
|
47
|
+
countMany: "{count} articles",
|
|
48
|
+
},
|
|
49
|
+
footer: {
|
|
50
|
+
tagline: "Default footer tagline",
|
|
51
|
+
navTitle: "Links",
|
|
52
|
+
navAria: "Footer navigation",
|
|
53
|
+
noCookies: "Cookie-free site.",
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
es: {
|
|
57
|
+
paginator: {
|
|
58
|
+
prev: "Anterior",
|
|
59
|
+
next: "Siguiente",
|
|
60
|
+
aria: "Paginación",
|
|
61
|
+
},
|
|
62
|
+
header: {
|
|
63
|
+
navAria: "Navegación principal",
|
|
64
|
+
},
|
|
65
|
+
site: {
|
|
66
|
+
title: "Título del sitio",
|
|
67
|
+
description: "Descripción del sitio",
|
|
68
|
+
paginationTitle: "Título del sitio",
|
|
69
|
+
paginationDescription: "Descripción de paginación del sitio",
|
|
70
|
+
},
|
|
71
|
+
errors: {
|
|
72
|
+
generic: "Error desconocido",
|
|
73
|
+
fetchPosts: "Error obteniendo posts:",
|
|
74
|
+
fetchCategories: "Error obteniendo categorías:",
|
|
75
|
+
fetchCategory: "Error obteniendo categoría:",
|
|
76
|
+
fetchCategoryPosts: "Error obteniendo posts de la categoría:",
|
|
77
|
+
fetchPost: "Error obteniendo post:",
|
|
78
|
+
fetchStaticRoutes: "Error generando rutas estáticas:",
|
|
79
|
+
fetchLegalPages: "Error generando rutas estáticas de páginas:",
|
|
80
|
+
fetchLegalPage: "Error obteniendo página:",
|
|
81
|
+
},
|
|
82
|
+
home: {
|
|
83
|
+
title: "Últimos artículos",
|
|
84
|
+
error: "Error",
|
|
85
|
+
errorHint: "Asegúrate de configurar la URL de tu sitio WordPress.",
|
|
86
|
+
empty: "No se encontraron posts.",
|
|
87
|
+
loadError: "Error cargando posts: {error}",
|
|
88
|
+
pageLabel: "Página {page}",
|
|
89
|
+
},
|
|
90
|
+
post: {
|
|
91
|
+
authorPrefix: "Por {name}",
|
|
92
|
+
featuredAlt: "Imagen destacada: {title}",
|
|
93
|
+
articleAlt: "Imagen del artículo: {title}",
|
|
94
|
+
aboutAuthor: "Sobre el autor",
|
|
95
|
+
},
|
|
96
|
+
category: {
|
|
97
|
+
empty: "No hay posts en esta categoría.",
|
|
98
|
+
emptyPage: "No hay posts en esta página.",
|
|
99
|
+
pageLabel: "Página {page}",
|
|
100
|
+
countOne: "{count} artículo",
|
|
101
|
+
countMany: "{count} artículos",
|
|
102
|
+
},
|
|
103
|
+
footer: {
|
|
104
|
+
tagline: "Tagline por defecto del pie de página",
|
|
105
|
+
navTitle: "Enlaces",
|
|
106
|
+
navAria: "Navegación del pie de página",
|
|
107
|
+
noCookies: "Sitio sin cookies ni trackers.",
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
let messages = JSON.parse(JSON.stringify(defaultMessages));
|
|
112
|
+
function deepMerge(target, source) {
|
|
113
|
+
const output = { ...target };
|
|
114
|
+
for (const [key, value] of Object.entries(source)) {
|
|
115
|
+
if (value &&
|
|
116
|
+
typeof value === "object" &&
|
|
117
|
+
!Array.isArray(value) &&
|
|
118
|
+
typeof target[key] === "object") {
|
|
119
|
+
output[key] = deepMerge(target[key], value);
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
output[key] = value;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return output;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Allow projects to override/extend default translations.
|
|
129
|
+
* Call once during app bootstrap with per-locale overrides.
|
|
130
|
+
*/
|
|
131
|
+
export function extendTranslations(overrides) {
|
|
132
|
+
messages = deepMerge(messages, overrides);
|
|
133
|
+
}
|
|
134
|
+
const fallbackLocale = "en";
|
|
135
|
+
function getMessage(locale, key) {
|
|
136
|
+
const parts = key.split(".");
|
|
137
|
+
let current = messages[locale];
|
|
138
|
+
for (const part of parts) {
|
|
139
|
+
if (typeof current !== "object" || current === null) {
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
current = current[part];
|
|
143
|
+
}
|
|
144
|
+
return typeof current === "string" ? current : undefined;
|
|
145
|
+
}
|
|
146
|
+
function interpolate(template, vars) {
|
|
147
|
+
if (!vars)
|
|
148
|
+
return template;
|
|
149
|
+
return Object.entries(vars).reduce((acc, [token, value]) => acc.replaceAll(`{${token}}`, String(value)), template);
|
|
150
|
+
}
|
|
151
|
+
export function getTranslator(locale) {
|
|
152
|
+
const normalizedLocale = locale || fallbackLocale;
|
|
153
|
+
return (key, vars) => {
|
|
154
|
+
const value = getMessage(normalizedLocale, key) ??
|
|
155
|
+
getMessage(fallbackLocale, key) ??
|
|
156
|
+
key;
|
|
157
|
+
if (typeof value !== "string")
|
|
158
|
+
return key;
|
|
159
|
+
return interpolate(value, vars);
|
|
160
|
+
};
|
|
161
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers to build localized URLs and pagination links.
|
|
3
|
+
*/
|
|
4
|
+
export declare function getLangPrefix(isDefaultLang: boolean, lang: string): string;
|
|
5
|
+
export declare function ensureTrailingSlash(path: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* Get the base site URL.
|
|
8
|
+
* Prefer passing from the app layer; falls back to localhost.
|
|
9
|
+
*/
|
|
10
|
+
export declare function getSiteUrl(siteUrl?: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Build an absolute site URL.
|
|
13
|
+
* @param path - Relative route (e.g. "/category/post")
|
|
14
|
+
* @param siteUrl - Base site URL from the app layer
|
|
15
|
+
* @returns Full URL (e.g. "http://localhost:3000/category/post")
|
|
16
|
+
*/
|
|
17
|
+
export declare function getAbsoluteUrl(path: string, siteUrl?: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Convert WordPress URLs to local/production URLs.
|
|
20
|
+
* Replaces the WordPress domain with the current site domain.
|
|
21
|
+
* @param wpUrl - WordPress URL (e.g. "https://api.example.com/category/post")
|
|
22
|
+
* @param wpApiBaseUrl - WordPress API base URL from the app layer
|
|
23
|
+
* @returns Relative or current-site URL (e.g. "/category/post")
|
|
24
|
+
*/
|
|
25
|
+
export declare function convertWpUrl(wpUrl: string, wpApiBaseUrl?: string): string;
|
|
26
|
+
type PrevNext = {
|
|
27
|
+
prev?: string;
|
|
28
|
+
next: string;
|
|
29
|
+
};
|
|
30
|
+
export declare function buildPrevNextUrls(opts: {
|
|
31
|
+
currentPage: number;
|
|
32
|
+
lang: string;
|
|
33
|
+
isDefaultLang: boolean;
|
|
34
|
+
siteUrl?: string;
|
|
35
|
+
}): PrevNext;
|
|
36
|
+
export declare function buildPrevNextFromBase({ baseUrl, currentPage, }: {
|
|
37
|
+
baseUrl: string;
|
|
38
|
+
currentPage: number;
|
|
39
|
+
}): PrevNext;
|
|
40
|
+
export {};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers to build localized URLs and pagination links.
|
|
3
|
+
*/
|
|
4
|
+
export function getLangPrefix(isDefaultLang, lang) {
|
|
5
|
+
return isDefaultLang ? "/" : `/${lang}/`;
|
|
6
|
+
}
|
|
7
|
+
export function ensureTrailingSlash(path) {
|
|
8
|
+
if (!path)
|
|
9
|
+
return "/";
|
|
10
|
+
return path.endsWith("/") ? path : `${path}/`;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Get the base site URL.
|
|
14
|
+
* Prefer passing from the app layer; falls back to localhost.
|
|
15
|
+
*/
|
|
16
|
+
export function getSiteUrl(siteUrl) {
|
|
17
|
+
if (!siteUrl)
|
|
18
|
+
return "http://localhost:3000";
|
|
19
|
+
try {
|
|
20
|
+
const url = new URL(siteUrl);
|
|
21
|
+
return url.origin;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return siteUrl;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Build an absolute site URL.
|
|
29
|
+
* @param path - Relative route (e.g. "/category/post")
|
|
30
|
+
* @param siteUrl - Base site URL from the app layer
|
|
31
|
+
* @returns Full URL (e.g. "http://localhost:3000/category/post")
|
|
32
|
+
*/
|
|
33
|
+
export function getAbsoluteUrl(path, siteUrl) {
|
|
34
|
+
const baseUrl = getSiteUrl(siteUrl);
|
|
35
|
+
// Ensure the path starts with /
|
|
36
|
+
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
37
|
+
const withSlash = ensureTrailingSlash(normalizedPath);
|
|
38
|
+
return `${baseUrl}${withSlash}`;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Convert WordPress URLs to local/production URLs.
|
|
42
|
+
* Replaces the WordPress domain with the current site domain.
|
|
43
|
+
* @param wpUrl - WordPress URL (e.g. "https://api.example.com/category/post")
|
|
44
|
+
* @param wpApiBaseUrl - WordPress API base URL from the app layer
|
|
45
|
+
* @returns Relative or current-site URL (e.g. "/category/post")
|
|
46
|
+
*/
|
|
47
|
+
export function convertWpUrl(wpUrl, wpApiBaseUrl) {
|
|
48
|
+
try {
|
|
49
|
+
const wpDomain = (wpApiBaseUrl || "").replace("/wp-json", "");
|
|
50
|
+
// If the URL contains the WordPress domain, extract only the path
|
|
51
|
+
if (wpDomain && wpUrl.includes(wpDomain)) {
|
|
52
|
+
const url = new URL(wpUrl);
|
|
53
|
+
return url.pathname;
|
|
54
|
+
}
|
|
55
|
+
// If it's already a relative URL, return as-is
|
|
56
|
+
if (wpUrl.startsWith("/")) {
|
|
57
|
+
return wpUrl;
|
|
58
|
+
}
|
|
59
|
+
// If it's an external URL, return as-is
|
|
60
|
+
return wpUrl;
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// If parsing fails, return as-is
|
|
64
|
+
return wpUrl;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export function buildPrevNextUrls(opts) {
|
|
68
|
+
const { currentPage, lang, isDefaultLang, siteUrl } = opts;
|
|
69
|
+
const canonicalBase = getLangPrefix(isDefaultLang, lang);
|
|
70
|
+
return buildPrevNextFromBase({
|
|
71
|
+
baseUrl: getAbsoluteUrl(canonicalBase, siteUrl),
|
|
72
|
+
currentPage,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
export function buildPrevNextFromBase({ baseUrl, currentPage, }) {
|
|
76
|
+
const normalizedBase = baseUrl.replace(/\/+$/, "");
|
|
77
|
+
const prev = currentPage > 2
|
|
78
|
+
? `${normalizedBase}/page/${currentPage - 1}`
|
|
79
|
+
: currentPage === 2
|
|
80
|
+
? `${normalizedBase}/`
|
|
81
|
+
: undefined;
|
|
82
|
+
const next = `${normalizedBase}/page/${currentPage + 1}`;
|
|
83
|
+
return { prev, next };
|
|
84
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { WPYoastHeadJson } from "wpjsapi-lib";
|
|
2
|
+
type OgImage = {
|
|
3
|
+
url?: string;
|
|
4
|
+
[key: string]: unknown;
|
|
5
|
+
};
|
|
6
|
+
type OgLike = {
|
|
7
|
+
yoast_head_json?: {
|
|
8
|
+
og_image?: OgImage[];
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
type FeaturedMedia = {
|
|
12
|
+
source_url?: string;
|
|
13
|
+
alt_text?: string;
|
|
14
|
+
media_details?: {
|
|
15
|
+
width?: number;
|
|
16
|
+
height?: number;
|
|
17
|
+
[key: string]: unknown;
|
|
18
|
+
};
|
|
19
|
+
[key: string]: unknown;
|
|
20
|
+
};
|
|
21
|
+
type FeaturedMediaLike = Pick<FeaturedMedia, "source_url">;
|
|
22
|
+
type YoastSchemaHolder = {
|
|
23
|
+
yoast_head_json?: {
|
|
24
|
+
schema?: unknown;
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
type YoastHolder = {
|
|
28
|
+
yoast_head_json?: WPYoastHeadJson;
|
|
29
|
+
};
|
|
30
|
+
type WithEmbeddedMedia = {
|
|
31
|
+
_embedded?: {
|
|
32
|
+
"wp:featuredmedia"?: Array<FeaturedMedia>;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
export declare function getOgImageUrl(entity?: OgLike, featuredMedia?: FeaturedMediaLike): string | undefined;
|
|
36
|
+
type RewriteOpts = {
|
|
37
|
+
siteUrl?: string;
|
|
38
|
+
wpApiUrl?: string;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Replace Yoast URLs so they match the frontend domain instead of the WP API domain.
|
|
42
|
+
* It stringifies the object to replace origins and keeps structure intact.
|
|
43
|
+
*/
|
|
44
|
+
export declare function rewriteYoastUrls<T extends WPYoastHeadJson | undefined>(yoast: T, opts?: RewriteOpts): T;
|
|
45
|
+
export declare function getYoastHead(entity?: YoastHolder, opts?: RewriteOpts): WPYoastHeadJson | undefined;
|
|
46
|
+
export declare function getYoastSchema(entity?: YoastSchemaHolder, opts?: RewriteOpts): import("wpjsapi-lib").WPYoastSchema;
|
|
47
|
+
export declare function stripBreadcrumbsFromSchema(schema: unknown): unknown;
|
|
48
|
+
export declare function getFeaturedMedia(entity?: WithEmbeddedMedia): FeaturedMedia | undefined;
|
|
49
|
+
export declare function getPlainTextExcerpt(html?: string, maxLength?: number): string | undefined;
|
|
50
|
+
type BreadcrumbItem = {
|
|
51
|
+
name: string;
|
|
52
|
+
item?: string;
|
|
53
|
+
};
|
|
54
|
+
export declare function buildBreadcrumbSchema(items: BreadcrumbItem[]): {
|
|
55
|
+
"@context": string;
|
|
56
|
+
"@type": string;
|
|
57
|
+
itemListElement: {
|
|
58
|
+
item?: string;
|
|
59
|
+
"@type": string;
|
|
60
|
+
position: number;
|
|
61
|
+
name: string;
|
|
62
|
+
}[];
|
|
63
|
+
};
|
|
64
|
+
export declare function buildCollectionPageSchema({ name, description, url, }: {
|
|
65
|
+
name: string;
|
|
66
|
+
description?: string;
|
|
67
|
+
url: string;
|
|
68
|
+
}): {
|
|
69
|
+
"@context": string;
|
|
70
|
+
"@type": string;
|
|
71
|
+
name: string;
|
|
72
|
+
description: string;
|
|
73
|
+
url: string;
|
|
74
|
+
};
|
|
75
|
+
export {};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { stripTags } from "./html";
|
|
2
|
+
export function getOgImageUrl(entity, featuredMedia) {
|
|
3
|
+
const ogUrl = entity?.yoast_head_json?.og_image?.[0]?.url;
|
|
4
|
+
return ogUrl || featuredMedia?.source_url;
|
|
5
|
+
}
|
|
6
|
+
const getOrigin = (url) => {
|
|
7
|
+
if (!url)
|
|
8
|
+
return null;
|
|
9
|
+
try {
|
|
10
|
+
return new URL(url).origin;
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
const normalizeWpApiOrigin = (wpApiUrl) => {
|
|
17
|
+
if (!wpApiUrl)
|
|
18
|
+
return null;
|
|
19
|
+
const cleaned = wpApiUrl.replace(/\/wp-json\/?$/, "");
|
|
20
|
+
return getOrigin(cleaned);
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Replace Yoast URLs so they match the frontend domain instead of the WP API domain.
|
|
24
|
+
* It stringifies the object to replace origins and keeps structure intact.
|
|
25
|
+
*/
|
|
26
|
+
export function rewriteYoastUrls(yoast, opts = {}) {
|
|
27
|
+
if (!yoast)
|
|
28
|
+
return yoast;
|
|
29
|
+
const targetOrigin = getOrigin(opts.siteUrl);
|
|
30
|
+
const sourceOrigin = normalizeWpApiOrigin(opts.wpApiUrl) || getOrigin(yoast.canonical);
|
|
31
|
+
if (!targetOrigin || !sourceOrigin || targetOrigin === sourceOrigin) {
|
|
32
|
+
return yoast;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const serialized = JSON.stringify(yoast);
|
|
36
|
+
const replaced = serialized.split(sourceOrigin).join(targetOrigin);
|
|
37
|
+
return JSON.parse(replaced);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return yoast;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export function getYoastHead(entity, opts) {
|
|
44
|
+
const yoast = entity?.yoast_head_json;
|
|
45
|
+
return rewriteYoastUrls(yoast, opts);
|
|
46
|
+
}
|
|
47
|
+
export function getYoastSchema(entity, opts) {
|
|
48
|
+
const yoast = getYoastHead(entity, opts);
|
|
49
|
+
return yoast?.schema || null;
|
|
50
|
+
}
|
|
51
|
+
export function stripBreadcrumbsFromSchema(schema) {
|
|
52
|
+
if (!schema || typeof schema !== "object")
|
|
53
|
+
return schema;
|
|
54
|
+
const graph = schema["@graph"];
|
|
55
|
+
if (!Array.isArray(graph))
|
|
56
|
+
return schema;
|
|
57
|
+
const filtered = graph.filter((node) => {
|
|
58
|
+
const type = node["@type"];
|
|
59
|
+
if (!type)
|
|
60
|
+
return true;
|
|
61
|
+
if (Array.isArray(type)) {
|
|
62
|
+
return !type.includes("BreadcrumbList");
|
|
63
|
+
}
|
|
64
|
+
return type !== "BreadcrumbList";
|
|
65
|
+
});
|
|
66
|
+
return { ...schema, "@graph": filtered };
|
|
67
|
+
}
|
|
68
|
+
export function getFeaturedMedia(entity) {
|
|
69
|
+
return entity?._embedded?.["wp:featuredmedia"]?.[0];
|
|
70
|
+
}
|
|
71
|
+
export function getPlainTextExcerpt(html, maxLength = 160) {
|
|
72
|
+
if (!html)
|
|
73
|
+
return undefined;
|
|
74
|
+
const text = html.replace(/<[^>]*>/g, "");
|
|
75
|
+
return maxLength > 0 ? text.slice(0, maxLength) : text;
|
|
76
|
+
}
|
|
77
|
+
export function buildBreadcrumbSchema(items) {
|
|
78
|
+
return {
|
|
79
|
+
"@context": "https://schema.org",
|
|
80
|
+
"@type": "BreadcrumbList",
|
|
81
|
+
itemListElement: items.map((it, idx) => ({
|
|
82
|
+
"@type": "ListItem",
|
|
83
|
+
position: idx + 1,
|
|
84
|
+
name: stripTags(it.name) || it.name,
|
|
85
|
+
...(it.item ? { item: it.item } : {}),
|
|
86
|
+
})),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
export function buildCollectionPageSchema({ name, description, url, }) {
|
|
90
|
+
return {
|
|
91
|
+
"@context": "https://schema.org",
|
|
92
|
+
"@type": "CollectionPage",
|
|
93
|
+
name,
|
|
94
|
+
description,
|
|
95
|
+
url,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { LanguageConfig } from "./hreflang";
|
|
2
|
+
export type SitemapRuntimeConfig = {
|
|
3
|
+
postsPerPagePagination: number;
|
|
4
|
+
};
|
|
5
|
+
export type SitemapConfig = {
|
|
6
|
+
languages: LanguageConfig[];
|
|
7
|
+
runtimeConfig: SitemapRuntimeConfig;
|
|
8
|
+
wpApiUrl?: string;
|
|
9
|
+
siteUrl?: string;
|
|
10
|
+
};
|
|
11
|
+
export type SitemapEntry = {
|
|
12
|
+
url: string;
|
|
13
|
+
lastmod?: string;
|
|
14
|
+
alternates?: Record<string, string>;
|
|
15
|
+
};
|
|
16
|
+
export declare function renderSitemap(entries: SitemapEntry[]): string;
|
|
17
|
+
export declare function renderSitemapIndex(sitemaps: Array<{
|
|
18
|
+
url: string;
|
|
19
|
+
lastmod?: string;
|
|
20
|
+
}>): string;
|
|
21
|
+
export declare function getHomeEntries(cfg: SitemapConfig): Promise<SitemapEntry[]>;
|
|
22
|
+
export declare function getHomePaginationEntries(cfg: SitemapConfig): Promise<SitemapEntry[]>;
|
|
23
|
+
export declare function getCategoryEntries(cfg: SitemapConfig): Promise<SitemapEntry[]>;
|
|
24
|
+
export declare function getCategoryPaginationEntries(cfg: SitemapConfig): Promise<SitemapEntry[]>;
|
|
25
|
+
export declare function getPostEntriesForLang(langCode: string, cfg: SitemapConfig): Promise<SitemapEntry[]>;
|
|
26
|
+
export declare function getLegalEntries(cfg: SitemapConfig): Promise<SitemapEntry[]>;
|