@elementor/editor-audits 4.3.3 → 4.3.4
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/index.d.mts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +560 -294
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +549 -273
- package/dist/index.mjs.map +1 -1
- package/package.json +15 -13
- package/src/api/page-context-client.ts +8 -5
- package/src/audits/accessibility-statement.ts +39 -0
- package/src/audits/accessibility-widget.ts +41 -0
- package/src/audits/google-consent-mode.ts +4 -7
- package/src/audits/images-inefficient-format.ts +67 -0
- package/src/audits/images-too-large.ts +23 -9
- package/src/components/violation-cta-button.tsx +3 -2
- package/src/components/violation-row.tsx +13 -4
- package/src/register-audits.ts +6 -0
- package/src/register-promotions.ts +23 -0
- package/src/runner.ts +9 -5
- package/src/types.ts +9 -1
- package/src/utils/atomic-background-image-sources.ts +56 -0
- package/src/utils/atomic-image-sources.ts +62 -0
- package/src/utils/background-image-sources.ts +32 -0
- package/src/utils/image-alt.ts +3 -1
- package/src/utils/image-like-sources.ts +5 -2
- package/src/utils/image-size-key.ts +8 -0
- package/src/utils/page-attachments.ts +16 -7
- package/src/utils/scan-accessibility-widgets.ts +7 -0
package/dist/index.mjs
CHANGED
|
@@ -77,17 +77,17 @@ async function requestFreshNonce() {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
// src/api/page-context-client.ts
|
|
80
|
-
async function fetchPageContext(documentId,
|
|
81
|
-
return requestPageContext(documentId,
|
|
80
|
+
async function fetchPageContext(documentId, imageSizeRequests) {
|
|
81
|
+
return requestPageContext(documentId, imageSizeRequests, true);
|
|
82
82
|
}
|
|
83
|
-
async function requestPageContext(documentId,
|
|
83
|
+
async function requestPageContext(documentId, imageSizeRequests, allowNonceRetry) {
|
|
84
84
|
const { restNamespace, nonce } = getWindowConfig();
|
|
85
85
|
const url = `${restNamespace}/audits/page-context`;
|
|
86
86
|
try {
|
|
87
87
|
const response = await httpService().get(url, {
|
|
88
88
|
params: {
|
|
89
89
|
document_id: documentId,
|
|
90
|
-
|
|
90
|
+
image_size_requests: imageSizeRequests
|
|
91
91
|
},
|
|
92
92
|
headers: { "X-WP-Nonce": nonce }
|
|
93
93
|
});
|
|
@@ -97,14 +97,14 @@ async function requestPageContext(documentId, attachmentIds, allowNonceRetry) {
|
|
|
97
97
|
throw error;
|
|
98
98
|
}
|
|
99
99
|
await refreshAuditsNonce();
|
|
100
|
-
return requestPageContext(documentId,
|
|
100
|
+
return requestPageContext(documentId, imageSizeRequests, false);
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
103
|
|
|
104
104
|
// src/registry.ts
|
|
105
105
|
var registry = /* @__PURE__ */ new Map();
|
|
106
|
-
function registerAudit(
|
|
107
|
-
registry.set(
|
|
106
|
+
function registerAudit(audit26) {
|
|
107
|
+
registry.set(audit26.id, audit26);
|
|
108
108
|
}
|
|
109
109
|
function getRegisteredAudits() {
|
|
110
110
|
return Array.from(registry.values());
|
|
@@ -141,8 +141,8 @@ var CATEGORY_LABELS = {
|
|
|
141
141
|
import { __ as __2 } from "@wordpress/i18n";
|
|
142
142
|
|
|
143
143
|
// src/utils/is-scored-audit.ts
|
|
144
|
-
function isScoredAudit(
|
|
145
|
-
return
|
|
144
|
+
function isScoredAudit(audit26) {
|
|
145
|
+
return audit26.weight > 0;
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
// src/utils/sort-failed-audits.ts
|
|
@@ -198,8 +198,8 @@ function auditStatusDisplayCounts(report) {
|
|
|
198
198
|
let pass = 0;
|
|
199
199
|
let skipped = 0;
|
|
200
200
|
let totalViolations = 0;
|
|
201
|
-
for (const { audit:
|
|
202
|
-
if (!isScoredAudit(
|
|
201
|
+
for (const { audit: audit26, result } of report.auditResults) {
|
|
202
|
+
if (!isScoredAudit(audit26)) {
|
|
203
203
|
continue;
|
|
204
204
|
}
|
|
205
205
|
switch (result.status) {
|
|
@@ -249,16 +249,16 @@ function computeReport(documentId, results) {
|
|
|
249
249
|
const accumulators = Object.fromEntries(
|
|
250
250
|
ALL_CATEGORIES.map((c) => [c, { totalWeight: 0, passedWeight: 0, total: 0, failed: 0 }])
|
|
251
251
|
);
|
|
252
|
-
for (const { audit:
|
|
252
|
+
for (const { audit: audit26, result } of results) {
|
|
253
253
|
if (result.status === "skipped") {
|
|
254
254
|
continue;
|
|
255
255
|
}
|
|
256
|
-
for (const category of
|
|
256
|
+
for (const category of audit26.categories) {
|
|
257
257
|
const acc = accumulators[category];
|
|
258
258
|
acc.total++;
|
|
259
|
-
acc.totalWeight +=
|
|
259
|
+
acc.totalWeight += audit26.weight;
|
|
260
260
|
if (result.status === "pass") {
|
|
261
|
-
acc.passedWeight +=
|
|
261
|
+
acc.passedWeight += audit26.weight;
|
|
262
262
|
} else {
|
|
263
263
|
acc.failed++;
|
|
264
264
|
}
|
|
@@ -282,6 +282,44 @@ function computeReport(documentId, results) {
|
|
|
282
282
|
};
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
+
// src/utils/fetch-rendered-html.ts
|
|
286
|
+
var FETCH_TIMEOUT_MS = 1e4;
|
|
287
|
+
async function fetchRenderedHtml(url) {
|
|
288
|
+
if (!url) {
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
const timeoutController = new AbortController();
|
|
292
|
+
const timeoutId = setTimeout(() => timeoutController.abort(), FETCH_TIMEOUT_MS);
|
|
293
|
+
try {
|
|
294
|
+
const response = await fetch(url, { credentials: "omit", signal: timeoutController.signal });
|
|
295
|
+
if (!response.ok) {
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
return await response.text();
|
|
299
|
+
} catch {
|
|
300
|
+
return null;
|
|
301
|
+
} finally {
|
|
302
|
+
clearTimeout(timeoutId);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// src/utils/atomic-background-image-sources.ts
|
|
307
|
+
import { getElementStyles } from "@elementor/editor-elements";
|
|
308
|
+
import {
|
|
309
|
+
backgroundImageOverlayPropTypeUtil,
|
|
310
|
+
backgroundOverlayPropTypeUtil,
|
|
311
|
+
backgroundPropTypeUtil
|
|
312
|
+
} from "@elementor/editor-props";
|
|
313
|
+
|
|
314
|
+
// src/utils/atomic-image-sources.ts
|
|
315
|
+
import {
|
|
316
|
+
imageAttachmentIdPropType,
|
|
317
|
+
imagePropTypeUtil,
|
|
318
|
+
imageSrcPropTypeUtil,
|
|
319
|
+
stringPropTypeUtil,
|
|
320
|
+
urlPropTypeUtil
|
|
321
|
+
} from "@elementor/editor-props";
|
|
322
|
+
|
|
285
323
|
// src/utils/walk.ts
|
|
286
324
|
function walkElements(tree, visit) {
|
|
287
325
|
const parents = [];
|
|
@@ -296,6 +334,89 @@ function recurse(nodes, parents, visit) {
|
|
|
296
334
|
}
|
|
297
335
|
}
|
|
298
336
|
|
|
337
|
+
// src/utils/atomic-image-sources.ts
|
|
338
|
+
var ATOMIC_IMAGE_PROP_KEYS = ["image", "poster"];
|
|
339
|
+
function walkAtomicImageSources(tree, visit) {
|
|
340
|
+
walkElements(tree, (node) => {
|
|
341
|
+
if (node.elType !== "widget") {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
for (const key of ATOMIC_IMAGE_PROP_KEYS) {
|
|
345
|
+
const media = extractAtomicImageMedia(node.settings[key]);
|
|
346
|
+
if (media) {
|
|
347
|
+
visit({ node, media });
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
function extractAtomicImageMedia(imageProp) {
|
|
353
|
+
const image = imagePropTypeUtil.extract(imageProp);
|
|
354
|
+
if (!image) {
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
const src = imageSrcPropTypeUtil.extract(image.src);
|
|
358
|
+
if (!src) {
|
|
359
|
+
return null;
|
|
360
|
+
}
|
|
361
|
+
const id = imageAttachmentIdPropType.extract(src.id) ?? void 0;
|
|
362
|
+
const url = urlPropTypeUtil.extract(src.url) ?? void 0;
|
|
363
|
+
if (!id && !url) {
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
const size = stringPropTypeUtil.extract(image.size) ?? void 0;
|
|
367
|
+
return { id, url, size };
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// src/utils/atomic-background-image-sources.ts
|
|
371
|
+
function walkAtomicBackgroundImageSources(tree, visit) {
|
|
372
|
+
walkElements(tree, (node) => {
|
|
373
|
+
const styles = getElementStyles(node.id);
|
|
374
|
+
if (!styles) {
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
for (const media of extractBackgroundImageMedia(styles)) {
|
|
378
|
+
visit({ node, media });
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
function extractBackgroundImageMedia(styles) {
|
|
383
|
+
const sources = [];
|
|
384
|
+
for (const style of Object.values(styles)) {
|
|
385
|
+
for (const variant of style.variants) {
|
|
386
|
+
const background = backgroundPropTypeUtil.extract(variant.props.background);
|
|
387
|
+
const overlays = backgroundOverlayPropTypeUtil.extract(background?.["background-overlay"]) ?? [];
|
|
388
|
+
for (const overlay of overlays) {
|
|
389
|
+
const imageOverlay = backgroundImageOverlayPropTypeUtil.extract(overlay);
|
|
390
|
+
const media = extractAtomicImageMedia(imageOverlay?.image);
|
|
391
|
+
if (media) {
|
|
392
|
+
sources.push(media);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return sources;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// src/utils/background-image-sources.ts
|
|
401
|
+
var BACKGROUND_IMAGE_SETTING_KEYS = [
|
|
402
|
+
"background_image",
|
|
403
|
+
"background_hover_image",
|
|
404
|
+
"background_overlay_image",
|
|
405
|
+
"background_overlay_hover_image",
|
|
406
|
+
"_background_image",
|
|
407
|
+
"_background_hover_image"
|
|
408
|
+
];
|
|
409
|
+
function walkBackgroundImageSources(tree, visit) {
|
|
410
|
+
walkElements(tree, (node) => {
|
|
411
|
+
for (const key of BACKGROUND_IMAGE_SETTING_KEYS) {
|
|
412
|
+
const media = node.settings[key];
|
|
413
|
+
if (media?.id || media?.url) {
|
|
414
|
+
visit({ node, media });
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
|
|
299
420
|
// src/utils/image-like-sources.ts
|
|
300
421
|
var IMAGE_LIKE_WIDGETS = /* @__PURE__ */ new Set(["image", "image-box", "image-carousel", "gallery", "image-gallery"]);
|
|
301
422
|
function hasPageImages(tree) {
|
|
@@ -324,28 +445,38 @@ function collectMediaFromNode(node) {
|
|
|
324
445
|
const sources = [];
|
|
325
446
|
const image = node.settings.image;
|
|
326
447
|
if (image?.id || image?.url) {
|
|
327
|
-
sources.push(image);
|
|
448
|
+
sources.push({ ...image, size: node.settings.image_size });
|
|
328
449
|
}
|
|
329
450
|
const gallery = node.settings.carousel ?? node.settings.gallery ?? node.settings.wp_gallery;
|
|
330
451
|
if (Array.isArray(gallery)) {
|
|
452
|
+
const gallerySize = node.settings.thumbnail_size;
|
|
331
453
|
for (const item of gallery) {
|
|
332
454
|
if (item?.id || item?.url) {
|
|
333
|
-
sources.push(item);
|
|
455
|
+
sources.push({ ...item, size: gallerySize });
|
|
334
456
|
}
|
|
335
457
|
}
|
|
336
458
|
}
|
|
337
459
|
return sources;
|
|
338
460
|
}
|
|
339
461
|
|
|
462
|
+
// src/utils/image-size-key.ts
|
|
463
|
+
function buildImageSizeKey({ id, size }) {
|
|
464
|
+
return `${id}:${size || "full"}`;
|
|
465
|
+
}
|
|
466
|
+
|
|
340
467
|
// src/utils/page-attachments.ts
|
|
341
|
-
function
|
|
342
|
-
const
|
|
343
|
-
|
|
468
|
+
function extractImageSizeRequests(tree) {
|
|
469
|
+
const keys = /* @__PURE__ */ new Set();
|
|
470
|
+
const collect = (media) => {
|
|
344
471
|
if (media.id) {
|
|
345
|
-
|
|
472
|
+
keys.add(buildImageSizeKey({ id: media.id, size: media.size }));
|
|
346
473
|
}
|
|
347
|
-
}
|
|
348
|
-
|
|
474
|
+
};
|
|
475
|
+
walkImageLikeSources(tree, ({ media }) => collect(media));
|
|
476
|
+
walkBackgroundImageSources(tree, ({ media }) => collect(media));
|
|
477
|
+
walkAtomicImageSources(tree, ({ media }) => collect(media));
|
|
478
|
+
walkAtomicBackgroundImageSources(tree, ({ media }) => collect(media));
|
|
479
|
+
return Array.from(keys).sort();
|
|
349
480
|
}
|
|
350
481
|
|
|
351
482
|
// src/utils/read-kit-snapshot.ts
|
|
@@ -440,17 +571,20 @@ function toSnapshot(element) {
|
|
|
440
571
|
// src/runner.ts
|
|
441
572
|
async function runPageAudit(documentId) {
|
|
442
573
|
const tree = buildSnapshotTree(getElements());
|
|
443
|
-
const
|
|
444
|
-
const pageContext = await fetchPageContext(documentId,
|
|
574
|
+
const imageSizeRequests = extractImageSizeRequests(tree);
|
|
575
|
+
const pageContext = await fetchPageContext(documentId, imageSizeRequests);
|
|
445
576
|
const elements = { documentId, tree };
|
|
446
|
-
const kit = await
|
|
447
|
-
|
|
577
|
+
const [kit, renderedHtml] = await Promise.all([
|
|
578
|
+
readKitSnapshot(pageContext.kit_id),
|
|
579
|
+
fetchRenderedHtml(pageContext.frontend_url)
|
|
580
|
+
]);
|
|
581
|
+
const ctx = { documentId, elements, pageContext, kit, renderedHtml };
|
|
448
582
|
const registered = getRegisteredAudits();
|
|
449
583
|
const auditResults = await Promise.all(
|
|
450
|
-
registered.map(async (
|
|
451
|
-
const { evaluate: _evaluate, ...meta } =
|
|
584
|
+
registered.map(async (audit26) => {
|
|
585
|
+
const { evaluate: _evaluate, ...meta } = audit26;
|
|
452
586
|
try {
|
|
453
|
-
const result = await
|
|
587
|
+
const result = await audit26.evaluate(ctx);
|
|
454
588
|
return { audit: meta, result };
|
|
455
589
|
} catch (error) {
|
|
456
590
|
const reason = error instanceof Error ? error.message : "unknown-error";
|
|
@@ -912,13 +1046,13 @@ function SeverityIcon({ severity }) {
|
|
|
912
1046
|
// src/components/violation-cta-button.tsx
|
|
913
1047
|
import * as React9 from "react";
|
|
914
1048
|
import { Button as Button3 } from "@elementor/ui";
|
|
915
|
-
function ViolationCtaButton({ ctaLabel, externalUrl }) {
|
|
1049
|
+
function ViolationCtaButton({ ctaLabel, externalUrl, variant = "outlined" }) {
|
|
916
1050
|
const handleClick = (event) => {
|
|
917
1051
|
event.stopPropagation();
|
|
918
1052
|
event.preventDefault();
|
|
919
1053
|
window.open(externalUrl, "_blank", "noopener");
|
|
920
1054
|
};
|
|
921
|
-
return /* @__PURE__ */ React9.createElement(Button3, { variant
|
|
1055
|
+
return /* @__PURE__ */ React9.createElement(Button3, { variant, color: "secondary", size: "small", onClick: handleClick }, ctaLabel);
|
|
922
1056
|
}
|
|
923
1057
|
|
|
924
1058
|
// src/components/violation-icons.tsx
|
|
@@ -950,13 +1084,13 @@ function ViolationIcon({ violation, widgetIcon }) {
|
|
|
950
1084
|
function SkipReasonTooltip({ reason }) {
|
|
951
1085
|
return /* @__PURE__ */ React11.createElement(Tooltip3, { title: reason, placement: "top" }, /* @__PURE__ */ React11.createElement(Box7, { "aria-label": reason, component: "span", sx: { display: "inline-flex", alignItems: "center" } }, /* @__PURE__ */ React11.createElement(HelpIcon, { fontSize: "small", color: "action" })));
|
|
952
1086
|
}
|
|
953
|
-
function StatusIndicator({ audit:
|
|
1087
|
+
function StatusIndicator({ audit: audit26, violations }) {
|
|
954
1088
|
if (violations) {
|
|
955
|
-
return /* @__PURE__ */ React11.createElement(React11.Fragment, null, isScoredAudit(
|
|
1089
|
+
return /* @__PURE__ */ React11.createElement(React11.Fragment, null, isScoredAudit(audit26) && /* @__PURE__ */ React11.createElement(Typography6, { variant: "caption", color: "text.secondary", fontWeight: "bold" }, violations.length), /* @__PURE__ */ React11.createElement(SeverityIcon, { severity: audit26.severity }));
|
|
956
1090
|
}
|
|
957
1091
|
return /* @__PURE__ */ React11.createElement(CheckIcon, { fontSize: "small", color: "success" });
|
|
958
1092
|
}
|
|
959
|
-
function ViolationRow({ audit:
|
|
1093
|
+
function ViolationRow({ audit: audit26, skipReason, violations }) {
|
|
960
1094
|
const [expanded, setExpanded] = useState3(false);
|
|
961
1095
|
const toggleExpanded = () => setExpanded((value) => !value);
|
|
962
1096
|
return /* @__PURE__ */ React11.createElement(Box7, { sx: { borderBottom: 1, borderColor: "divider", paddingBlock: 0.5 } }, /* @__PURE__ */ React11.createElement(Box7, { sx: { display: "flex", alignItems: "center", gap: 0.5 } }, /* @__PURE__ */ React11.createElement(
|
|
@@ -972,8 +1106,8 @@ function ViolationRow({ audit: audit23, skipReason, violations }) {
|
|
|
972
1106
|
},
|
|
973
1107
|
onClick: toggleExpanded
|
|
974
1108
|
},
|
|
975
|
-
/* @__PURE__ */ React11.createElement(Typography6, { variant: "body2", sx: { flex: 1 } },
|
|
976
|
-
!skipReason && /* @__PURE__ */ React11.createElement(StatusIndicator, { audit:
|
|
1109
|
+
/* @__PURE__ */ React11.createElement(Typography6, { variant: "body2", sx: { flex: 1 } }, audit26.title),
|
|
1110
|
+
!skipReason && /* @__PURE__ */ React11.createElement(StatusIndicator, { audit: audit26, violations })
|
|
977
1111
|
), skipReason && /* @__PURE__ */ React11.createElement(SkipReasonTooltip, { reason: skipReason }), /* @__PURE__ */ React11.createElement(
|
|
978
1112
|
IconButton5,
|
|
979
1113
|
{
|
|
@@ -999,7 +1133,7 @@ function ViolationRow({ audit: audit23, skipReason, violations }) {
|
|
|
999
1133
|
icon: /* @__PURE__ */ React11.createElement(AlertCircleIcon2, { fontSize: "small", color: "secondary", "aria-hidden": true })
|
|
1000
1134
|
},
|
|
1001
1135
|
/* @__PURE__ */ React11.createElement(AlertTitle, null, /* @__PURE__ */ React11.createElement(Typography6, { variant: "caption", component: "p", color: "text.primary", fontWeight: "bold" }, __11("What's the issue", "elementor"))),
|
|
1002
|
-
/* @__PURE__ */ React11.createElement(Typography6, { variant: "caption", component: "p", color: "text.secondary" },
|
|
1136
|
+
/* @__PURE__ */ React11.createElement(Typography6, { variant: "caption", component: "p", color: "text.secondary" }, audit26.description)
|
|
1003
1137
|
), /* @__PURE__ */ React11.createElement(
|
|
1004
1138
|
Alert,
|
|
1005
1139
|
{
|
|
@@ -1008,7 +1142,7 @@ function ViolationRow({ audit: audit23, skipReason, violations }) {
|
|
|
1008
1142
|
icon: /* @__PURE__ */ React11.createElement(BulbIcon2, { fontSize: "small", color: "info", "aria-hidden": true })
|
|
1009
1143
|
},
|
|
1010
1144
|
/* @__PURE__ */ React11.createElement(AlertTitle, null, /* @__PURE__ */ React11.createElement(Typography6, { variant: "caption", component: "p", color: "text.primary", fontWeight: "bold" }, __11("How to resolve", "elementor"))),
|
|
1011
|
-
/* @__PURE__ */ React11.createElement(Typography6, { variant: "caption", component: "p", color: "text.secondary" },
|
|
1145
|
+
/* @__PURE__ */ React11.createElement(Typography6, { variant: "caption", component: "p", color: "text.secondary" }, audit26.fixHint)
|
|
1012
1146
|
)), violations && violations.length > 0 && /* @__PURE__ */ React11.createElement(Box7, { role: "list", sx: { paddingBlockEnd: 1, paddingInlineStart: 2 } }, violations.map((violation, idx) => {
|
|
1013
1147
|
const widgetIcon = violation.elementId ? getElementIcon(violation.elementId) : null;
|
|
1014
1148
|
const elementTitle = violation.elementId ? getElementTitle(violation.elementId) : null;
|
|
@@ -1044,13 +1178,20 @@ function ViolationRow({ audit: audit23, skipReason, violations }) {
|
|
|
1044
1178
|
prompt: violation.angiePrompt ?? buildAngiePrompt(rowLabel)
|
|
1045
1179
|
}
|
|
1046
1180
|
),
|
|
1047
|
-
violation.ctaLabel && violation.externalUrl ? /* @__PURE__ */ React11.createElement(
|
|
1181
|
+
violation.ctaLabel && violation.externalUrl ? /* @__PURE__ */ React11.createElement(Box7, { sx: { display: "flex", alignItems: "center", gap: 0.5 } }, /* @__PURE__ */ React11.createElement(
|
|
1048
1182
|
ViolationCtaButton,
|
|
1049
1183
|
{
|
|
1050
1184
|
ctaLabel: violation.ctaLabel,
|
|
1051
1185
|
externalUrl: violation.externalUrl
|
|
1052
1186
|
}
|
|
1053
|
-
)
|
|
1187
|
+
), violation.secondaryCtaLabel && violation.secondaryCtaUrl && /* @__PURE__ */ React11.createElement(
|
|
1188
|
+
ViolationCtaButton,
|
|
1189
|
+
{
|
|
1190
|
+
ctaLabel: violation.secondaryCtaLabel,
|
|
1191
|
+
externalUrl: violation.secondaryCtaUrl,
|
|
1192
|
+
variant: "text"
|
|
1193
|
+
}
|
|
1194
|
+
)) : /* @__PURE__ */ React11.createElement(
|
|
1054
1195
|
EyeIcon,
|
|
1055
1196
|
{
|
|
1056
1197
|
className: "violation-hover-icon",
|
|
@@ -1148,17 +1289,17 @@ import { __ as __14 } from "@wordpress/i18n";
|
|
|
1148
1289
|
var ALL_SEVERITIES = ["error", "warning", "info"];
|
|
1149
1290
|
function countSeverities(report, category) {
|
|
1150
1291
|
const counts = { error: 0, warning: 0, info: 0 };
|
|
1151
|
-
for (const { audit:
|
|
1292
|
+
for (const { audit: audit26, result } of report.auditResults) {
|
|
1152
1293
|
if (result.status !== "fail") {
|
|
1153
1294
|
continue;
|
|
1154
1295
|
}
|
|
1155
|
-
if (category && !
|
|
1296
|
+
if (category && !audit26.categories.includes(category)) {
|
|
1156
1297
|
continue;
|
|
1157
1298
|
}
|
|
1158
|
-
if (!isScoredAudit(
|
|
1299
|
+
if (!isScoredAudit(audit26)) {
|
|
1159
1300
|
continue;
|
|
1160
1301
|
}
|
|
1161
|
-
counts[
|
|
1302
|
+
counts[audit26.severity] += result.violations.length;
|
|
1162
1303
|
}
|
|
1163
1304
|
return counts;
|
|
1164
1305
|
}
|
|
@@ -1461,6 +1602,26 @@ var PROMOTIONS = [
|
|
|
1461
1602
|
);
|
|
1462
1603
|
},
|
|
1463
1604
|
getCtaUrl: firstFailExternalUrl
|
|
1605
|
+
},
|
|
1606
|
+
{
|
|
1607
|
+
auditId: "audits/images-inefficient-format",
|
|
1608
|
+
icon: ShieldHalfFilledIcon,
|
|
1609
|
+
ctaLabel: __19("Optimize all", "elementor"),
|
|
1610
|
+
formatSubtitle: (run) => {
|
|
1611
|
+
if (run.result.status !== "fail") {
|
|
1612
|
+
return null;
|
|
1613
|
+
}
|
|
1614
|
+
const count = run.result.metadata?.inefficientImageFormatCount ?? 0;
|
|
1615
|
+
if (count === 0) {
|
|
1616
|
+
return null;
|
|
1617
|
+
}
|
|
1618
|
+
return sprintf3(
|
|
1619
|
+
/* translators: %d: number of images served in an inefficient format. */
|
|
1620
|
+
_n("%d image", "%d images", count, "elementor"),
|
|
1621
|
+
count
|
|
1622
|
+
);
|
|
1623
|
+
},
|
|
1624
|
+
getCtaUrl: firstFailExternalUrl
|
|
1464
1625
|
}
|
|
1465
1626
|
];
|
|
1466
1627
|
|
|
@@ -1842,16 +2003,93 @@ var audit = {
|
|
|
1842
2003
|
}
|
|
1843
2004
|
};
|
|
1844
2005
|
|
|
1845
|
-
// src/audits/
|
|
2006
|
+
// src/audits/accessibility-statement.ts
|
|
1846
2007
|
import { __ as __26 } from "@wordpress/i18n";
|
|
1847
2008
|
var audit2 = {
|
|
1848
|
-
id: "audits/
|
|
1849
|
-
title: __26("
|
|
2009
|
+
id: "audits/accessibility-statement",
|
|
2010
|
+
title: __26("Create an accessibility statement", "elementor"),
|
|
1850
2011
|
description: __26(
|
|
2012
|
+
"An accessibility statement showcases your efforts to create an inclusive online space, highlighting helpful features and a commitment to accessibility.",
|
|
2013
|
+
"elementor"
|
|
2014
|
+
),
|
|
2015
|
+
fixHint: __26("Use Ally to create and publish an accessibility statement for your site.", "elementor"),
|
|
2016
|
+
categories: ["accessibility"],
|
|
2017
|
+
severity: "info",
|
|
2018
|
+
weight: 1,
|
|
2019
|
+
evaluate: (ctx) => {
|
|
2020
|
+
const isReady = ctx.pageContext.ally_plugin_active;
|
|
2021
|
+
if (isReady && ctx.pageContext.ally_accessibility_statement_created) {
|
|
2022
|
+
return { status: "pass" };
|
|
2023
|
+
}
|
|
2024
|
+
return {
|
|
2025
|
+
status: "fail",
|
|
2026
|
+
violations: [
|
|
2027
|
+
{
|
|
2028
|
+
auditId: audit2.id,
|
|
2029
|
+
label: __26("No accessibility statement has been created for this site.", "elementor"),
|
|
2030
|
+
externalUrl: isReady ? ctx.pageContext.ally_accessibility_statement_url : ctx.pageContext.ally_plugin_url,
|
|
2031
|
+
ctaLabel: isReady ? __26("Create", "elementor") : void 0,
|
|
2032
|
+
secondaryCtaLabel: __26("Learn more", "elementor"),
|
|
2033
|
+
secondaryCtaUrl: "https://go.elementor.com/acc-plg-learn-more"
|
|
2034
|
+
}
|
|
2035
|
+
]
|
|
2036
|
+
};
|
|
2037
|
+
}
|
|
2038
|
+
};
|
|
2039
|
+
|
|
2040
|
+
// src/audits/accessibility-widget.ts
|
|
2041
|
+
import { __ as __27 } from "@wordpress/i18n";
|
|
2042
|
+
|
|
2043
|
+
// src/utils/scan-accessibility-widgets.ts
|
|
2044
|
+
var ACCESSIBILITY_WIDGET_SCRIPT_SOURCES = ["cdn.elementor.com/a11y/widget.js"];
|
|
2045
|
+
function hasAccessibilityWidgetScript(html) {
|
|
2046
|
+
return ACCESSIBILITY_WIDGET_SCRIPT_SOURCES.some((src) => html.includes(src));
|
|
2047
|
+
}
|
|
2048
|
+
|
|
2049
|
+
// src/audits/accessibility-widget.ts
|
|
2050
|
+
var audit3 = {
|
|
2051
|
+
id: "audits/accessibility-widget",
|
|
2052
|
+
title: __27("Add an accessibility widget", "elementor"),
|
|
2053
|
+
description: __27("Make your site more inclusive by adding an accessibility widget.", "elementor"),
|
|
2054
|
+
fixHint: __27("Activate Ally\u2019s accessibility widget to give visitors on-page accessibility tools.", "elementor"),
|
|
2055
|
+
categories: ["accessibility"],
|
|
2056
|
+
severity: "info",
|
|
2057
|
+
weight: 1,
|
|
2058
|
+
evaluate: (ctx) => {
|
|
2059
|
+
if (!ctx.pageContext.frontend_url) {
|
|
2060
|
+
return { status: "skipped", reason: __27("Page is not published.", "elementor") };
|
|
2061
|
+
}
|
|
2062
|
+
if (!ctx.renderedHtml) {
|
|
2063
|
+
return { status: "skipped", reason: __27("Could not fetch the published page.", "elementor") };
|
|
2064
|
+
}
|
|
2065
|
+
if (hasAccessibilityWidgetScript(ctx.renderedHtml)) {
|
|
2066
|
+
return { status: "pass" };
|
|
2067
|
+
}
|
|
2068
|
+
const isReady = ctx.pageContext.ally_plugin_active;
|
|
2069
|
+
return {
|
|
2070
|
+
status: "fail",
|
|
2071
|
+
violations: [
|
|
2072
|
+
{
|
|
2073
|
+
auditId: audit3.id,
|
|
2074
|
+
label: __27("No accessibility widget is active on this site.", "elementor"),
|
|
2075
|
+
externalUrl: isReady ? ctx.pageContext.ally_widget_settings_url : ctx.pageContext.ally_plugin_url,
|
|
2076
|
+
ctaLabel: __27("Activate", "elementor")
|
|
2077
|
+
}
|
|
2078
|
+
]
|
|
2079
|
+
};
|
|
2080
|
+
}
|
|
2081
|
+
};
|
|
2082
|
+
|
|
2083
|
+
// src/audits/cookie-policy.ts
|
|
2084
|
+
import { __ as __28 } from "@wordpress/i18n";
|
|
2085
|
+
var audit4 = {
|
|
2086
|
+
id: "audits/cookie-policy",
|
|
2087
|
+
title: __28("Cookie policy", "elementor"),
|
|
2088
|
+
description: __28(
|
|
1851
2089
|
"A cookie policy is required by privacy regulations such as GDPR (EU) or CCPA (US) to inform visitors about tracking and data collection.",
|
|
1852
2090
|
"elementor"
|
|
1853
2091
|
),
|
|
1854
|
-
fixHint:
|
|
2092
|
+
fixHint: __28("Install the Cookiez plugin to add a cookie policy to your website.", "elementor"),
|
|
1855
2093
|
categories: ["compliance"],
|
|
1856
2094
|
severity: "info",
|
|
1857
2095
|
weight: 1,
|
|
@@ -1863,8 +2101,8 @@ var audit2 = {
|
|
|
1863
2101
|
status: "fail",
|
|
1864
2102
|
violations: [
|
|
1865
2103
|
{
|
|
1866
|
-
auditId:
|
|
1867
|
-
label:
|
|
2104
|
+
auditId: audit4.id,
|
|
2105
|
+
label: __28("Cookiez plugin is not installed or active.", "elementor"),
|
|
1868
2106
|
externalUrl: ctx.pageContext.cookiez_plugin_url
|
|
1869
2107
|
}
|
|
1870
2108
|
]
|
|
@@ -1874,7 +2112,7 @@ var audit2 = {
|
|
|
1874
2112
|
|
|
1875
2113
|
// src/audits/deep-nesting.ts
|
|
1876
2114
|
import { getWidgetsCache } from "@elementor/editor-elements";
|
|
1877
|
-
import { __ as
|
|
2115
|
+
import { __ as __29 } from "@wordpress/i18n";
|
|
1878
2116
|
var MAX_NESTING_DEPTH = 6;
|
|
1879
2117
|
function isNestingElement(node, widgetsCache) {
|
|
1880
2118
|
if (node.elType === "container") {
|
|
@@ -1882,20 +2120,20 @@ function isNestingElement(node, widgetsCache) {
|
|
|
1882
2120
|
}
|
|
1883
2121
|
return !!widgetsCache?.[node.elType]?.meta?.is_container;
|
|
1884
2122
|
}
|
|
1885
|
-
var
|
|
2123
|
+
var audit5 = {
|
|
1886
2124
|
id: "audits/deep-nesting",
|
|
1887
|
-
title:
|
|
1888
|
-
description:
|
|
2125
|
+
title: __29("Deep container nesting", "elementor"),
|
|
2126
|
+
description: __29(
|
|
1889
2127
|
"Container nesting exceeds the recommended depth. Deep DOM trees hurt rendering performance and readability.",
|
|
1890
2128
|
"elementor"
|
|
1891
2129
|
),
|
|
1892
|
-
fixHint:
|
|
2130
|
+
fixHint: __29("Flatten the layout by removing unnecessary wrapper containers.", "elementor"),
|
|
1893
2131
|
categories: ["performance", "best-practices"],
|
|
1894
2132
|
severity: "warning",
|
|
1895
2133
|
weight: 5,
|
|
1896
2134
|
evaluate: (ctx) => {
|
|
1897
2135
|
if (ctx.elements.tree.length === 0) {
|
|
1898
|
-
return { status: "skipped", reason:
|
|
2136
|
+
return { status: "skipped", reason: __29("No elements", "elementor") };
|
|
1899
2137
|
}
|
|
1900
2138
|
const widgetsCache = getWidgetsCache();
|
|
1901
2139
|
const violations = [];
|
|
@@ -1906,10 +2144,10 @@ var audit3 = {
|
|
|
1906
2144
|
const depth = parents.filter((parent) => isNestingElement(parent, widgetsCache)).length + 1;
|
|
1907
2145
|
if (depth > MAX_NESTING_DEPTH) {
|
|
1908
2146
|
violations.push({
|
|
1909
|
-
auditId:
|
|
2147
|
+
auditId: audit5.id,
|
|
1910
2148
|
elementId: node.id,
|
|
1911
2149
|
targetHint: "element-settings",
|
|
1912
|
-
label:
|
|
2150
|
+
label: __29("Container nesting is too deep.", "elementor")
|
|
1913
2151
|
});
|
|
1914
2152
|
}
|
|
1915
2153
|
});
|
|
@@ -1918,15 +2156,15 @@ var audit3 = {
|
|
|
1918
2156
|
};
|
|
1919
2157
|
|
|
1920
2158
|
// src/audits/default-design-system.ts
|
|
1921
|
-
import { __ as
|
|
1922
|
-
var
|
|
2159
|
+
import { __ as __30 } from "@wordpress/i18n";
|
|
2160
|
+
var audit6 = {
|
|
1923
2161
|
id: "audits/default-design-system",
|
|
1924
|
-
title:
|
|
1925
|
-
description:
|
|
2162
|
+
title: __30("Default website kit", "elementor"),
|
|
2163
|
+
description: __30(
|
|
1926
2164
|
"Your website is using the default design system colors and fonts. Custom branding makes the website feel uniquely yours.",
|
|
1927
2165
|
"elementor"
|
|
1928
2166
|
),
|
|
1929
|
-
fixHint:
|
|
2167
|
+
fixHint: __30("Open Site Settings and customize your kit (colors, fonts, layout).", "elementor"),
|
|
1930
2168
|
categories: ["best-practices"],
|
|
1931
2169
|
severity: "info",
|
|
1932
2170
|
weight: 1,
|
|
@@ -1938,8 +2176,8 @@ var audit4 = {
|
|
|
1938
2176
|
status: "fail",
|
|
1939
2177
|
violations: [
|
|
1940
2178
|
{
|
|
1941
|
-
auditId:
|
|
1942
|
-
label:
|
|
2179
|
+
auditId: audit6.id,
|
|
2180
|
+
label: __30("Kit appears unchanged from default.", "elementor"),
|
|
1943
2181
|
targetHint: "site-settings"
|
|
1944
2182
|
}
|
|
1945
2183
|
]
|
|
@@ -1949,16 +2187,16 @@ var audit4 = {
|
|
|
1949
2187
|
|
|
1950
2188
|
// src/audits/deprecated-widgets.ts
|
|
1951
2189
|
import { getWidgetsCache as getWidgetsCache2 } from "@elementor/editor-elements";
|
|
1952
|
-
import { __ as
|
|
2190
|
+
import { __ as __31 } from "@wordpress/i18n";
|
|
1953
2191
|
var DEPRECATION_CONTROL_NAME = "deprecation_message";
|
|
1954
|
-
var
|
|
2192
|
+
var audit7 = {
|
|
1955
2193
|
id: "audits/deprecated-widgets",
|
|
1956
|
-
title:
|
|
1957
|
-
description:
|
|
2194
|
+
title: __31("Deprecated widgets", "elementor"),
|
|
2195
|
+
description: __31(
|
|
1958
2196
|
"Deprecated widgets should not be used. For better capabilities use the recommended replacement.",
|
|
1959
2197
|
"elementor"
|
|
1960
2198
|
),
|
|
1961
|
-
fixHint:
|
|
2199
|
+
fixHint: __31("Replace each deprecated widget with the recommended new widget shown in its panel.", "elementor"),
|
|
1962
2200
|
categories: ["best-practices", "performance"],
|
|
1963
2201
|
severity: "warning",
|
|
1964
2202
|
weight: 7,
|
|
@@ -1982,10 +2220,10 @@ var audit5 = {
|
|
|
1982
2220
|
return;
|
|
1983
2221
|
}
|
|
1984
2222
|
violations.push({
|
|
1985
|
-
auditId:
|
|
2223
|
+
auditId: audit7.id,
|
|
1986
2224
|
elementId: node.id,
|
|
1987
2225
|
targetHint: "element-settings",
|
|
1988
|
-
label:
|
|
2226
|
+
label: __31("Using deprecated widget.", "elementor")
|
|
1989
2227
|
});
|
|
1990
2228
|
});
|
|
1991
2229
|
return violations.length === 0 ? { status: "pass" } : { status: "fail", violations };
|
|
@@ -1993,28 +2231,7 @@ var audit5 = {
|
|
|
1993
2231
|
};
|
|
1994
2232
|
|
|
1995
2233
|
// src/audits/google-consent-mode.ts
|
|
1996
|
-
import { __ as
|
|
1997
|
-
|
|
1998
|
-
// src/utils/fetch-rendered-html.ts
|
|
1999
|
-
var FETCH_TIMEOUT_MS = 1e4;
|
|
2000
|
-
async function fetchRenderedHtml(url) {
|
|
2001
|
-
if (!url) {
|
|
2002
|
-
return null;
|
|
2003
|
-
}
|
|
2004
|
-
const timeoutController = new AbortController();
|
|
2005
|
-
const timeoutId = setTimeout(() => timeoutController.abort(), FETCH_TIMEOUT_MS);
|
|
2006
|
-
try {
|
|
2007
|
-
const response = await fetch(url, { credentials: "omit", signal: timeoutController.signal });
|
|
2008
|
-
if (!response.ok) {
|
|
2009
|
-
return null;
|
|
2010
|
-
}
|
|
2011
|
-
return await response.text();
|
|
2012
|
-
} catch {
|
|
2013
|
-
return null;
|
|
2014
|
-
} finally {
|
|
2015
|
-
clearTimeout(timeoutId);
|
|
2016
|
-
}
|
|
2017
|
-
}
|
|
2234
|
+
import { __ as __32 } from "@wordpress/i18n";
|
|
2018
2235
|
|
|
2019
2236
|
// src/utils/scan-consent-signals.ts
|
|
2020
2237
|
var GOOGLE_TRACKING_PATTERNS = [
|
|
@@ -2035,44 +2252,43 @@ function hasConsentDefaultCall(html) {
|
|
|
2035
2252
|
}
|
|
2036
2253
|
|
|
2037
2254
|
// src/audits/google-consent-mode.ts
|
|
2038
|
-
var
|
|
2255
|
+
var audit8 = {
|
|
2039
2256
|
id: "audits/google-consent-mode",
|
|
2040
|
-
title:
|
|
2041
|
-
description:
|
|
2257
|
+
title: __32("Google Consent Mode", "elementor"),
|
|
2258
|
+
description: __32(
|
|
2042
2259
|
"Google Analytics, Ads, or Tag Manager are running on this site and may not receive a consent signal, which risks losing conversion/analytics data and compliance exposure.",
|
|
2043
2260
|
"elementor"
|
|
2044
2261
|
),
|
|
2045
|
-
fixHint:
|
|
2262
|
+
fixHint: __32(
|
|
2046
2263
|
"Turn on Google Consent Mode in your cookie consent plugin so Google tags respect visitor consent choices.",
|
|
2047
2264
|
"elementor"
|
|
2048
2265
|
),
|
|
2049
2266
|
categories: ["compliance"],
|
|
2050
2267
|
severity: "warning",
|
|
2051
2268
|
weight: 1,
|
|
2052
|
-
evaluate:
|
|
2269
|
+
evaluate: (ctx) => {
|
|
2053
2270
|
if (!ctx.pageContext.frontend_url) {
|
|
2054
|
-
return { status: "skipped", reason:
|
|
2271
|
+
return { status: "skipped", reason: __32("Page is not published.", "elementor") };
|
|
2055
2272
|
}
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
return { status: "skipped", reason: __30("Could not fetch the published page.", "elementor") };
|
|
2273
|
+
if (!ctx.renderedHtml) {
|
|
2274
|
+
return { status: "skipped", reason: __32("Could not fetch the published page.", "elementor") };
|
|
2059
2275
|
}
|
|
2060
|
-
if (!hasGoogleTracking(
|
|
2061
|
-
return { status: "skipped", reason:
|
|
2276
|
+
if (!hasGoogleTracking(ctx.renderedHtml)) {
|
|
2277
|
+
return { status: "skipped", reason: __32("No Google tracking product detected.", "elementor") };
|
|
2062
2278
|
}
|
|
2063
|
-
if (hasConsentDefaultCall(
|
|
2279
|
+
if (hasConsentDefaultCall(ctx.renderedHtml)) {
|
|
2064
2280
|
return { status: "pass" };
|
|
2065
2281
|
}
|
|
2066
|
-
const label =
|
|
2282
|
+
const label = __32("No Google Consent Mode signal was found on the page.", "elementor");
|
|
2067
2283
|
const isCookiezReady = ctx.pageContext.cookiez_plugin_installed && ctx.pageContext.cookiez_plugin_active;
|
|
2068
2284
|
if (isCookiezReady) {
|
|
2069
2285
|
return {
|
|
2070
2286
|
status: "fail",
|
|
2071
2287
|
violations: [
|
|
2072
2288
|
{
|
|
2073
|
-
auditId:
|
|
2289
|
+
auditId: audit8.id,
|
|
2074
2290
|
label,
|
|
2075
|
-
ctaLabel:
|
|
2291
|
+
ctaLabel: __32("Enable", "elementor"),
|
|
2076
2292
|
externalUrl: ctx.pageContext.cookiez_consent_mode_settings_url
|
|
2077
2293
|
}
|
|
2078
2294
|
]
|
|
@@ -2082,7 +2298,7 @@ var audit6 = {
|
|
|
2082
2298
|
status: "fail",
|
|
2083
2299
|
violations: [
|
|
2084
2300
|
{
|
|
2085
|
-
auditId:
|
|
2301
|
+
auditId: audit8.id,
|
|
2086
2302
|
label,
|
|
2087
2303
|
externalUrl: ctx.pageContext.cookiez_plugin_action_url
|
|
2088
2304
|
}
|
|
@@ -2092,7 +2308,7 @@ var audit6 = {
|
|
|
2092
2308
|
};
|
|
2093
2309
|
|
|
2094
2310
|
// src/audits/heading-structure.ts
|
|
2095
|
-
import { __ as
|
|
2311
|
+
import { __ as __33 } from "@wordpress/i18n";
|
|
2096
2312
|
var HEADING_LEVELS = ["h1", "h2", "h3", "h4", "h5", "h6"];
|
|
2097
2313
|
var HEADING_CONTROLS_REGISTRY = {
|
|
2098
2314
|
// Core
|
|
@@ -2268,47 +2484,47 @@ function extractPageHeadings(tree) {
|
|
|
2268
2484
|
});
|
|
2269
2485
|
return headings;
|
|
2270
2486
|
}
|
|
2271
|
-
var
|
|
2487
|
+
var audit9 = {
|
|
2272
2488
|
id: "audits/heading-structure",
|
|
2273
|
-
title:
|
|
2274
|
-
description:
|
|
2275
|
-
fixHint:
|
|
2489
|
+
title: __33("Heading structure", "elementor"),
|
|
2490
|
+
description: __33("Pages should have exactly one H1 and a non-skipping heading order.", "elementor"),
|
|
2491
|
+
fixHint: __33("Ensure your page has one H1 and that heading levels do not skip (no H2 \u2192 H4).", "elementor"),
|
|
2276
2492
|
categories: ["seo", "accessibility"],
|
|
2277
2493
|
severity: "error",
|
|
2278
2494
|
weight: 10,
|
|
2279
2495
|
evaluate: (ctx) => {
|
|
2280
2496
|
if (ctx.elements.tree.length === 0) {
|
|
2281
|
-
return { status: "skipped", reason:
|
|
2497
|
+
return { status: "skipped", reason: __33("No elements", "elementor") };
|
|
2282
2498
|
}
|
|
2283
2499
|
const headings = extractPageHeadings(ctx.elements.tree);
|
|
2284
2500
|
const violations = [];
|
|
2285
2501
|
if (headings.length === 0) {
|
|
2286
2502
|
violations.push({
|
|
2287
|
-
auditId:
|
|
2288
|
-
label:
|
|
2503
|
+
auditId: audit9.id,
|
|
2504
|
+
label: __33("No headings found on the page.", "elementor")
|
|
2289
2505
|
});
|
|
2290
2506
|
} else {
|
|
2291
2507
|
const h1Count = headings.filter((h) => h.level === 1).length;
|
|
2292
2508
|
if (h1Count === 0) {
|
|
2293
|
-
violations.push({ auditId:
|
|
2509
|
+
violations.push({ auditId: audit9.id, label: __33("No H1 on the page.", "elementor") });
|
|
2294
2510
|
}
|
|
2295
2511
|
if (h1Count > 1) {
|
|
2296
2512
|
headings.filter((h) => h.level === 1).slice(1).forEach(
|
|
2297
2513
|
(h) => violations.push({
|
|
2298
|
-
auditId:
|
|
2514
|
+
auditId: audit9.id,
|
|
2299
2515
|
elementId: h.elementId,
|
|
2300
2516
|
targetHint: "element-settings",
|
|
2301
|
-
label:
|
|
2517
|
+
label: __33("More than one H1 on the page.", "elementor")
|
|
2302
2518
|
})
|
|
2303
2519
|
);
|
|
2304
2520
|
}
|
|
2305
2521
|
for (let i = 1; i < headings.length; i++) {
|
|
2306
2522
|
if (headings[i].level - headings[i - 1].level > 1) {
|
|
2307
2523
|
violations.push({
|
|
2308
|
-
auditId:
|
|
2524
|
+
auditId: audit9.id,
|
|
2309
2525
|
elementId: headings[i].elementId,
|
|
2310
2526
|
targetHint: "element-settings",
|
|
2311
|
-
label:
|
|
2527
|
+
label: __33("Heading level skipped.", "elementor")
|
|
2312
2528
|
});
|
|
2313
2529
|
}
|
|
2314
2530
|
}
|
|
@@ -2318,33 +2534,33 @@ var audit7 = {
|
|
|
2318
2534
|
};
|
|
2319
2535
|
|
|
2320
2536
|
// src/audits/hidden-elements.ts
|
|
2321
|
-
import { __ as
|
|
2537
|
+
import { __ as __34 } from "@wordpress/i18n";
|
|
2322
2538
|
function isHiddenOnAllDevices(settings) {
|
|
2323
2539
|
return Boolean(settings.hide_desktop) && Boolean(settings.hide_tablet) && Boolean(settings.hide_mobile);
|
|
2324
2540
|
}
|
|
2325
|
-
var
|
|
2541
|
+
var audit10 = {
|
|
2326
2542
|
id: "audits/hidden-elements",
|
|
2327
|
-
title:
|
|
2328
|
-
description:
|
|
2543
|
+
title: __34("Hidden elements", "elementor"),
|
|
2544
|
+
description: __34(
|
|
2329
2545
|
"Elements hidden on all devices simultaneously are effectively dead code in the page tree.",
|
|
2330
2546
|
"elementor"
|
|
2331
2547
|
),
|
|
2332
|
-
fixHint:
|
|
2548
|
+
fixHint: __34("Remove the element or make it visible on at least one device breakpoint.", "elementor"),
|
|
2333
2549
|
categories: ["best-practices", "performance"],
|
|
2334
2550
|
severity: "info",
|
|
2335
2551
|
weight: 3,
|
|
2336
2552
|
evaluate: (ctx) => {
|
|
2337
2553
|
if (ctx.elements.tree.length === 0) {
|
|
2338
|
-
return { status: "skipped", reason:
|
|
2554
|
+
return { status: "skipped", reason: __34("No elements", "elementor") };
|
|
2339
2555
|
}
|
|
2340
2556
|
const violations = [];
|
|
2341
2557
|
walkElements(ctx.elements.tree, (node) => {
|
|
2342
2558
|
if (isHiddenOnAllDevices(node.settings)) {
|
|
2343
2559
|
violations.push({
|
|
2344
|
-
auditId:
|
|
2560
|
+
auditId: audit10.id,
|
|
2345
2561
|
elementId: node.id,
|
|
2346
2562
|
targetHint: "element-settings",
|
|
2347
|
-
label:
|
|
2563
|
+
label: __34("Element is hidden on all devices.", "elementor")
|
|
2348
2564
|
});
|
|
2349
2565
|
}
|
|
2350
2566
|
});
|
|
@@ -2353,7 +2569,7 @@ var audit8 = {
|
|
|
2353
2569
|
};
|
|
2354
2570
|
|
|
2355
2571
|
// src/audits/images-alt-text.ts
|
|
2356
|
-
import { __ as
|
|
2572
|
+
import { __ as __35 } from "@wordpress/i18n";
|
|
2357
2573
|
|
|
2358
2574
|
// src/utils/image-alt.ts
|
|
2359
2575
|
function hasMeaningfulAlt(media, pageContext) {
|
|
@@ -2361,7 +2577,8 @@ function hasMeaningfulAlt(media, pageContext) {
|
|
|
2361
2577
|
return true;
|
|
2362
2578
|
}
|
|
2363
2579
|
if (media.id) {
|
|
2364
|
-
const
|
|
2580
|
+
const key = buildImageSizeKey({ id: media.id, size: media.size });
|
|
2581
|
+
const alt = pageContext.image_sizes[key]?.alt ?? "";
|
|
2365
2582
|
return alt.trim().length > 0;
|
|
2366
2583
|
}
|
|
2367
2584
|
return (media.alt ?? "").trim().length > 0;
|
|
@@ -2371,17 +2588,17 @@ function isImageSourcePresent(media) {
|
|
|
2371
2588
|
}
|
|
2372
2589
|
|
|
2373
2590
|
// src/audits/images-alt-text.ts
|
|
2374
|
-
var
|
|
2591
|
+
var audit11 = {
|
|
2375
2592
|
id: "audits/images-alt-text",
|
|
2376
|
-
title:
|
|
2377
|
-
description:
|
|
2378
|
-
fixHint:
|
|
2593
|
+
title: __35("Images alt text", "elementor"),
|
|
2594
|
+
description: __35("Every image needs a meaningful alt attribute for screen readers and image-search.", "elementor"),
|
|
2595
|
+
fixHint: __35("Open the image's settings and add an Alt Text describing the image.", "elementor"),
|
|
2379
2596
|
categories: ["seo", "accessibility"],
|
|
2380
2597
|
severity: "error",
|
|
2381
2598
|
weight: 10,
|
|
2382
2599
|
evaluate: (ctx) => {
|
|
2383
2600
|
if (!hasPageImages(ctx.elements.tree)) {
|
|
2384
|
-
return { status: "skipped", reason:
|
|
2601
|
+
return { status: "skipped", reason: __35("No images", "elementor") };
|
|
2385
2602
|
}
|
|
2386
2603
|
const violations = [];
|
|
2387
2604
|
const failedWidgetIds = /* @__PURE__ */ new Set();
|
|
@@ -2394,10 +2611,10 @@ var audit9 = {
|
|
|
2394
2611
|
if (!failedWidgetIds.has(node.id)) {
|
|
2395
2612
|
failedWidgetIds.add(node.id);
|
|
2396
2613
|
violations.push({
|
|
2397
|
-
auditId:
|
|
2614
|
+
auditId: audit11.id,
|
|
2398
2615
|
elementId: node.id,
|
|
2399
2616
|
targetHint: "element-settings",
|
|
2400
|
-
label:
|
|
2617
|
+
label: __35("Image is missing alt text.", "elementor"),
|
|
2401
2618
|
externalUrl: ctx.pageContext.ally_plugin_url
|
|
2402
2619
|
});
|
|
2403
2620
|
}
|
|
@@ -2406,30 +2623,79 @@ var audit9 = {
|
|
|
2406
2623
|
}
|
|
2407
2624
|
};
|
|
2408
2625
|
|
|
2626
|
+
// src/audits/images-inefficient-format.ts
|
|
2627
|
+
import { __ as __36 } from "@wordpress/i18n";
|
|
2628
|
+
var LEGACY_RASTER_MIME_TYPES = /* @__PURE__ */ new Set(["image/jpeg", "image/png", "image/gif", "image/bmp", "image/tiff"]);
|
|
2629
|
+
var audit12 = {
|
|
2630
|
+
id: "audits/images-inefficient-format",
|
|
2631
|
+
title: __36("Inefficient image format", "elementor"),
|
|
2632
|
+
description: __36("Image isn't served in a modern, efficient format like WebP or AVIF.", "elementor"),
|
|
2633
|
+
fixHint: __36("Convert the image to a modern format like WebP or AVIF, or enable image optimization.", "elementor"),
|
|
2634
|
+
categories: ["performance"],
|
|
2635
|
+
severity: "info",
|
|
2636
|
+
weight: 1,
|
|
2637
|
+
evaluate: (ctx) => {
|
|
2638
|
+
const offendingElementIds = /* @__PURE__ */ new Set();
|
|
2639
|
+
let hasAnyImage = false;
|
|
2640
|
+
let inefficientImageFormatCount = 0;
|
|
2641
|
+
const evaluateSource = (node, media) => {
|
|
2642
|
+
if (media.id || media.url) {
|
|
2643
|
+
hasAnyImage = true;
|
|
2644
|
+
}
|
|
2645
|
+
const id = media.id;
|
|
2646
|
+
if (!id) {
|
|
2647
|
+
return;
|
|
2648
|
+
}
|
|
2649
|
+
const mime = ctx.pageContext.image_sizes[buildImageSizeKey({ id, size: media.size })]?.mime;
|
|
2650
|
+
if (!mime || !LEGACY_RASTER_MIME_TYPES.has(mime)) {
|
|
2651
|
+
return;
|
|
2652
|
+
}
|
|
2653
|
+
inefficientImageFormatCount++;
|
|
2654
|
+
offendingElementIds.add(node.id);
|
|
2655
|
+
};
|
|
2656
|
+
walkImageLikeSources(ctx.elements.tree, ({ node, media }) => evaluateSource(node, media));
|
|
2657
|
+
walkBackgroundImageSources(ctx.elements.tree, ({ node, media }) => evaluateSource(node, media));
|
|
2658
|
+
walkAtomicImageSources(ctx.elements.tree, ({ node, media }) => evaluateSource(node, media));
|
|
2659
|
+
walkAtomicBackgroundImageSources(ctx.elements.tree, ({ node, media }) => evaluateSource(node, media));
|
|
2660
|
+
if (!hasAnyImage) {
|
|
2661
|
+
return { status: "skipped", reason: __36("No images", "elementor") };
|
|
2662
|
+
}
|
|
2663
|
+
const violations = Array.from(offendingElementIds).map((elementId) => ({
|
|
2664
|
+
auditId: audit12.id,
|
|
2665
|
+
elementId,
|
|
2666
|
+
targetHint: "element-settings",
|
|
2667
|
+
label: __36("Image isn't served in a modern format like WebP or AVIF.", "elementor"),
|
|
2668
|
+
externalUrl: ctx.pageContext.image_optimization_plugin_url
|
|
2669
|
+
}));
|
|
2670
|
+
return violations.length === 0 ? { status: "pass" } : { status: "fail", violations, metadata: { inefficientImageFormatCount } };
|
|
2671
|
+
}
|
|
2672
|
+
};
|
|
2673
|
+
|
|
2409
2674
|
// src/audits/images-too-large.ts
|
|
2410
|
-
import { __ as
|
|
2675
|
+
import { __ as __37, sprintf as sprintf4 } from "@wordpress/i18n";
|
|
2411
2676
|
var SIZE_THRESHOLD_BYTES = 500 * 1024;
|
|
2412
2677
|
var BYTES_PER_KB = 1024;
|
|
2413
|
-
var
|
|
2678
|
+
var audit13 = {
|
|
2414
2679
|
id: "audits/images-too-large",
|
|
2415
|
-
title:
|
|
2416
|
-
description:
|
|
2417
|
-
fixHint:
|
|
2680
|
+
title: __37("Oversized images", "elementor"),
|
|
2681
|
+
description: __37("Large image files slow down the page.", "elementor"),
|
|
2682
|
+
fixHint: __37("Replace the image with a smaller version or enable image optimization.", "elementor"),
|
|
2418
2683
|
categories: ["performance"],
|
|
2419
2684
|
severity: "warning",
|
|
2420
2685
|
weight: 7,
|
|
2421
2686
|
evaluate: (ctx) => {
|
|
2422
|
-
if (!hasPageImages(ctx.elements.tree)) {
|
|
2423
|
-
return { status: "skipped", reason: __34("No images", "elementor") };
|
|
2424
|
-
}
|
|
2425
2687
|
const widgetMaxKb = /* @__PURE__ */ new Map();
|
|
2426
2688
|
let oversizedImageCount = 0;
|
|
2427
|
-
|
|
2689
|
+
let hasAnyImage = false;
|
|
2690
|
+
const evaluateSource = (node, media) => {
|
|
2691
|
+
if (media.id || media.url) {
|
|
2692
|
+
hasAnyImage = true;
|
|
2693
|
+
}
|
|
2428
2694
|
const id = media.id;
|
|
2429
2695
|
if (!id) {
|
|
2430
2696
|
return;
|
|
2431
2697
|
}
|
|
2432
|
-
const size = ctx.pageContext.image_sizes[id];
|
|
2698
|
+
const size = ctx.pageContext.image_sizes[buildImageSizeKey({ id, size: media.size })];
|
|
2433
2699
|
if (!size || size.filesize_bytes <= SIZE_THRESHOLD_BYTES) {
|
|
2434
2700
|
return;
|
|
2435
2701
|
}
|
|
@@ -2437,14 +2703,21 @@ var audit10 = {
|
|
|
2437
2703
|
const kb = Math.round(size.filesize_bytes / BYTES_PER_KB);
|
|
2438
2704
|
const currentMax = widgetMaxKb.get(node.id) ?? 0;
|
|
2439
2705
|
widgetMaxKb.set(node.id, Math.max(currentMax, kb));
|
|
2440
|
-
}
|
|
2706
|
+
};
|
|
2707
|
+
walkImageLikeSources(ctx.elements.tree, ({ node, media }) => evaluateSource(node, media));
|
|
2708
|
+
walkBackgroundImageSources(ctx.elements.tree, ({ node, media }) => evaluateSource(node, media));
|
|
2709
|
+
walkAtomicImageSources(ctx.elements.tree, ({ node, media }) => evaluateSource(node, media));
|
|
2710
|
+
walkAtomicBackgroundImageSources(ctx.elements.tree, ({ node, media }) => evaluateSource(node, media));
|
|
2711
|
+
if (!hasAnyImage) {
|
|
2712
|
+
return { status: "skipped", reason: __37("No images", "elementor") };
|
|
2713
|
+
}
|
|
2441
2714
|
const violations = Array.from(widgetMaxKb.entries()).map(([elementId, kb]) => ({
|
|
2442
|
-
auditId:
|
|
2715
|
+
auditId: audit13.id,
|
|
2443
2716
|
elementId,
|
|
2444
2717
|
targetHint: "element-settings",
|
|
2445
2718
|
label: sprintf4(
|
|
2446
2719
|
/* translators: %d is the image file size in kilobytes. */
|
|
2447
|
-
|
|
2720
|
+
__37("Image is %d KB (over 500 KB).", "elementor"),
|
|
2448
2721
|
kb
|
|
2449
2722
|
),
|
|
2450
2723
|
externalUrl: ctx.pageContext.image_optimization_plugin_url
|
|
@@ -2454,21 +2727,21 @@ var audit10 = {
|
|
|
2454
2727
|
};
|
|
2455
2728
|
|
|
2456
2729
|
// src/audits/nested-boxed-containers.ts
|
|
2457
|
-
import { __ as
|
|
2730
|
+
import { __ as __38 } from "@wordpress/i18n";
|
|
2458
2731
|
function isBoxed(settings) {
|
|
2459
2732
|
return settings.content_width === "boxed";
|
|
2460
2733
|
}
|
|
2461
|
-
var
|
|
2734
|
+
var audit14 = {
|
|
2462
2735
|
id: "audits/nested-boxed-containers",
|
|
2463
|
-
title:
|
|
2464
|
-
description:
|
|
2465
|
-
fixHint:
|
|
2736
|
+
title: __38("Boxed container nested inside a boxed parent", "elementor"),
|
|
2737
|
+
description: __38("An inner container does not need to be boxed when its parent already is.", "elementor"),
|
|
2738
|
+
fixHint: __38("Change the inner container's content width to Full Width.", "elementor"),
|
|
2466
2739
|
categories: ["best-practices", "performance"],
|
|
2467
2740
|
severity: "info",
|
|
2468
2741
|
weight: 5,
|
|
2469
2742
|
evaluate: (ctx) => {
|
|
2470
2743
|
if (ctx.elements.tree.length === 0) {
|
|
2471
|
-
return { status: "skipped", reason:
|
|
2744
|
+
return { status: "skipped", reason: __38("No elements", "elementor") };
|
|
2472
2745
|
}
|
|
2473
2746
|
const violations = [];
|
|
2474
2747
|
walkElements(ctx.elements.tree, (node, parents) => {
|
|
@@ -2478,10 +2751,10 @@ var audit11 = {
|
|
|
2478
2751
|
const nearestContainerAncestor = [...parents].reverse().find((p) => p.elType === "container");
|
|
2479
2752
|
if (nearestContainerAncestor && isBoxed(nearestContainerAncestor.settings)) {
|
|
2480
2753
|
violations.push({
|
|
2481
|
-
auditId:
|
|
2754
|
+
auditId: audit14.id,
|
|
2482
2755
|
elementId: node.id,
|
|
2483
2756
|
targetHint: "element-settings",
|
|
2484
|
-
label:
|
|
2757
|
+
label: __38("Nested boxed container.", "elementor")
|
|
2485
2758
|
});
|
|
2486
2759
|
}
|
|
2487
2760
|
});
|
|
@@ -2490,12 +2763,12 @@ var audit11 = {
|
|
|
2490
2763
|
};
|
|
2491
2764
|
|
|
2492
2765
|
// src/audits/page-excerpt.ts
|
|
2493
|
-
import { __ as
|
|
2494
|
-
var
|
|
2766
|
+
import { __ as __39 } from "@wordpress/i18n";
|
|
2767
|
+
var audit15 = {
|
|
2495
2768
|
id: "audits/page-excerpt",
|
|
2496
|
-
title:
|
|
2497
|
-
description:
|
|
2498
|
-
fixHint:
|
|
2769
|
+
title: __39("Page excerpt", "elementor"),
|
|
2770
|
+
description: __39("A descriptive excerpt helps search engines and previews summarize the page.", "elementor"),
|
|
2771
|
+
fixHint: __39("Open Page Settings and write a short excerpt.", "elementor"),
|
|
2499
2772
|
categories: ["seo"],
|
|
2500
2773
|
severity: "warning",
|
|
2501
2774
|
weight: 5,
|
|
@@ -2507,8 +2780,8 @@ var audit12 = {
|
|
|
2507
2780
|
status: "fail",
|
|
2508
2781
|
violations: [
|
|
2509
2782
|
{
|
|
2510
|
-
auditId:
|
|
2511
|
-
label:
|
|
2783
|
+
auditId: audit15.id,
|
|
2784
|
+
label: __39("Page has no excerpt.", "elementor"),
|
|
2512
2785
|
targetHint: "page-settings",
|
|
2513
2786
|
angieFix: true
|
|
2514
2787
|
}
|
|
@@ -2518,12 +2791,12 @@ var audit12 = {
|
|
|
2518
2791
|
};
|
|
2519
2792
|
|
|
2520
2793
|
// src/audits/page-featured-image.ts
|
|
2521
|
-
import { __ as
|
|
2522
|
-
var
|
|
2794
|
+
import { __ as __40 } from "@wordpress/i18n";
|
|
2795
|
+
var audit16 = {
|
|
2523
2796
|
id: "audits/page-featured-image",
|
|
2524
|
-
title:
|
|
2525
|
-
description:
|
|
2526
|
-
fixHint:
|
|
2797
|
+
title: __40("Page featured image", "elementor"),
|
|
2798
|
+
description: __40("Featured images are used by social shares and many themes for hero visuals.", "elementor"),
|
|
2799
|
+
fixHint: __40("Open Page Settings and set a featured image.", "elementor"),
|
|
2527
2800
|
categories: ["seo"],
|
|
2528
2801
|
severity: "info",
|
|
2529
2802
|
weight: 5,
|
|
@@ -2535,8 +2808,8 @@ var audit13 = {
|
|
|
2535
2808
|
status: "fail",
|
|
2536
2809
|
violations: [
|
|
2537
2810
|
{
|
|
2538
|
-
auditId:
|
|
2539
|
-
label:
|
|
2811
|
+
auditId: audit16.id,
|
|
2812
|
+
label: __40("No featured image set.", "elementor"),
|
|
2540
2813
|
targetHint: "page-settings"
|
|
2541
2814
|
}
|
|
2542
2815
|
]
|
|
@@ -2545,13 +2818,13 @@ var audit13 = {
|
|
|
2545
2818
|
};
|
|
2546
2819
|
|
|
2547
2820
|
// src/audits/page-title.ts
|
|
2548
|
-
import { __ as
|
|
2821
|
+
import { __ as __41 } from "@wordpress/i18n";
|
|
2549
2822
|
var MAX_TITLE_LENGTH = 60;
|
|
2550
|
-
var
|
|
2823
|
+
var audit17 = {
|
|
2551
2824
|
id: "audits/page-title",
|
|
2552
|
-
title:
|
|
2553
|
-
description:
|
|
2554
|
-
fixHint:
|
|
2825
|
+
title: __41("Page title", "elementor"),
|
|
2826
|
+
description: __41("Pages need a clear title for SEO and screen-reader navigation.", "elementor"),
|
|
2827
|
+
fixHint: __41("Open Page Settings and add a title.", "elementor"),
|
|
2555
2828
|
categories: ["seo"],
|
|
2556
2829
|
severity: "error",
|
|
2557
2830
|
weight: 10,
|
|
@@ -2562,11 +2835,11 @@ var audit14 = {
|
|
|
2562
2835
|
status: "fail",
|
|
2563
2836
|
violations: [
|
|
2564
2837
|
{
|
|
2565
|
-
auditId:
|
|
2566
|
-
label:
|
|
2838
|
+
auditId: audit17.id,
|
|
2839
|
+
label: __41("Page has no title.", "elementor"),
|
|
2567
2840
|
targetHint: "page-settings",
|
|
2568
2841
|
angieFix: true,
|
|
2569
|
-
angiePrompt:
|
|
2842
|
+
angiePrompt: __41(
|
|
2570
2843
|
"Based on this page's contents, generate a title for this page.",
|
|
2571
2844
|
"elementor"
|
|
2572
2845
|
)
|
|
@@ -2579,8 +2852,8 @@ var audit14 = {
|
|
|
2579
2852
|
status: "fail",
|
|
2580
2853
|
violations: [
|
|
2581
2854
|
{
|
|
2582
|
-
auditId:
|
|
2583
|
-
label:
|
|
2855
|
+
auditId: audit17.id,
|
|
2856
|
+
label: __41("Page title is too long.", "elementor"),
|
|
2584
2857
|
targetHint: "page-settings",
|
|
2585
2858
|
angieFix: true
|
|
2586
2859
|
}
|
|
@@ -2592,7 +2865,7 @@ var audit14 = {
|
|
|
2592
2865
|
};
|
|
2593
2866
|
|
|
2594
2867
|
// src/audits/prefer-global-colors.ts
|
|
2595
|
-
import { __ as
|
|
2868
|
+
import { __ as __42, sprintf as sprintf5 } from "@wordpress/i18n";
|
|
2596
2869
|
|
|
2597
2870
|
// src/utils/collect-hardcoded-colors.ts
|
|
2598
2871
|
var RESERVED_SETTING_KEYS = /* @__PURE__ */ new Set(["__globals__", "__dynamic__"]);
|
|
@@ -2658,20 +2931,20 @@ function findMatchingGlobalByValue(value, globals) {
|
|
|
2658
2931
|
}
|
|
2659
2932
|
|
|
2660
2933
|
// src/audits/prefer-global-colors.ts
|
|
2661
|
-
var
|
|
2934
|
+
var audit18 = {
|
|
2662
2935
|
id: "audits/prefer-global-colors",
|
|
2663
|
-
title:
|
|
2664
|
-
description:
|
|
2665
|
-
fixHint:
|
|
2936
|
+
title: __42("Prefer global colors", "elementor"),
|
|
2937
|
+
description: __42("Global colors make the design consistent and easy to update site-wide.", "elementor"),
|
|
2938
|
+
fixHint: __42("Replace the hard-coded value with the matching global color.", "elementor"),
|
|
2666
2939
|
categories: ["best-practices"],
|
|
2667
2940
|
severity: "info",
|
|
2668
2941
|
weight: 3,
|
|
2669
2942
|
evaluate: (ctx) => {
|
|
2670
2943
|
if (ctx.elements.tree.length === 0) {
|
|
2671
|
-
return { status: "skipped", reason:
|
|
2944
|
+
return { status: "skipped", reason: __42("No elements", "elementor") };
|
|
2672
2945
|
}
|
|
2673
2946
|
if (ctx.kit.globals.colors.length === 0) {
|
|
2674
|
-
return { status: "skipped", reason:
|
|
2947
|
+
return { status: "skipped", reason: __42("No global colors", "elementor") };
|
|
2675
2948
|
}
|
|
2676
2949
|
const violations = [];
|
|
2677
2950
|
walkElements(ctx.elements.tree, (node) => {
|
|
@@ -2681,13 +2954,13 @@ var audit15 = {
|
|
|
2681
2954
|
continue;
|
|
2682
2955
|
}
|
|
2683
2956
|
violations.push({
|
|
2684
|
-
auditId:
|
|
2957
|
+
auditId: audit18.id,
|
|
2685
2958
|
elementId: node.id,
|
|
2686
2959
|
targetHint: "element-settings",
|
|
2687
2960
|
angieFix: true,
|
|
2688
2961
|
label: sprintf5(
|
|
2689
2962
|
/* translators: 1: hard-coded color value, 2: global color title. */
|
|
2690
|
-
|
|
2963
|
+
__42('replace "%1$s" with "%2$s" global color', "elementor"),
|
|
2691
2964
|
value,
|
|
2692
2965
|
global.title
|
|
2693
2966
|
)
|
|
@@ -2699,7 +2972,7 @@ var audit15 = {
|
|
|
2699
2972
|
};
|
|
2700
2973
|
|
|
2701
2974
|
// src/audits/prefer-global-fonts.ts
|
|
2702
|
-
import { __ as
|
|
2975
|
+
import { __ as __43, sprintf as sprintf6 } from "@wordpress/i18n";
|
|
2703
2976
|
|
|
2704
2977
|
// src/utils/collect-hardcoded-fonts.ts
|
|
2705
2978
|
var RESERVED_SETTING_KEYS2 = /* @__PURE__ */ new Set(["__globals__", "__dynamic__"]);
|
|
@@ -2757,20 +3030,20 @@ function collectHardcodedFonts(settings, pathPrefix = "") {
|
|
|
2757
3030
|
}
|
|
2758
3031
|
|
|
2759
3032
|
// src/audits/prefer-global-fonts.ts
|
|
2760
|
-
var
|
|
3033
|
+
var audit19 = {
|
|
2761
3034
|
id: "audits/prefer-global-fonts",
|
|
2762
|
-
title:
|
|
2763
|
-
description:
|
|
2764
|
-
fixHint:
|
|
3035
|
+
title: __43("Prefer global fonts", "elementor"),
|
|
3036
|
+
description: __43("Global fonts make the design consistent and easy to update site-wide.", "elementor"),
|
|
3037
|
+
fixHint: __43("Replace the hard-coded value with the matching global font.", "elementor"),
|
|
2765
3038
|
categories: ["best-practices", "performance"],
|
|
2766
3039
|
severity: "info",
|
|
2767
3040
|
weight: 3,
|
|
2768
3041
|
evaluate: (ctx) => {
|
|
2769
3042
|
if (ctx.elements.tree.length === 0) {
|
|
2770
|
-
return { status: "skipped", reason:
|
|
3043
|
+
return { status: "skipped", reason: __43("No elements", "elementor") };
|
|
2771
3044
|
}
|
|
2772
3045
|
if (ctx.kit.globals.fonts.length === 0) {
|
|
2773
|
-
return { status: "skipped", reason:
|
|
3046
|
+
return { status: "skipped", reason: __43("No global fonts", "elementor") };
|
|
2774
3047
|
}
|
|
2775
3048
|
const violations = [];
|
|
2776
3049
|
walkElements(ctx.elements.tree, (node) => {
|
|
@@ -2780,12 +3053,12 @@ var audit16 = {
|
|
|
2780
3053
|
continue;
|
|
2781
3054
|
}
|
|
2782
3055
|
violations.push({
|
|
2783
|
-
auditId:
|
|
3056
|
+
auditId: audit19.id,
|
|
2784
3057
|
elementId: node.id,
|
|
2785
3058
|
targetHint: "element-settings",
|
|
2786
3059
|
label: sprintf6(
|
|
2787
3060
|
/* translators: %s: global font title. */
|
|
2788
|
-
|
|
3061
|
+
__43('replace hardcoded typography with "%s" global font', "elementor"),
|
|
2789
3062
|
global.title
|
|
2790
3063
|
)
|
|
2791
3064
|
});
|
|
@@ -2796,15 +3069,15 @@ var audit16 = {
|
|
|
2796
3069
|
};
|
|
2797
3070
|
|
|
2798
3071
|
// src/audits/privacy-policy.ts
|
|
2799
|
-
import { __ as
|
|
2800
|
-
var
|
|
3072
|
+
import { __ as __44 } from "@wordpress/i18n";
|
|
3073
|
+
var audit20 = {
|
|
2801
3074
|
id: "audits/privacy-policy",
|
|
2802
|
-
title:
|
|
2803
|
-
description:
|
|
3075
|
+
title: __44("Privacy policy", "elementor"),
|
|
3076
|
+
description: __44(
|
|
2804
3077
|
"A privacy policy page is required by privacy regulations such as GDPR (EU) and CCPA (US).",
|
|
2805
3078
|
"elementor"
|
|
2806
3079
|
),
|
|
2807
|
-
fixHint:
|
|
3080
|
+
fixHint: __44(
|
|
2808
3081
|
"Go to Settings > Privacy in the WordPress admin and assign a published privacy policy page.",
|
|
2809
3082
|
"elementor"
|
|
2810
3083
|
),
|
|
@@ -2819,10 +3092,10 @@ var audit17 = {
|
|
|
2819
3092
|
status: "fail",
|
|
2820
3093
|
violations: [
|
|
2821
3094
|
{
|
|
2822
|
-
auditId:
|
|
2823
|
-
label:
|
|
3095
|
+
auditId: audit20.id,
|
|
3096
|
+
label: __44("No privacy policy page is set.", "elementor"),
|
|
2824
3097
|
externalUrl: ctx.pageContext.privacy_settings_url,
|
|
2825
|
-
ctaLabel:
|
|
3098
|
+
ctaLabel: __44("Create", "elementor")
|
|
2826
3099
|
}
|
|
2827
3100
|
]
|
|
2828
3101
|
};
|
|
@@ -2830,15 +3103,15 @@ var audit17 = {
|
|
|
2830
3103
|
};
|
|
2831
3104
|
|
|
2832
3105
|
// src/audits/robots-noindex.ts
|
|
2833
|
-
import { __ as
|
|
2834
|
-
var
|
|
3106
|
+
import { __ as __45 } from "@wordpress/i18n";
|
|
3107
|
+
var audit21 = {
|
|
2835
3108
|
id: "audits/robots-noindex",
|
|
2836
|
-
title:
|
|
2837
|
-
description:
|
|
3109
|
+
title: __45("Search engine visibility", "elementor"),
|
|
3110
|
+
description: __45(
|
|
2838
3111
|
"When search engine visibility is checked in WordPress Settings -> Reading -> Search Engine Visibility, search engines are discouraged from indexing the website.",
|
|
2839
3112
|
"elementor"
|
|
2840
3113
|
),
|
|
2841
|
-
fixHint:
|
|
3114
|
+
fixHint: __45(
|
|
2842
3115
|
'Go to Settings \u2192 Reading in the WordPress admin and uncheck "Discourage search engines from indexing this site" when the website should be indexed.',
|
|
2843
3116
|
"elementor"
|
|
2844
3117
|
),
|
|
@@ -2853,8 +3126,8 @@ var audit18 = {
|
|
|
2853
3126
|
status: "fail",
|
|
2854
3127
|
violations: [
|
|
2855
3128
|
{
|
|
2856
|
-
auditId:
|
|
2857
|
-
label:
|
|
3129
|
+
auditId: audit21.id,
|
|
3130
|
+
label: __45("Search engines are discouraged from indexing this website.", "elementor"),
|
|
2858
3131
|
externalUrl: ctx.pageContext.reading_settings_url
|
|
2859
3132
|
}
|
|
2860
3133
|
]
|
|
@@ -2863,15 +3136,15 @@ var audit18 = {
|
|
|
2863
3136
|
};
|
|
2864
3137
|
|
|
2865
3138
|
// src/audits/scan-for-cookies.ts
|
|
2866
|
-
import { __ as
|
|
2867
|
-
var
|
|
3139
|
+
import { __ as __46 } from "@wordpress/i18n";
|
|
3140
|
+
var audit22 = {
|
|
2868
3141
|
id: "audits/scan-for-cookies",
|
|
2869
|
-
title:
|
|
2870
|
-
description:
|
|
3142
|
+
title: __46("Scan for cookies", "elementor"),
|
|
3143
|
+
description: __46(
|
|
2871
3144
|
"Your site may be setting cookies you haven't disclosed. Some countries require a banner even without a full consent policy. Scan to see what needs disclosure.",
|
|
2872
3145
|
"elementor"
|
|
2873
3146
|
),
|
|
2874
|
-
fixHint:
|
|
3147
|
+
fixHint: __46("Run a Cookiez scan on this page to see which cookies need disclosure.", "elementor"),
|
|
2875
3148
|
categories: ["compliance"],
|
|
2876
3149
|
severity: "info",
|
|
2877
3150
|
weight: 0,
|
|
@@ -2881,8 +3154,8 @@ var audit19 = {
|
|
|
2881
3154
|
status: "fail",
|
|
2882
3155
|
violations: [
|
|
2883
3156
|
{
|
|
2884
|
-
auditId:
|
|
2885
|
-
label:
|
|
3157
|
+
auditId: audit22.id,
|
|
3158
|
+
label: __46("This page has not been scanned for cookies yet.", "elementor"),
|
|
2886
3159
|
externalUrl: isReady ? ctx.pageContext.cookiez_scan_url : ctx.pageContext.cookiez_plugin_action_url
|
|
2887
3160
|
}
|
|
2888
3161
|
]
|
|
@@ -2891,29 +3164,29 @@ var audit19 = {
|
|
|
2891
3164
|
};
|
|
2892
3165
|
|
|
2893
3166
|
// src/audits/sections-and-columns.ts
|
|
2894
|
-
import { __ as
|
|
2895
|
-
var
|
|
3167
|
+
import { __ as __47 } from "@wordpress/i18n";
|
|
3168
|
+
var audit23 = {
|
|
2896
3169
|
id: "audits/sections-and-columns",
|
|
2897
|
-
title:
|
|
2898
|
-
description:
|
|
3170
|
+
title: __47("Sections and columns", "elementor"),
|
|
3171
|
+
description: __47(
|
|
2899
3172
|
"Sections and columns are legacy elements. Containers render fewer DOM nodes and are more flexible.",
|
|
2900
3173
|
"elementor"
|
|
2901
3174
|
),
|
|
2902
|
-
fixHint:
|
|
3175
|
+
fixHint: __47("Use the Container Converter to replace each section/column with a container.", "elementor"),
|
|
2903
3176
|
categories: ["best-practices", "performance"],
|
|
2904
3177
|
severity: "warning",
|
|
2905
3178
|
weight: 7,
|
|
2906
3179
|
evaluate: (ctx) => {
|
|
2907
3180
|
if (ctx.elements.tree.length === 0) {
|
|
2908
|
-
return { status: "skipped", reason:
|
|
3181
|
+
return { status: "skipped", reason: __47("No elements", "elementor") };
|
|
2909
3182
|
}
|
|
2910
3183
|
const violations = [];
|
|
2911
3184
|
walkElements(ctx.elements.tree, (node) => {
|
|
2912
3185
|
if (node.elType === "section" || node.elType === "column") {
|
|
2913
3186
|
violations.push({
|
|
2914
|
-
auditId:
|
|
3187
|
+
auditId: audit23.id,
|
|
2915
3188
|
elementId: node.id,
|
|
2916
|
-
label: node.elType === "section" ?
|
|
3189
|
+
label: node.elType === "section" ? __47("Section element", "elementor") : __47("Column element", "elementor")
|
|
2917
3190
|
});
|
|
2918
3191
|
}
|
|
2919
3192
|
});
|
|
@@ -2922,15 +3195,15 @@ var audit20 = {
|
|
|
2922
3195
|
};
|
|
2923
3196
|
|
|
2924
3197
|
// src/audits/site-identity.ts
|
|
2925
|
-
import { __ as
|
|
2926
|
-
var
|
|
3198
|
+
import { __ as __48 } from "@wordpress/i18n";
|
|
3199
|
+
var audit24 = {
|
|
2927
3200
|
id: "audits/site-identity",
|
|
2928
|
-
title:
|
|
2929
|
-
description:
|
|
3201
|
+
title: __48("Site identity", "elementor"),
|
|
3202
|
+
description: __48(
|
|
2930
3203
|
"Site name, description, logo, and favicon establish your brand and appear in search results and browser tabs.",
|
|
2931
3204
|
"elementor"
|
|
2932
3205
|
),
|
|
2933
|
-
fixHint:
|
|
3206
|
+
fixHint: __48("Open Site Settings \u2192 Site Identity and complete all the missing fields.", "elementor"),
|
|
2934
3207
|
categories: ["best-practices", "seo"],
|
|
2935
3208
|
severity: "info",
|
|
2936
3209
|
weight: 7,
|
|
@@ -2939,30 +3212,30 @@ var audit21 = {
|
|
|
2939
3212
|
const violations = [];
|
|
2940
3213
|
if (!identity.site_name_set) {
|
|
2941
3214
|
violations.push({
|
|
2942
|
-
auditId:
|
|
2943
|
-
label:
|
|
3215
|
+
auditId: audit24.id,
|
|
3216
|
+
label: __48("Site name is missing or still uses the default.", "elementor"),
|
|
2944
3217
|
targetHint: "site-identity-settings"
|
|
2945
3218
|
});
|
|
2946
3219
|
}
|
|
2947
3220
|
if (!identity.site_description_set) {
|
|
2948
3221
|
violations.push({
|
|
2949
|
-
auditId:
|
|
2950
|
-
label:
|
|
3222
|
+
auditId: audit24.id,
|
|
3223
|
+
label: __48("Site description is missing or still uses the default.", "elementor"),
|
|
2951
3224
|
targetHint: "site-identity-settings",
|
|
2952
3225
|
angieFix: true
|
|
2953
3226
|
});
|
|
2954
3227
|
}
|
|
2955
3228
|
if (!identity.site_logo_set) {
|
|
2956
3229
|
violations.push({
|
|
2957
|
-
auditId:
|
|
2958
|
-
label:
|
|
3230
|
+
auditId: audit24.id,
|
|
3231
|
+
label: __48("Site logo is not set.", "elementor"),
|
|
2959
3232
|
targetHint: "site-identity-settings"
|
|
2960
3233
|
});
|
|
2961
3234
|
}
|
|
2962
3235
|
if (!identity.site_favicon_set) {
|
|
2963
3236
|
violations.push({
|
|
2964
|
-
auditId:
|
|
2965
|
-
label:
|
|
3237
|
+
auditId: audit24.id,
|
|
3238
|
+
label: __48("Site favicon is not set.", "elementor"),
|
|
2966
3239
|
targetHint: "site-identity-settings"
|
|
2967
3240
|
});
|
|
2968
3241
|
}
|
|
@@ -2978,7 +3251,7 @@ var audit21 = {
|
|
|
2978
3251
|
|
|
2979
3252
|
// src/audits/too-many-widgets.ts
|
|
2980
3253
|
import { getWidgetsCache as getWidgetsCache3 } from "@elementor/editor-elements";
|
|
2981
|
-
import { __ as
|
|
3254
|
+
import { __ as __49 } from "@wordpress/i18n";
|
|
2982
3255
|
var WIDGET_COUNT_THRESHOLD = 100;
|
|
2983
3256
|
function isCountableWidget(node, widgetsCache) {
|
|
2984
3257
|
if (node.elType === "widget") {
|
|
@@ -2986,17 +3259,17 @@ function isCountableWidget(node, widgetsCache) {
|
|
|
2986
3259
|
}
|
|
2987
3260
|
return !!widgetsCache?.[node.elType]?.meta?.is_compound;
|
|
2988
3261
|
}
|
|
2989
|
-
var
|
|
3262
|
+
var audit25 = {
|
|
2990
3263
|
id: "audits/too-many-widgets",
|
|
2991
|
-
title:
|
|
2992
|
-
description:
|
|
2993
|
-
fixHint:
|
|
3264
|
+
title: __49("Too many widgets", "elementor"),
|
|
3265
|
+
description: __49("Excessive DOM size caused by too many widgets degrades rendering performance.", "elementor"),
|
|
3266
|
+
fixHint: __49("Reduce the number of widgets on the page by removing or combining elements.", "elementor"),
|
|
2994
3267
|
categories: ["best-practices", "performance"],
|
|
2995
3268
|
severity: "warning",
|
|
2996
3269
|
weight: 5,
|
|
2997
3270
|
evaluate: (ctx) => {
|
|
2998
3271
|
if (ctx.elements.tree.length === 0) {
|
|
2999
|
-
return { status: "skipped", reason:
|
|
3272
|
+
return { status: "skipped", reason: __49("No elements", "elementor") };
|
|
3000
3273
|
}
|
|
3001
3274
|
const widgetsCache = getWidgetsCache3();
|
|
3002
3275
|
let widgetCount = 0;
|
|
@@ -3012,8 +3285,8 @@ var audit22 = {
|
|
|
3012
3285
|
status: "fail",
|
|
3013
3286
|
violations: [
|
|
3014
3287
|
{
|
|
3015
|
-
auditId:
|
|
3016
|
-
label:
|
|
3288
|
+
auditId: audit25.id,
|
|
3289
|
+
label: __49("Page has too many widgets.", "elementor")
|
|
3017
3290
|
}
|
|
3018
3291
|
]
|
|
3019
3292
|
};
|
|
@@ -3022,32 +3295,35 @@ var audit22 = {
|
|
|
3022
3295
|
|
|
3023
3296
|
// src/register-audits.ts
|
|
3024
3297
|
var AUDITS = [
|
|
3025
|
-
|
|
3026
|
-
audit12,
|
|
3027
|
-
audit13,
|
|
3028
|
-
audit8,
|
|
3029
|
-
audit5,
|
|
3030
|
-
audit22,
|
|
3031
|
-
audit20,
|
|
3032
|
-
audit3,
|
|
3033
|
-
audit11,
|
|
3034
|
-
audit4,
|
|
3035
|
-
audit21,
|
|
3298
|
+
audit17,
|
|
3036
3299
|
audit15,
|
|
3037
3300
|
audit16,
|
|
3038
|
-
audit7,
|
|
3039
|
-
audit9,
|
|
3040
3301
|
audit10,
|
|
3302
|
+
audit7,
|
|
3303
|
+
audit25,
|
|
3304
|
+
audit23,
|
|
3305
|
+
audit5,
|
|
3306
|
+
audit14,
|
|
3307
|
+
audit6,
|
|
3308
|
+
audit24,
|
|
3041
3309
|
audit18,
|
|
3042
|
-
|
|
3310
|
+
audit19,
|
|
3311
|
+
audit9,
|
|
3312
|
+
audit11,
|
|
3313
|
+
audit13,
|
|
3314
|
+
audit12,
|
|
3315
|
+
audit21,
|
|
3316
|
+
audit20,
|
|
3043
3317
|
audit,
|
|
3044
3318
|
audit2,
|
|
3045
|
-
|
|
3046
|
-
|
|
3319
|
+
audit3,
|
|
3320
|
+
audit4,
|
|
3321
|
+
audit22,
|
|
3322
|
+
audit8
|
|
3047
3323
|
];
|
|
3048
3324
|
function registerAllAudits() {
|
|
3049
|
-
for (const
|
|
3050
|
-
registerAudit(
|
|
3325
|
+
for (const audit26 of AUDITS) {
|
|
3326
|
+
registerAudit(audit26);
|
|
3051
3327
|
}
|
|
3052
3328
|
}
|
|
3053
3329
|
|