@vicacha-devs/strapi-plugin-seo 0.0.0-stage → 2.0.12
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/LICENSE +21 -0
- package/README.md +84 -2
- package/dist/admin/components/CMEditView/RightLinksCompo/SeoChecks/AlternativeTextCheck/index.d.ts +9 -0
- package/dist/admin/components/CMEditView/RightLinksCompo/SeoChecks/CanonicalUrlCheck/index.d.ts +7 -0
- package/dist/admin/components/CMEditView/RightLinksCompo/SeoChecks/KeywordDensityCheck/index.d.ts +7 -0
- package/dist/admin/components/CMEditView/RightLinksCompo/SeoChecks/LastUpdatedAtCheck/index.d.ts +7 -0
- package/dist/admin/components/CMEditView/RightLinksCompo/SeoChecks/MetaDescriptionCheck/index.d.ts +7 -0
- package/dist/admin/components/CMEditView/RightLinksCompo/SeoChecks/MetaRobotCheck/index.d.ts +7 -0
- package/dist/admin/components/CMEditView/RightLinksCompo/SeoChecks/MetaTitleCheck/index.d.ts +7 -0
- package/dist/admin/components/CMEditView/RightLinksCompo/SeoChecks/OpenGraphCheck/index.d.ts +7 -0
- package/dist/admin/components/CMEditView/RightLinksCompo/SeoChecks/SEOAccordion/index.d.ts +10 -0
- package/dist/admin/components/CMEditView/RightLinksCompo/SeoChecks/StructuredDataCheck/index.d.ts +7 -0
- package/dist/admin/components/CMEditView/RightLinksCompo/SeoChecks/WordCountCheck/index.d.ts +7 -0
- package/dist/admin/components/CMEditView/RightLinksCompo/SeoChecks/index.d.ts +10 -0
- package/dist/admin/components/CMEditView/RightLinksCompo/Summary/BrowserPreview/KeywordCheck/index.d.ts +7 -0
- package/dist/admin/components/CMEditView/RightLinksCompo/Summary/BrowserPreview/MetaChecks/index.d.ts +8 -0
- package/dist/admin/components/CMEditView/RightLinksCompo/Summary/BrowserPreview/Serp/index.d.ts +6 -0
- package/dist/admin/components/CMEditView/RightLinksCompo/Summary/BrowserPreview/index.d.ts +6 -0
- package/dist/admin/components/CMEditView/RightLinksCompo/Summary/OpenGraphPreview/Facebook/index.d.ts +8 -0
- package/dist/admin/components/CMEditView/RightLinksCompo/Summary/OpenGraphPreview/LinkedIn/index.d.ts +8 -0
- package/dist/admin/components/CMEditView/RightLinksCompo/Summary/OpenGraphPreview/X/index.d.ts +8 -0
- package/dist/admin/components/CMEditView/RightLinksCompo/Summary/OpenGraphPreview/index.d.ts +6 -0
- package/dist/admin/components/CMEditView/RightLinksCompo/Summary/PreviewChecks/index.d.ts +6 -0
- package/dist/admin/components/CMEditView/RightLinksCompo/Summary/index.d.ts +4 -0
- package/dist/admin/components/CMEditView/RightLinksCompo/Summary/reducer.d.ts +2 -0
- package/dist/admin/components/CMEditView/RightLinksCompo/index.d.ts +1 -0
- package/dist/admin/components/CMEditView/utils/checks.d.ts +14 -0
- package/dist/admin/components/CMEditView/utils/getRegularImageAltTexts.d.ts +5 -0
- package/dist/admin/components/CMEditView/utils/getRichTextAndBlocksFields.d.ts +10 -0
- package/dist/admin/components/CMEditView/utils/getRichTextData.d.ts +2 -0
- package/dist/admin/components/HomePage/Header/index.d.ts +5 -0
- package/dist/admin/components/HomePage/Main/EmptyComponentLayout/illo.d.ts +1 -0
- package/dist/admin/components/HomePage/Main/SettingsModal/index.d.ts +8 -0
- package/dist/admin/components/HomePage/Main/index.d.ts +6 -0
- package/dist/admin/components/Initializer.d.ts +5 -0
- package/dist/admin/hooks/useSettingsApi.d.ts +5 -0
- package/dist/admin/index-C8tiCtgn.cjs +3490 -0
- package/dist/admin/index-CJ64dp6B.js +3473 -0
- package/dist/admin/index-CZ4VBOGS.cjs +589 -0
- package/dist/admin/index-DgvE6ytW.js +571 -0
- package/dist/admin/index.cjs +5 -0
- package/dist/admin/index.d.ts +18 -0
- package/dist/admin/index.js +5 -0
- package/dist/admin/index.mjs +5 -0
- package/dist/admin/pages/App/index.d.ts +2 -0
- package/dist/admin/pages/HomePage/index.d.ts +2 -0
- package/dist/admin/permissions.d.ts +10 -0
- package/dist/admin/pluginId.d.ts +1 -0
- package/dist/admin/translations/ar.json.d.ts +133 -0
- package/dist/admin/translations/en.json.d.ts +133 -0
- package/dist/admin/translations/es.json.d.ts +133 -0
- package/dist/admin/translations/fr.json.d.ts +133 -0
- package/dist/admin/translations/pt-BR.json.d.ts +133 -0
- package/dist/admin/translations/tr.json.d.ts +133 -0
- package/dist/admin/utils/getTrad.d.ts +1 -0
- package/dist/admin/utils/prefixPluginTranslations.d.ts +1 -0
- package/dist/package.json +3 -0
- package/dist/server/bootstrap.d.ts +5 -0
- package/dist/server/components/open-graph.json.d.ts +36 -0
- package/dist/server/components/seo.json.d.ts +52 -0
- package/dist/server/config/index.d.ts +5 -0
- package/dist/server/controllers/index.d.ts +16 -0
- package/dist/server/controllers/seo.d.ts +13 -0
- package/dist/server/controllers/settings.d.ts +16 -0
- package/dist/server/destroy.d.ts +5 -0
- package/dist/server/index.cjs +416 -0
- package/dist/server/index.d.ts +83 -0
- package/dist/server/index.js +416 -0
- package/dist/server/index.mjs +416 -0
- package/dist/server/register.d.ts +5 -0
- package/dist/server/routes/index.d.ts +35 -0
- package/dist/server/routes/seo.d.ts +16 -0
- package/dist/server/routes/settings.d.ts +16 -0
- package/dist/server/services/index.d.ts +19 -0
- package/dist/server/services/seo.d.ts +12 -0
- package/dist/server/services/settings.d.ts +10 -0
- package/dist/shared/index.cjs +17 -0
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.js +17 -0
- package/dist/shared/index.mjs +17 -0
- package/package.json +100 -3
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
3
|
+
const bootstrap = async ({ strapi }) => {
|
|
4
|
+
const actions = [
|
|
5
|
+
{
|
|
6
|
+
section: "plugins",
|
|
7
|
+
displayName: "Access the SEO plugin",
|
|
8
|
+
uid: "read",
|
|
9
|
+
pluginName: "seo"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
section: "plugins",
|
|
13
|
+
displayName: "Manage SEO plugin settings",
|
|
14
|
+
uid: "settings.update",
|
|
15
|
+
pluginName: "seo"
|
|
16
|
+
}
|
|
17
|
+
];
|
|
18
|
+
await strapi.admin.services.permission.actionProvider.registerMany(actions);
|
|
19
|
+
};
|
|
20
|
+
const config = {
|
|
21
|
+
default: {},
|
|
22
|
+
validator() {
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
const seoController = ({ strapi }) => ({
|
|
26
|
+
findSeoComponent(ctx) {
|
|
27
|
+
ctx.body = strapi.plugin("seo").service("seo").getSeoComponent();
|
|
28
|
+
return ctx.body;
|
|
29
|
+
},
|
|
30
|
+
findContentTypes(ctx) {
|
|
31
|
+
ctx.body = strapi.plugin("seo").service("seo").getContentTypes();
|
|
32
|
+
return ctx.body;
|
|
33
|
+
},
|
|
34
|
+
async createSeoComponent(ctx) {
|
|
35
|
+
const previousWatching = strapi.reload?.isWatching;
|
|
36
|
+
if (strapi.reload) {
|
|
37
|
+
strapi.reload.isWatching = false;
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
const data = await strapi.plugin("seo").service("seo").createSeoComponent();
|
|
41
|
+
if (!data) {
|
|
42
|
+
if (strapi.reload && previousWatching !== void 0) {
|
|
43
|
+
strapi.reload.isWatching = previousWatching;
|
|
44
|
+
}
|
|
45
|
+
ctx.status = 500;
|
|
46
|
+
ctx.body = { error: "Failed to create SEO component" };
|
|
47
|
+
return ctx.body;
|
|
48
|
+
}
|
|
49
|
+
if (typeof strapi.reload === "function") {
|
|
50
|
+
setImmediate(() => strapi.reload());
|
|
51
|
+
}
|
|
52
|
+
ctx.body = data;
|
|
53
|
+
return data;
|
|
54
|
+
} catch (error) {
|
|
55
|
+
if (strapi.reload && previousWatching !== void 0) {
|
|
56
|
+
strapi.reload.isWatching = previousWatching;
|
|
57
|
+
}
|
|
58
|
+
strapi.log?.error?.(String(error));
|
|
59
|
+
if (typeof ctx.throw === "function") {
|
|
60
|
+
ctx.throw(500, error);
|
|
61
|
+
}
|
|
62
|
+
ctx.status = 500;
|
|
63
|
+
ctx.body = { error: "Failed to create SEO component" };
|
|
64
|
+
return ctx.body;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
const isPlainRecord$1 = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
69
|
+
const settingsController = ({ strapi }) => {
|
|
70
|
+
const getSettingsService = () => strapi.plugin("seo").service("settings");
|
|
71
|
+
const getSettings = async (ctx) => {
|
|
72
|
+
try {
|
|
73
|
+
const result = await getSettingsService().getSettings();
|
|
74
|
+
ctx.body = result;
|
|
75
|
+
return result;
|
|
76
|
+
} catch (err) {
|
|
77
|
+
ctx.throw(500, err);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
const setSettings = async (ctx) => {
|
|
81
|
+
const { body } = ctx.request ?? {};
|
|
82
|
+
if (!isPlainRecord$1(body)) {
|
|
83
|
+
if (typeof ctx.badRequest === "function") {
|
|
84
|
+
return ctx.badRequest("Invalid SEO settings payload");
|
|
85
|
+
}
|
|
86
|
+
return ctx.throw(400, "Invalid SEO settings payload");
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
const settingsService2 = getSettingsService();
|
|
90
|
+
await settingsService2.setSettings(body);
|
|
91
|
+
const updated = await settingsService2.getSettings();
|
|
92
|
+
ctx.body = updated;
|
|
93
|
+
return updated;
|
|
94
|
+
} catch (err) {
|
|
95
|
+
ctx.throw(500, err);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
return {
|
|
99
|
+
getSettings,
|
|
100
|
+
setSettings
|
|
101
|
+
};
|
|
102
|
+
};
|
|
103
|
+
const controllers = {
|
|
104
|
+
seo: seoController,
|
|
105
|
+
settings: settingsController
|
|
106
|
+
};
|
|
107
|
+
const destroy = (_context) => {
|
|
108
|
+
};
|
|
109
|
+
const register = (_context) => {
|
|
110
|
+
};
|
|
111
|
+
const READ_POLICIES = [
|
|
112
|
+
"admin::isAuthenticatedAdmin",
|
|
113
|
+
{
|
|
114
|
+
name: "admin::hasPermissions",
|
|
115
|
+
config: { actions: ["plugin::seo.read"] }
|
|
116
|
+
}
|
|
117
|
+
];
|
|
118
|
+
const seoRoutes = {
|
|
119
|
+
type: "admin",
|
|
120
|
+
routes: [
|
|
121
|
+
{
|
|
122
|
+
method: "GET",
|
|
123
|
+
path: "/component",
|
|
124
|
+
handler: "seo.findSeoComponent",
|
|
125
|
+
config: {
|
|
126
|
+
policies: READ_POLICIES
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
method: "POST",
|
|
131
|
+
path: "/component",
|
|
132
|
+
handler: "seo.createSeoComponent",
|
|
133
|
+
config: {
|
|
134
|
+
policies: READ_POLICIES
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
method: "GET",
|
|
139
|
+
path: "/content-types",
|
|
140
|
+
handler: "seo.findContentTypes",
|
|
141
|
+
config: {
|
|
142
|
+
policies: READ_POLICIES
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
]
|
|
146
|
+
};
|
|
147
|
+
const SETTINGS_POLICIES = [
|
|
148
|
+
"admin::isAuthenticatedAdmin",
|
|
149
|
+
{
|
|
150
|
+
name: "admin::hasPermissions",
|
|
151
|
+
config: { actions: ["plugin::seo.read"] }
|
|
152
|
+
}
|
|
153
|
+
];
|
|
154
|
+
const settingsRoutes = {
|
|
155
|
+
type: "admin",
|
|
156
|
+
routes: [
|
|
157
|
+
{
|
|
158
|
+
method: "GET",
|
|
159
|
+
path: "/settings",
|
|
160
|
+
handler: "settings.getSettings",
|
|
161
|
+
config: { policies: SETTINGS_POLICIES }
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
method: "POST",
|
|
165
|
+
path: "/settings",
|
|
166
|
+
handler: "settings.setSettings",
|
|
167
|
+
config: { policies: SETTINGS_POLICIES }
|
|
168
|
+
}
|
|
169
|
+
]
|
|
170
|
+
};
|
|
171
|
+
const routes = {
|
|
172
|
+
seo: seoRoutes,
|
|
173
|
+
settings: settingsRoutes
|
|
174
|
+
};
|
|
175
|
+
const collectionName$1 = "components_shared_open_graphs";
|
|
176
|
+
const info$1 = { "displayName": "openGraph", "icon": "project-diagram" };
|
|
177
|
+
const options$1 = {};
|
|
178
|
+
const attributes$1 = { "ogTitle": { "type": "string", "required": true, "maxLength": 70 }, "ogDescription": { "type": "string", "maxLength": 200, "required": true }, "ogImage": { "allowedTypes": ["images"], "type": "media", "multiple": false }, "ogUrl": { "type": "string", "required": false }, "ogType": { "type": "string", "required": false } };
|
|
179
|
+
const openGraph = {
|
|
180
|
+
collectionName: collectionName$1,
|
|
181
|
+
info: info$1,
|
|
182
|
+
options: options$1,
|
|
183
|
+
attributes: attributes$1
|
|
184
|
+
};
|
|
185
|
+
const collectionName = "components_shared_seos";
|
|
186
|
+
const info = { "displayName": "seo", "icon": "search" };
|
|
187
|
+
const options = {};
|
|
188
|
+
const attributes = { "metaTitle": { "required": true, "type": "string", "maxLength": 60 }, "metaDescription": { "type": "string", "required": true, "maxLength": 160, "minLength": 50 }, "metaImage": { "type": "media", "multiple": false, "required": false, "allowedTypes": ["images"] }, "openGraph": { "type": "component", "repeatable": false, "component": "shared.open-graph" }, "keywords": { "type": "text", "regex": "[^,]+" }, "metaRobots": { "type": "string", "regex": "[^,]+" }, "metaViewport": { "type": "string" }, "canonicalURL": { "type": "string" }, "structuredData": { "type": "json" } };
|
|
189
|
+
const seoContent = {
|
|
190
|
+
collectionName,
|
|
191
|
+
info,
|
|
192
|
+
options,
|
|
193
|
+
attributes
|
|
194
|
+
};
|
|
195
|
+
const BLACKLISTED_PLUGINS = [
|
|
196
|
+
"upload",
|
|
197
|
+
"i18n",
|
|
198
|
+
"users-permissions",
|
|
199
|
+
"content-releases",
|
|
200
|
+
"review-workflows",
|
|
201
|
+
"email",
|
|
202
|
+
"seo",
|
|
203
|
+
"email-designer-5"
|
|
204
|
+
];
|
|
205
|
+
const isContentManagerVisible = (ct) => {
|
|
206
|
+
const pluginOptions = ct.__schema__?.pluginOptions ?? ct.pluginOptions;
|
|
207
|
+
return pluginOptions?.["content-manager"]?.visible !== false;
|
|
208
|
+
};
|
|
209
|
+
const shouldIncludeContentType = (name, ct) => {
|
|
210
|
+
if (name.startsWith("api::")) return true;
|
|
211
|
+
return name.startsWith("plugin::") && isContentManagerVisible(ct);
|
|
212
|
+
};
|
|
213
|
+
const resolveGlobalId = (name, ct) => {
|
|
214
|
+
if (ct.globalId) return ct.globalId;
|
|
215
|
+
return ct.info?.displayName ?? name;
|
|
216
|
+
};
|
|
217
|
+
const hasSeoComponentAttribute = (ct) => {
|
|
218
|
+
const seoAttr = ct.attributes?.seo;
|
|
219
|
+
return typeof seoAttr?.component === "string" && seoAttr.component.trim().length > 0;
|
|
220
|
+
};
|
|
221
|
+
const buildContentTypeSeoItem = (name, ct) => ({
|
|
222
|
+
seo: hasSeoComponentAttribute(ct),
|
|
223
|
+
uid: ct.uid ?? name,
|
|
224
|
+
kind: ct.kind ?? "collectionType",
|
|
225
|
+
globalId: resolveGlobalId(name, ct),
|
|
226
|
+
attributes: ct.attributes ?? {}
|
|
227
|
+
});
|
|
228
|
+
const isAllowedPluginContentType = (name) => {
|
|
229
|
+
const pluginPrefix = name.replace("plugin::", "").split(".")[0];
|
|
230
|
+
return !BLACKLISTED_PLUGINS.includes(pluginPrefix);
|
|
231
|
+
};
|
|
232
|
+
const seoService = ({ strapi }) => ({
|
|
233
|
+
getSeoComponent() {
|
|
234
|
+
const seoComponent = strapi.components?.["shared.seo"];
|
|
235
|
+
return seoComponent ? { attributes: seoComponent.attributes, category: seoComponent.category } : null;
|
|
236
|
+
},
|
|
237
|
+
getContentTypes() {
|
|
238
|
+
const contentTypes = strapi.contentTypes || {};
|
|
239
|
+
const keys = Object.keys(contentTypes);
|
|
240
|
+
const collectionTypes = [];
|
|
241
|
+
const singleTypes = [];
|
|
242
|
+
const plugins = [];
|
|
243
|
+
keys.forEach((name) => {
|
|
244
|
+
const ct = contentTypes[name];
|
|
245
|
+
if (!ct || !shouldIncludeContentType(name, ct)) return;
|
|
246
|
+
const object = buildContentTypeSeoItem(name, ct);
|
|
247
|
+
if (name.startsWith("api::")) {
|
|
248
|
+
const targetList = ct.kind === "collectionType" ? collectionTypes : singleTypes;
|
|
249
|
+
targetList.push(object);
|
|
250
|
+
} else if (isAllowedPluginContentType(name)) {
|
|
251
|
+
plugins.push(object);
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
return { collectionTypes, singleTypes, plugins };
|
|
255
|
+
},
|
|
256
|
+
async createSeoComponent() {
|
|
257
|
+
const seoComponent = await this.getSeoComponent();
|
|
258
|
+
if (seoComponent) {
|
|
259
|
+
return seoComponent;
|
|
260
|
+
}
|
|
261
|
+
if (!openGraph || !seoContent) {
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
const hasOpenGraph = Boolean(strapi.components?.["shared.open-graph"]);
|
|
265
|
+
try {
|
|
266
|
+
return await strapi.plugin("content-type-builder").services.components.createComponent({
|
|
267
|
+
component: {
|
|
268
|
+
category: "shared",
|
|
269
|
+
displayName: seoContent.info.displayName,
|
|
270
|
+
icon: seoContent.info.icon,
|
|
271
|
+
attributes: seoContent.attributes
|
|
272
|
+
},
|
|
273
|
+
components: hasOpenGraph ? [] : [
|
|
274
|
+
{
|
|
275
|
+
tmpUID: "shared.open-graph",
|
|
276
|
+
category: "shared",
|
|
277
|
+
displayName: openGraph.info.displayName,
|
|
278
|
+
icon: openGraph.info.icon,
|
|
279
|
+
attributes: openGraph.attributes
|
|
280
|
+
}
|
|
281
|
+
]
|
|
282
|
+
});
|
|
283
|
+
} catch (error) {
|
|
284
|
+
strapi.log?.error?.(String(error));
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
const DEFAULT_SEO_CHECKS = {
|
|
290
|
+
metaTitle: true,
|
|
291
|
+
metaDescription: true,
|
|
292
|
+
metaRobots: true,
|
|
293
|
+
openGraph: true,
|
|
294
|
+
wordCount: true,
|
|
295
|
+
canonicalUrl: true,
|
|
296
|
+
keywordDensity: true,
|
|
297
|
+
structuredData: true,
|
|
298
|
+
alternativeText: true,
|
|
299
|
+
lastUpdatedAt: true
|
|
300
|
+
};
|
|
301
|
+
const FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
|
|
302
|
+
const SEO_CHECK_KEYS = Object.keys(DEFAULT_SEO_CHECKS);
|
|
303
|
+
const isPlainRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
304
|
+
const sanitizeSeoChecks = (raw) => {
|
|
305
|
+
const source = isPlainRecord(raw) ? raw : {};
|
|
306
|
+
const checks = { ...DEFAULT_SEO_CHECKS };
|
|
307
|
+
SEO_CHECK_KEYS.forEach((key) => {
|
|
308
|
+
if (typeof source[key] === "boolean") {
|
|
309
|
+
checks[key] = source[key];
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
return checks;
|
|
313
|
+
};
|
|
314
|
+
const sanitizeSeoSettingsMap = (raw) => {
|
|
315
|
+
const result = {};
|
|
316
|
+
if (!isPlainRecord(raw)) {
|
|
317
|
+
return result;
|
|
318
|
+
}
|
|
319
|
+
Object.keys(raw).forEach((key) => {
|
|
320
|
+
const trimmedKey = key.trim();
|
|
321
|
+
if (!trimmedKey || trimmedKey.length > 128 || FORBIDDEN_KEYS.has(trimmedKey)) {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
const entry = raw[key];
|
|
325
|
+
if (!isPlainRecord(entry)) {
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
const fallbackName = trimmedKey.split(".").pop() || trimmedKey;
|
|
329
|
+
const rawName = entry.collectionName;
|
|
330
|
+
const collectionName2 = typeof rawName === "string" && rawName.trim().length > 0 ? rawName.trim().slice(0, 128) : fallbackName;
|
|
331
|
+
result[trimmedKey] = {
|
|
332
|
+
collectionName: collectionName2,
|
|
333
|
+
seoChecks: sanitizeSeoChecks(entry.seoChecks)
|
|
334
|
+
};
|
|
335
|
+
});
|
|
336
|
+
return result;
|
|
337
|
+
};
|
|
338
|
+
const settingsService = ({ strapi }) => {
|
|
339
|
+
const getPluginStore = () => {
|
|
340
|
+
return strapi.store({
|
|
341
|
+
environment: "",
|
|
342
|
+
type: "plugin",
|
|
343
|
+
name: "seo"
|
|
344
|
+
});
|
|
345
|
+
};
|
|
346
|
+
const createDefaultConfig = async () => {
|
|
347
|
+
const pluginStore = getPluginStore();
|
|
348
|
+
const newContentTypes = {};
|
|
349
|
+
const keys = Object.keys(strapi.contentTypes || {});
|
|
350
|
+
keys.forEach((key) => {
|
|
351
|
+
if (key.includes("api::") || key.includes("plugin::")) {
|
|
352
|
+
newContentTypes[key] = {
|
|
353
|
+
collectionName: key.split(".").pop() || key,
|
|
354
|
+
seoChecks: { ...DEFAULT_SEO_CHECKS }
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
await pluginStore.set({ key: "settings", value: newContentTypes });
|
|
359
|
+
return pluginStore.get({ key: "settings" });
|
|
360
|
+
};
|
|
361
|
+
const getSettings = async () => {
|
|
362
|
+
const pluginStore = getPluginStore();
|
|
363
|
+
const stored = await pluginStore.get({ key: "settings" });
|
|
364
|
+
if (!isPlainRecord(stored)) {
|
|
365
|
+
return createDefaultConfig();
|
|
366
|
+
}
|
|
367
|
+
const config2 = sanitizeSeoSettingsMap(stored);
|
|
368
|
+
let updated = false;
|
|
369
|
+
const keys = Object.keys(strapi.contentTypes || {});
|
|
370
|
+
keys.forEach((key) => {
|
|
371
|
+
if ((key.includes("api::") || key.includes("plugin::")) && !Object.prototype.hasOwnProperty.call(config2, key)) {
|
|
372
|
+
config2[key] = {
|
|
373
|
+
collectionName: key.split(".").pop() || key,
|
|
374
|
+
seoChecks: { ...DEFAULT_SEO_CHECKS }
|
|
375
|
+
};
|
|
376
|
+
updated = true;
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
if (updated) {
|
|
380
|
+
await pluginStore.set({ key: "settings", value: config2 });
|
|
381
|
+
}
|
|
382
|
+
return config2;
|
|
383
|
+
};
|
|
384
|
+
const setSettings = async (data) => {
|
|
385
|
+
const pluginStore = getPluginStore();
|
|
386
|
+
const sanitized = sanitizeSeoSettingsMap(data);
|
|
387
|
+
const existingRaw = await pluginStore.get({
|
|
388
|
+
key: "settings"
|
|
389
|
+
});
|
|
390
|
+
const existing = isPlainRecord(existingRaw) ? sanitizeSeoSettingsMap(existingRaw) : {};
|
|
391
|
+
const merged = {
|
|
392
|
+
...existing,
|
|
393
|
+
...sanitized
|
|
394
|
+
};
|
|
395
|
+
await pluginStore.set({ key: "settings", value: merged });
|
|
396
|
+
return pluginStore.get({ key: "settings" });
|
|
397
|
+
};
|
|
398
|
+
return {
|
|
399
|
+
getSettings,
|
|
400
|
+
setSettings
|
|
401
|
+
};
|
|
402
|
+
};
|
|
403
|
+
const services = {
|
|
404
|
+
seo: seoService,
|
|
405
|
+
settings: settingsService
|
|
406
|
+
};
|
|
407
|
+
const index = {
|
|
408
|
+
register,
|
|
409
|
+
bootstrap,
|
|
410
|
+
destroy,
|
|
411
|
+
config,
|
|
412
|
+
controllers,
|
|
413
|
+
routes,
|
|
414
|
+
services
|
|
415
|
+
};
|
|
416
|
+
exports.default = index;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
declare const _default: {
|
|
2
|
+
register: (_context: {
|
|
3
|
+
strapi: import("@strapi/strapi").Core.Strapi;
|
|
4
|
+
}) => void;
|
|
5
|
+
bootstrap: ({ strapi }: {
|
|
6
|
+
strapi: import("@strapi/strapi").Core.Strapi;
|
|
7
|
+
}) => Promise<void>;
|
|
8
|
+
destroy: (_context: {
|
|
9
|
+
strapi: import("@strapi/strapi").Core.Strapi;
|
|
10
|
+
}) => void;
|
|
11
|
+
config: {
|
|
12
|
+
default: {};
|
|
13
|
+
validator(): void;
|
|
14
|
+
};
|
|
15
|
+
controllers: {
|
|
16
|
+
seo: ({ strapi }: {
|
|
17
|
+
strapi: import("@strapi/strapi").Core.Strapi;
|
|
18
|
+
}) => {
|
|
19
|
+
findSeoComponent(ctx: import('./controllers/seo').SeoControllerContext): unknown;
|
|
20
|
+
findContentTypes(ctx: import('./controllers/seo').SeoControllerContext): unknown;
|
|
21
|
+
createSeoComponent(ctx: import('./controllers/seo').SeoControllerContext): Promise<unknown>;
|
|
22
|
+
};
|
|
23
|
+
settings: ({ strapi }: {
|
|
24
|
+
strapi: import("@strapi/strapi").Core.Strapi;
|
|
25
|
+
}) => {
|
|
26
|
+
getSettings: (ctx: import('./controllers/settings').SettingsControllerContext) => Promise<import('../../shared').SeoSettingsMap | undefined>;
|
|
27
|
+
setSettings: (ctx: import('./controllers/settings').SettingsControllerContext) => Promise<unknown>;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
routes: {
|
|
31
|
+
seo: {
|
|
32
|
+
type: string;
|
|
33
|
+
routes: {
|
|
34
|
+
method: string;
|
|
35
|
+
path: string;
|
|
36
|
+
handler: string;
|
|
37
|
+
config: {
|
|
38
|
+
policies: (string | {
|
|
39
|
+
name: string;
|
|
40
|
+
config: {
|
|
41
|
+
actions: string[];
|
|
42
|
+
};
|
|
43
|
+
})[];
|
|
44
|
+
};
|
|
45
|
+
}[];
|
|
46
|
+
};
|
|
47
|
+
settings: {
|
|
48
|
+
type: string;
|
|
49
|
+
routes: {
|
|
50
|
+
method: string;
|
|
51
|
+
path: string;
|
|
52
|
+
handler: string;
|
|
53
|
+
config: {
|
|
54
|
+
policies: (string | {
|
|
55
|
+
name: string;
|
|
56
|
+
config: {
|
|
57
|
+
actions: string[];
|
|
58
|
+
};
|
|
59
|
+
})[];
|
|
60
|
+
};
|
|
61
|
+
}[];
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
services: {
|
|
65
|
+
seo: ({ strapi }: {
|
|
66
|
+
strapi: import("@strapi/strapi").Core.Strapi;
|
|
67
|
+
}) => {
|
|
68
|
+
getSeoComponent(): {
|
|
69
|
+
attributes: Record<string, unknown> | undefined;
|
|
70
|
+
category: string | undefined;
|
|
71
|
+
} | null;
|
|
72
|
+
getContentTypes(): import('../../shared').ContentTypesResponse;
|
|
73
|
+
createSeoComponent(): Promise<unknown>;
|
|
74
|
+
};
|
|
75
|
+
settings: ({ strapi }: {
|
|
76
|
+
strapi: import("@strapi/strapi").Core.Strapi;
|
|
77
|
+
}) => {
|
|
78
|
+
getSettings: () => Promise<import('../../shared').SeoSettingsMap>;
|
|
79
|
+
setSettings: (data: import('../../shared').SeoSettingsMap) => Promise<import('../../shared').SeoSettingsMap>;
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
export default _default;
|