@elementor/editor-audits 4.3.2 → 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 +10 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +570 -295
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +559 -274
- 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/audits/page-title.ts +4 -0
- package/src/components/violation-cta-button.tsx +3 -2
- package/src/components/violation-row.tsx +16 -5
- package/src/register-audits.ts +6 -0
- package/src/register-promotions.ts +23 -0
- package/src/runner.ts +9 -5
- package/src/types.ts +10 -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;
|
|
@@ -1038,14 +1172,26 @@ function ViolationRow({ audit: audit23, skipReason, violations }) {
|
|
|
1038
1172
|
},
|
|
1039
1173
|
/* @__PURE__ */ React11.createElement(ViolationIcon, { violation, widgetIcon }),
|
|
1040
1174
|
/* @__PURE__ */ React11.createElement(Box7, { sx: { flex: 1 } }, /* @__PURE__ */ React11.createElement(Typography6, { variant: "caption" }, rowLabel), violation.detail && /* @__PURE__ */ React11.createElement(Typography6, { variant: "caption", color: "text.secondary" }, violation.detail)),
|
|
1041
|
-
violation.angieFix && /* @__PURE__ */ React11.createElement(
|
|
1042
|
-
|
|
1175
|
+
violation.angieFix && /* @__PURE__ */ React11.createElement(
|
|
1176
|
+
FixViolationWithAngie,
|
|
1177
|
+
{
|
|
1178
|
+
prompt: violation.angiePrompt ?? buildAngiePrompt(rowLabel)
|
|
1179
|
+
}
|
|
1180
|
+
),
|
|
1181
|
+
violation.ctaLabel && violation.externalUrl ? /* @__PURE__ */ React11.createElement(Box7, { sx: { display: "flex", alignItems: "center", gap: 0.5 } }, /* @__PURE__ */ React11.createElement(
|
|
1043
1182
|
ViolationCtaButton,
|
|
1044
1183
|
{
|
|
1045
1184
|
ctaLabel: violation.ctaLabel,
|
|
1046
1185
|
externalUrl: violation.externalUrl
|
|
1047
1186
|
}
|
|
1048
|
-
)
|
|
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(
|
|
1049
1195
|
EyeIcon,
|
|
1050
1196
|
{
|
|
1051
1197
|
className: "violation-hover-icon",
|
|
@@ -1143,17 +1289,17 @@ import { __ as __14 } from "@wordpress/i18n";
|
|
|
1143
1289
|
var ALL_SEVERITIES = ["error", "warning", "info"];
|
|
1144
1290
|
function countSeverities(report, category) {
|
|
1145
1291
|
const counts = { error: 0, warning: 0, info: 0 };
|
|
1146
|
-
for (const { audit:
|
|
1292
|
+
for (const { audit: audit26, result } of report.auditResults) {
|
|
1147
1293
|
if (result.status !== "fail") {
|
|
1148
1294
|
continue;
|
|
1149
1295
|
}
|
|
1150
|
-
if (category && !
|
|
1296
|
+
if (category && !audit26.categories.includes(category)) {
|
|
1151
1297
|
continue;
|
|
1152
1298
|
}
|
|
1153
|
-
if (!isScoredAudit(
|
|
1299
|
+
if (!isScoredAudit(audit26)) {
|
|
1154
1300
|
continue;
|
|
1155
1301
|
}
|
|
1156
|
-
counts[
|
|
1302
|
+
counts[audit26.severity] += result.violations.length;
|
|
1157
1303
|
}
|
|
1158
1304
|
return counts;
|
|
1159
1305
|
}
|
|
@@ -1456,6 +1602,26 @@ var PROMOTIONS = [
|
|
|
1456
1602
|
);
|
|
1457
1603
|
},
|
|
1458
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
|
|
1459
1625
|
}
|
|
1460
1626
|
];
|
|
1461
1627
|
|
|
@@ -1837,16 +2003,93 @@ var audit = {
|
|
|
1837
2003
|
}
|
|
1838
2004
|
};
|
|
1839
2005
|
|
|
1840
|
-
// src/audits/
|
|
2006
|
+
// src/audits/accessibility-statement.ts
|
|
1841
2007
|
import { __ as __26 } from "@wordpress/i18n";
|
|
1842
2008
|
var audit2 = {
|
|
1843
|
-
id: "audits/
|
|
1844
|
-
title: __26("
|
|
2009
|
+
id: "audits/accessibility-statement",
|
|
2010
|
+
title: __26("Create an accessibility statement", "elementor"),
|
|
1845
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(
|
|
1846
2089
|
"A cookie policy is required by privacy regulations such as GDPR (EU) or CCPA (US) to inform visitors about tracking and data collection.",
|
|
1847
2090
|
"elementor"
|
|
1848
2091
|
),
|
|
1849
|
-
fixHint:
|
|
2092
|
+
fixHint: __28("Install the Cookiez plugin to add a cookie policy to your website.", "elementor"),
|
|
1850
2093
|
categories: ["compliance"],
|
|
1851
2094
|
severity: "info",
|
|
1852
2095
|
weight: 1,
|
|
@@ -1858,8 +2101,8 @@ var audit2 = {
|
|
|
1858
2101
|
status: "fail",
|
|
1859
2102
|
violations: [
|
|
1860
2103
|
{
|
|
1861
|
-
auditId:
|
|
1862
|
-
label:
|
|
2104
|
+
auditId: audit4.id,
|
|
2105
|
+
label: __28("Cookiez plugin is not installed or active.", "elementor"),
|
|
1863
2106
|
externalUrl: ctx.pageContext.cookiez_plugin_url
|
|
1864
2107
|
}
|
|
1865
2108
|
]
|
|
@@ -1869,7 +2112,7 @@ var audit2 = {
|
|
|
1869
2112
|
|
|
1870
2113
|
// src/audits/deep-nesting.ts
|
|
1871
2114
|
import { getWidgetsCache } from "@elementor/editor-elements";
|
|
1872
|
-
import { __ as
|
|
2115
|
+
import { __ as __29 } from "@wordpress/i18n";
|
|
1873
2116
|
var MAX_NESTING_DEPTH = 6;
|
|
1874
2117
|
function isNestingElement(node, widgetsCache) {
|
|
1875
2118
|
if (node.elType === "container") {
|
|
@@ -1877,20 +2120,20 @@ function isNestingElement(node, widgetsCache) {
|
|
|
1877
2120
|
}
|
|
1878
2121
|
return !!widgetsCache?.[node.elType]?.meta?.is_container;
|
|
1879
2122
|
}
|
|
1880
|
-
var
|
|
2123
|
+
var audit5 = {
|
|
1881
2124
|
id: "audits/deep-nesting",
|
|
1882
|
-
title:
|
|
1883
|
-
description:
|
|
2125
|
+
title: __29("Deep container nesting", "elementor"),
|
|
2126
|
+
description: __29(
|
|
1884
2127
|
"Container nesting exceeds the recommended depth. Deep DOM trees hurt rendering performance and readability.",
|
|
1885
2128
|
"elementor"
|
|
1886
2129
|
),
|
|
1887
|
-
fixHint:
|
|
2130
|
+
fixHint: __29("Flatten the layout by removing unnecessary wrapper containers.", "elementor"),
|
|
1888
2131
|
categories: ["performance", "best-practices"],
|
|
1889
2132
|
severity: "warning",
|
|
1890
2133
|
weight: 5,
|
|
1891
2134
|
evaluate: (ctx) => {
|
|
1892
2135
|
if (ctx.elements.tree.length === 0) {
|
|
1893
|
-
return { status: "skipped", reason:
|
|
2136
|
+
return { status: "skipped", reason: __29("No elements", "elementor") };
|
|
1894
2137
|
}
|
|
1895
2138
|
const widgetsCache = getWidgetsCache();
|
|
1896
2139
|
const violations = [];
|
|
@@ -1901,10 +2144,10 @@ var audit3 = {
|
|
|
1901
2144
|
const depth = parents.filter((parent) => isNestingElement(parent, widgetsCache)).length + 1;
|
|
1902
2145
|
if (depth > MAX_NESTING_DEPTH) {
|
|
1903
2146
|
violations.push({
|
|
1904
|
-
auditId:
|
|
2147
|
+
auditId: audit5.id,
|
|
1905
2148
|
elementId: node.id,
|
|
1906
2149
|
targetHint: "element-settings",
|
|
1907
|
-
label:
|
|
2150
|
+
label: __29("Container nesting is too deep.", "elementor")
|
|
1908
2151
|
});
|
|
1909
2152
|
}
|
|
1910
2153
|
});
|
|
@@ -1913,15 +2156,15 @@ var audit3 = {
|
|
|
1913
2156
|
};
|
|
1914
2157
|
|
|
1915
2158
|
// src/audits/default-design-system.ts
|
|
1916
|
-
import { __ as
|
|
1917
|
-
var
|
|
2159
|
+
import { __ as __30 } from "@wordpress/i18n";
|
|
2160
|
+
var audit6 = {
|
|
1918
2161
|
id: "audits/default-design-system",
|
|
1919
|
-
title:
|
|
1920
|
-
description:
|
|
2162
|
+
title: __30("Default website kit", "elementor"),
|
|
2163
|
+
description: __30(
|
|
1921
2164
|
"Your website is using the default design system colors and fonts. Custom branding makes the website feel uniquely yours.",
|
|
1922
2165
|
"elementor"
|
|
1923
2166
|
),
|
|
1924
|
-
fixHint:
|
|
2167
|
+
fixHint: __30("Open Site Settings and customize your kit (colors, fonts, layout).", "elementor"),
|
|
1925
2168
|
categories: ["best-practices"],
|
|
1926
2169
|
severity: "info",
|
|
1927
2170
|
weight: 1,
|
|
@@ -1933,8 +2176,8 @@ var audit4 = {
|
|
|
1933
2176
|
status: "fail",
|
|
1934
2177
|
violations: [
|
|
1935
2178
|
{
|
|
1936
|
-
auditId:
|
|
1937
|
-
label:
|
|
2179
|
+
auditId: audit6.id,
|
|
2180
|
+
label: __30("Kit appears unchanged from default.", "elementor"),
|
|
1938
2181
|
targetHint: "site-settings"
|
|
1939
2182
|
}
|
|
1940
2183
|
]
|
|
@@ -1944,16 +2187,16 @@ var audit4 = {
|
|
|
1944
2187
|
|
|
1945
2188
|
// src/audits/deprecated-widgets.ts
|
|
1946
2189
|
import { getWidgetsCache as getWidgetsCache2 } from "@elementor/editor-elements";
|
|
1947
|
-
import { __ as
|
|
2190
|
+
import { __ as __31 } from "@wordpress/i18n";
|
|
1948
2191
|
var DEPRECATION_CONTROL_NAME = "deprecation_message";
|
|
1949
|
-
var
|
|
2192
|
+
var audit7 = {
|
|
1950
2193
|
id: "audits/deprecated-widgets",
|
|
1951
|
-
title:
|
|
1952
|
-
description:
|
|
2194
|
+
title: __31("Deprecated widgets", "elementor"),
|
|
2195
|
+
description: __31(
|
|
1953
2196
|
"Deprecated widgets should not be used. For better capabilities use the recommended replacement.",
|
|
1954
2197
|
"elementor"
|
|
1955
2198
|
),
|
|
1956
|
-
fixHint:
|
|
2199
|
+
fixHint: __31("Replace each deprecated widget with the recommended new widget shown in its panel.", "elementor"),
|
|
1957
2200
|
categories: ["best-practices", "performance"],
|
|
1958
2201
|
severity: "warning",
|
|
1959
2202
|
weight: 7,
|
|
@@ -1977,10 +2220,10 @@ var audit5 = {
|
|
|
1977
2220
|
return;
|
|
1978
2221
|
}
|
|
1979
2222
|
violations.push({
|
|
1980
|
-
auditId:
|
|
2223
|
+
auditId: audit7.id,
|
|
1981
2224
|
elementId: node.id,
|
|
1982
2225
|
targetHint: "element-settings",
|
|
1983
|
-
label:
|
|
2226
|
+
label: __31("Using deprecated widget.", "elementor")
|
|
1984
2227
|
});
|
|
1985
2228
|
});
|
|
1986
2229
|
return violations.length === 0 ? { status: "pass" } : { status: "fail", violations };
|
|
@@ -1988,28 +2231,7 @@ var audit5 = {
|
|
|
1988
2231
|
};
|
|
1989
2232
|
|
|
1990
2233
|
// src/audits/google-consent-mode.ts
|
|
1991
|
-
import { __ as
|
|
1992
|
-
|
|
1993
|
-
// src/utils/fetch-rendered-html.ts
|
|
1994
|
-
var FETCH_TIMEOUT_MS = 1e4;
|
|
1995
|
-
async function fetchRenderedHtml(url) {
|
|
1996
|
-
if (!url) {
|
|
1997
|
-
return null;
|
|
1998
|
-
}
|
|
1999
|
-
const timeoutController = new AbortController();
|
|
2000
|
-
const timeoutId = setTimeout(() => timeoutController.abort(), FETCH_TIMEOUT_MS);
|
|
2001
|
-
try {
|
|
2002
|
-
const response = await fetch(url, { credentials: "omit", signal: timeoutController.signal });
|
|
2003
|
-
if (!response.ok) {
|
|
2004
|
-
return null;
|
|
2005
|
-
}
|
|
2006
|
-
return await response.text();
|
|
2007
|
-
} catch {
|
|
2008
|
-
return null;
|
|
2009
|
-
} finally {
|
|
2010
|
-
clearTimeout(timeoutId);
|
|
2011
|
-
}
|
|
2012
|
-
}
|
|
2234
|
+
import { __ as __32 } from "@wordpress/i18n";
|
|
2013
2235
|
|
|
2014
2236
|
// src/utils/scan-consent-signals.ts
|
|
2015
2237
|
var GOOGLE_TRACKING_PATTERNS = [
|
|
@@ -2030,44 +2252,43 @@ function hasConsentDefaultCall(html) {
|
|
|
2030
2252
|
}
|
|
2031
2253
|
|
|
2032
2254
|
// src/audits/google-consent-mode.ts
|
|
2033
|
-
var
|
|
2255
|
+
var audit8 = {
|
|
2034
2256
|
id: "audits/google-consent-mode",
|
|
2035
|
-
title:
|
|
2036
|
-
description:
|
|
2257
|
+
title: __32("Google Consent Mode", "elementor"),
|
|
2258
|
+
description: __32(
|
|
2037
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.",
|
|
2038
2260
|
"elementor"
|
|
2039
2261
|
),
|
|
2040
|
-
fixHint:
|
|
2262
|
+
fixHint: __32(
|
|
2041
2263
|
"Turn on Google Consent Mode in your cookie consent plugin so Google tags respect visitor consent choices.",
|
|
2042
2264
|
"elementor"
|
|
2043
2265
|
),
|
|
2044
2266
|
categories: ["compliance"],
|
|
2045
2267
|
severity: "warning",
|
|
2046
2268
|
weight: 1,
|
|
2047
|
-
evaluate:
|
|
2269
|
+
evaluate: (ctx) => {
|
|
2048
2270
|
if (!ctx.pageContext.frontend_url) {
|
|
2049
|
-
return { status: "skipped", reason:
|
|
2271
|
+
return { status: "skipped", reason: __32("Page is not published.", "elementor") };
|
|
2050
2272
|
}
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
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") };
|
|
2054
2275
|
}
|
|
2055
|
-
if (!hasGoogleTracking(
|
|
2056
|
-
return { status: "skipped", reason:
|
|
2276
|
+
if (!hasGoogleTracking(ctx.renderedHtml)) {
|
|
2277
|
+
return { status: "skipped", reason: __32("No Google tracking product detected.", "elementor") };
|
|
2057
2278
|
}
|
|
2058
|
-
if (hasConsentDefaultCall(
|
|
2279
|
+
if (hasConsentDefaultCall(ctx.renderedHtml)) {
|
|
2059
2280
|
return { status: "pass" };
|
|
2060
2281
|
}
|
|
2061
|
-
const label =
|
|
2282
|
+
const label = __32("No Google Consent Mode signal was found on the page.", "elementor");
|
|
2062
2283
|
const isCookiezReady = ctx.pageContext.cookiez_plugin_installed && ctx.pageContext.cookiez_plugin_active;
|
|
2063
2284
|
if (isCookiezReady) {
|
|
2064
2285
|
return {
|
|
2065
2286
|
status: "fail",
|
|
2066
2287
|
violations: [
|
|
2067
2288
|
{
|
|
2068
|
-
auditId:
|
|
2289
|
+
auditId: audit8.id,
|
|
2069
2290
|
label,
|
|
2070
|
-
ctaLabel:
|
|
2291
|
+
ctaLabel: __32("Enable", "elementor"),
|
|
2071
2292
|
externalUrl: ctx.pageContext.cookiez_consent_mode_settings_url
|
|
2072
2293
|
}
|
|
2073
2294
|
]
|
|
@@ -2077,7 +2298,7 @@ var audit6 = {
|
|
|
2077
2298
|
status: "fail",
|
|
2078
2299
|
violations: [
|
|
2079
2300
|
{
|
|
2080
|
-
auditId:
|
|
2301
|
+
auditId: audit8.id,
|
|
2081
2302
|
label,
|
|
2082
2303
|
externalUrl: ctx.pageContext.cookiez_plugin_action_url
|
|
2083
2304
|
}
|
|
@@ -2087,7 +2308,7 @@ var audit6 = {
|
|
|
2087
2308
|
};
|
|
2088
2309
|
|
|
2089
2310
|
// src/audits/heading-structure.ts
|
|
2090
|
-
import { __ as
|
|
2311
|
+
import { __ as __33 } from "@wordpress/i18n";
|
|
2091
2312
|
var HEADING_LEVELS = ["h1", "h2", "h3", "h4", "h5", "h6"];
|
|
2092
2313
|
var HEADING_CONTROLS_REGISTRY = {
|
|
2093
2314
|
// Core
|
|
@@ -2263,47 +2484,47 @@ function extractPageHeadings(tree) {
|
|
|
2263
2484
|
});
|
|
2264
2485
|
return headings;
|
|
2265
2486
|
}
|
|
2266
|
-
var
|
|
2487
|
+
var audit9 = {
|
|
2267
2488
|
id: "audits/heading-structure",
|
|
2268
|
-
title:
|
|
2269
|
-
description:
|
|
2270
|
-
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"),
|
|
2271
2492
|
categories: ["seo", "accessibility"],
|
|
2272
2493
|
severity: "error",
|
|
2273
2494
|
weight: 10,
|
|
2274
2495
|
evaluate: (ctx) => {
|
|
2275
2496
|
if (ctx.elements.tree.length === 0) {
|
|
2276
|
-
return { status: "skipped", reason:
|
|
2497
|
+
return { status: "skipped", reason: __33("No elements", "elementor") };
|
|
2277
2498
|
}
|
|
2278
2499
|
const headings = extractPageHeadings(ctx.elements.tree);
|
|
2279
2500
|
const violations = [];
|
|
2280
2501
|
if (headings.length === 0) {
|
|
2281
2502
|
violations.push({
|
|
2282
|
-
auditId:
|
|
2283
|
-
label:
|
|
2503
|
+
auditId: audit9.id,
|
|
2504
|
+
label: __33("No headings found on the page.", "elementor")
|
|
2284
2505
|
});
|
|
2285
2506
|
} else {
|
|
2286
2507
|
const h1Count = headings.filter((h) => h.level === 1).length;
|
|
2287
2508
|
if (h1Count === 0) {
|
|
2288
|
-
violations.push({ auditId:
|
|
2509
|
+
violations.push({ auditId: audit9.id, label: __33("No H1 on the page.", "elementor") });
|
|
2289
2510
|
}
|
|
2290
2511
|
if (h1Count > 1) {
|
|
2291
2512
|
headings.filter((h) => h.level === 1).slice(1).forEach(
|
|
2292
2513
|
(h) => violations.push({
|
|
2293
|
-
auditId:
|
|
2514
|
+
auditId: audit9.id,
|
|
2294
2515
|
elementId: h.elementId,
|
|
2295
2516
|
targetHint: "element-settings",
|
|
2296
|
-
label:
|
|
2517
|
+
label: __33("More than one H1 on the page.", "elementor")
|
|
2297
2518
|
})
|
|
2298
2519
|
);
|
|
2299
2520
|
}
|
|
2300
2521
|
for (let i = 1; i < headings.length; i++) {
|
|
2301
2522
|
if (headings[i].level - headings[i - 1].level > 1) {
|
|
2302
2523
|
violations.push({
|
|
2303
|
-
auditId:
|
|
2524
|
+
auditId: audit9.id,
|
|
2304
2525
|
elementId: headings[i].elementId,
|
|
2305
2526
|
targetHint: "element-settings",
|
|
2306
|
-
label:
|
|
2527
|
+
label: __33("Heading level skipped.", "elementor")
|
|
2307
2528
|
});
|
|
2308
2529
|
}
|
|
2309
2530
|
}
|
|
@@ -2313,33 +2534,33 @@ var audit7 = {
|
|
|
2313
2534
|
};
|
|
2314
2535
|
|
|
2315
2536
|
// src/audits/hidden-elements.ts
|
|
2316
|
-
import { __ as
|
|
2537
|
+
import { __ as __34 } from "@wordpress/i18n";
|
|
2317
2538
|
function isHiddenOnAllDevices(settings) {
|
|
2318
2539
|
return Boolean(settings.hide_desktop) && Boolean(settings.hide_tablet) && Boolean(settings.hide_mobile);
|
|
2319
2540
|
}
|
|
2320
|
-
var
|
|
2541
|
+
var audit10 = {
|
|
2321
2542
|
id: "audits/hidden-elements",
|
|
2322
|
-
title:
|
|
2323
|
-
description:
|
|
2543
|
+
title: __34("Hidden elements", "elementor"),
|
|
2544
|
+
description: __34(
|
|
2324
2545
|
"Elements hidden on all devices simultaneously are effectively dead code in the page tree.",
|
|
2325
2546
|
"elementor"
|
|
2326
2547
|
),
|
|
2327
|
-
fixHint:
|
|
2548
|
+
fixHint: __34("Remove the element or make it visible on at least one device breakpoint.", "elementor"),
|
|
2328
2549
|
categories: ["best-practices", "performance"],
|
|
2329
2550
|
severity: "info",
|
|
2330
2551
|
weight: 3,
|
|
2331
2552
|
evaluate: (ctx) => {
|
|
2332
2553
|
if (ctx.elements.tree.length === 0) {
|
|
2333
|
-
return { status: "skipped", reason:
|
|
2554
|
+
return { status: "skipped", reason: __34("No elements", "elementor") };
|
|
2334
2555
|
}
|
|
2335
2556
|
const violations = [];
|
|
2336
2557
|
walkElements(ctx.elements.tree, (node) => {
|
|
2337
2558
|
if (isHiddenOnAllDevices(node.settings)) {
|
|
2338
2559
|
violations.push({
|
|
2339
|
-
auditId:
|
|
2560
|
+
auditId: audit10.id,
|
|
2340
2561
|
elementId: node.id,
|
|
2341
2562
|
targetHint: "element-settings",
|
|
2342
|
-
label:
|
|
2563
|
+
label: __34("Element is hidden on all devices.", "elementor")
|
|
2343
2564
|
});
|
|
2344
2565
|
}
|
|
2345
2566
|
});
|
|
@@ -2348,7 +2569,7 @@ var audit8 = {
|
|
|
2348
2569
|
};
|
|
2349
2570
|
|
|
2350
2571
|
// src/audits/images-alt-text.ts
|
|
2351
|
-
import { __ as
|
|
2572
|
+
import { __ as __35 } from "@wordpress/i18n";
|
|
2352
2573
|
|
|
2353
2574
|
// src/utils/image-alt.ts
|
|
2354
2575
|
function hasMeaningfulAlt(media, pageContext) {
|
|
@@ -2356,7 +2577,8 @@ function hasMeaningfulAlt(media, pageContext) {
|
|
|
2356
2577
|
return true;
|
|
2357
2578
|
}
|
|
2358
2579
|
if (media.id) {
|
|
2359
|
-
const
|
|
2580
|
+
const key = buildImageSizeKey({ id: media.id, size: media.size });
|
|
2581
|
+
const alt = pageContext.image_sizes[key]?.alt ?? "";
|
|
2360
2582
|
return alt.trim().length > 0;
|
|
2361
2583
|
}
|
|
2362
2584
|
return (media.alt ?? "").trim().length > 0;
|
|
@@ -2366,17 +2588,17 @@ function isImageSourcePresent(media) {
|
|
|
2366
2588
|
}
|
|
2367
2589
|
|
|
2368
2590
|
// src/audits/images-alt-text.ts
|
|
2369
|
-
var
|
|
2591
|
+
var audit11 = {
|
|
2370
2592
|
id: "audits/images-alt-text",
|
|
2371
|
-
title:
|
|
2372
|
-
description:
|
|
2373
|
-
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"),
|
|
2374
2596
|
categories: ["seo", "accessibility"],
|
|
2375
2597
|
severity: "error",
|
|
2376
2598
|
weight: 10,
|
|
2377
2599
|
evaluate: (ctx) => {
|
|
2378
2600
|
if (!hasPageImages(ctx.elements.tree)) {
|
|
2379
|
-
return { status: "skipped", reason:
|
|
2601
|
+
return { status: "skipped", reason: __35("No images", "elementor") };
|
|
2380
2602
|
}
|
|
2381
2603
|
const violations = [];
|
|
2382
2604
|
const failedWidgetIds = /* @__PURE__ */ new Set();
|
|
@@ -2389,10 +2611,10 @@ var audit9 = {
|
|
|
2389
2611
|
if (!failedWidgetIds.has(node.id)) {
|
|
2390
2612
|
failedWidgetIds.add(node.id);
|
|
2391
2613
|
violations.push({
|
|
2392
|
-
auditId:
|
|
2614
|
+
auditId: audit11.id,
|
|
2393
2615
|
elementId: node.id,
|
|
2394
2616
|
targetHint: "element-settings",
|
|
2395
|
-
label:
|
|
2617
|
+
label: __35("Image is missing alt text.", "elementor"),
|
|
2396
2618
|
externalUrl: ctx.pageContext.ally_plugin_url
|
|
2397
2619
|
});
|
|
2398
2620
|
}
|
|
@@ -2401,30 +2623,79 @@ var audit9 = {
|
|
|
2401
2623
|
}
|
|
2402
2624
|
};
|
|
2403
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
|
+
|
|
2404
2674
|
// src/audits/images-too-large.ts
|
|
2405
|
-
import { __ as
|
|
2675
|
+
import { __ as __37, sprintf as sprintf4 } from "@wordpress/i18n";
|
|
2406
2676
|
var SIZE_THRESHOLD_BYTES = 500 * 1024;
|
|
2407
2677
|
var BYTES_PER_KB = 1024;
|
|
2408
|
-
var
|
|
2678
|
+
var audit13 = {
|
|
2409
2679
|
id: "audits/images-too-large",
|
|
2410
|
-
title:
|
|
2411
|
-
description:
|
|
2412
|
-
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"),
|
|
2413
2683
|
categories: ["performance"],
|
|
2414
2684
|
severity: "warning",
|
|
2415
2685
|
weight: 7,
|
|
2416
2686
|
evaluate: (ctx) => {
|
|
2417
|
-
if (!hasPageImages(ctx.elements.tree)) {
|
|
2418
|
-
return { status: "skipped", reason: __34("No images", "elementor") };
|
|
2419
|
-
}
|
|
2420
2687
|
const widgetMaxKb = /* @__PURE__ */ new Map();
|
|
2421
2688
|
let oversizedImageCount = 0;
|
|
2422
|
-
|
|
2689
|
+
let hasAnyImage = false;
|
|
2690
|
+
const evaluateSource = (node, media) => {
|
|
2691
|
+
if (media.id || media.url) {
|
|
2692
|
+
hasAnyImage = true;
|
|
2693
|
+
}
|
|
2423
2694
|
const id = media.id;
|
|
2424
2695
|
if (!id) {
|
|
2425
2696
|
return;
|
|
2426
2697
|
}
|
|
2427
|
-
const size = ctx.pageContext.image_sizes[id];
|
|
2698
|
+
const size = ctx.pageContext.image_sizes[buildImageSizeKey({ id, size: media.size })];
|
|
2428
2699
|
if (!size || size.filesize_bytes <= SIZE_THRESHOLD_BYTES) {
|
|
2429
2700
|
return;
|
|
2430
2701
|
}
|
|
@@ -2432,14 +2703,21 @@ var audit10 = {
|
|
|
2432
2703
|
const kb = Math.round(size.filesize_bytes / BYTES_PER_KB);
|
|
2433
2704
|
const currentMax = widgetMaxKb.get(node.id) ?? 0;
|
|
2434
2705
|
widgetMaxKb.set(node.id, Math.max(currentMax, kb));
|
|
2435
|
-
}
|
|
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
|
+
}
|
|
2436
2714
|
const violations = Array.from(widgetMaxKb.entries()).map(([elementId, kb]) => ({
|
|
2437
|
-
auditId:
|
|
2715
|
+
auditId: audit13.id,
|
|
2438
2716
|
elementId,
|
|
2439
2717
|
targetHint: "element-settings",
|
|
2440
2718
|
label: sprintf4(
|
|
2441
2719
|
/* translators: %d is the image file size in kilobytes. */
|
|
2442
|
-
|
|
2720
|
+
__37("Image is %d KB (over 500 KB).", "elementor"),
|
|
2443
2721
|
kb
|
|
2444
2722
|
),
|
|
2445
2723
|
externalUrl: ctx.pageContext.image_optimization_plugin_url
|
|
@@ -2449,21 +2727,21 @@ var audit10 = {
|
|
|
2449
2727
|
};
|
|
2450
2728
|
|
|
2451
2729
|
// src/audits/nested-boxed-containers.ts
|
|
2452
|
-
import { __ as
|
|
2730
|
+
import { __ as __38 } from "@wordpress/i18n";
|
|
2453
2731
|
function isBoxed(settings) {
|
|
2454
2732
|
return settings.content_width === "boxed";
|
|
2455
2733
|
}
|
|
2456
|
-
var
|
|
2734
|
+
var audit14 = {
|
|
2457
2735
|
id: "audits/nested-boxed-containers",
|
|
2458
|
-
title:
|
|
2459
|
-
description:
|
|
2460
|
-
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"),
|
|
2461
2739
|
categories: ["best-practices", "performance"],
|
|
2462
2740
|
severity: "info",
|
|
2463
2741
|
weight: 5,
|
|
2464
2742
|
evaluate: (ctx) => {
|
|
2465
2743
|
if (ctx.elements.tree.length === 0) {
|
|
2466
|
-
return { status: "skipped", reason:
|
|
2744
|
+
return { status: "skipped", reason: __38("No elements", "elementor") };
|
|
2467
2745
|
}
|
|
2468
2746
|
const violations = [];
|
|
2469
2747
|
walkElements(ctx.elements.tree, (node, parents) => {
|
|
@@ -2473,10 +2751,10 @@ var audit11 = {
|
|
|
2473
2751
|
const nearestContainerAncestor = [...parents].reverse().find((p) => p.elType === "container");
|
|
2474
2752
|
if (nearestContainerAncestor && isBoxed(nearestContainerAncestor.settings)) {
|
|
2475
2753
|
violations.push({
|
|
2476
|
-
auditId:
|
|
2754
|
+
auditId: audit14.id,
|
|
2477
2755
|
elementId: node.id,
|
|
2478
2756
|
targetHint: "element-settings",
|
|
2479
|
-
label:
|
|
2757
|
+
label: __38("Nested boxed container.", "elementor")
|
|
2480
2758
|
});
|
|
2481
2759
|
}
|
|
2482
2760
|
});
|
|
@@ -2485,12 +2763,12 @@ var audit11 = {
|
|
|
2485
2763
|
};
|
|
2486
2764
|
|
|
2487
2765
|
// src/audits/page-excerpt.ts
|
|
2488
|
-
import { __ as
|
|
2489
|
-
var
|
|
2766
|
+
import { __ as __39 } from "@wordpress/i18n";
|
|
2767
|
+
var audit15 = {
|
|
2490
2768
|
id: "audits/page-excerpt",
|
|
2491
|
-
title:
|
|
2492
|
-
description:
|
|
2493
|
-
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"),
|
|
2494
2772
|
categories: ["seo"],
|
|
2495
2773
|
severity: "warning",
|
|
2496
2774
|
weight: 5,
|
|
@@ -2502,8 +2780,8 @@ var audit12 = {
|
|
|
2502
2780
|
status: "fail",
|
|
2503
2781
|
violations: [
|
|
2504
2782
|
{
|
|
2505
|
-
auditId:
|
|
2506
|
-
label:
|
|
2783
|
+
auditId: audit15.id,
|
|
2784
|
+
label: __39("Page has no excerpt.", "elementor"),
|
|
2507
2785
|
targetHint: "page-settings",
|
|
2508
2786
|
angieFix: true
|
|
2509
2787
|
}
|
|
@@ -2513,12 +2791,12 @@ var audit12 = {
|
|
|
2513
2791
|
};
|
|
2514
2792
|
|
|
2515
2793
|
// src/audits/page-featured-image.ts
|
|
2516
|
-
import { __ as
|
|
2517
|
-
var
|
|
2794
|
+
import { __ as __40 } from "@wordpress/i18n";
|
|
2795
|
+
var audit16 = {
|
|
2518
2796
|
id: "audits/page-featured-image",
|
|
2519
|
-
title:
|
|
2520
|
-
description:
|
|
2521
|
-
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"),
|
|
2522
2800
|
categories: ["seo"],
|
|
2523
2801
|
severity: "info",
|
|
2524
2802
|
weight: 5,
|
|
@@ -2530,8 +2808,8 @@ var audit13 = {
|
|
|
2530
2808
|
status: "fail",
|
|
2531
2809
|
violations: [
|
|
2532
2810
|
{
|
|
2533
|
-
auditId:
|
|
2534
|
-
label:
|
|
2811
|
+
auditId: audit16.id,
|
|
2812
|
+
label: __40("No featured image set.", "elementor"),
|
|
2535
2813
|
targetHint: "page-settings"
|
|
2536
2814
|
}
|
|
2537
2815
|
]
|
|
@@ -2540,13 +2818,13 @@ var audit13 = {
|
|
|
2540
2818
|
};
|
|
2541
2819
|
|
|
2542
2820
|
// src/audits/page-title.ts
|
|
2543
|
-
import { __ as
|
|
2821
|
+
import { __ as __41 } from "@wordpress/i18n";
|
|
2544
2822
|
var MAX_TITLE_LENGTH = 60;
|
|
2545
|
-
var
|
|
2823
|
+
var audit17 = {
|
|
2546
2824
|
id: "audits/page-title",
|
|
2547
|
-
title:
|
|
2548
|
-
description:
|
|
2549
|
-
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"),
|
|
2550
2828
|
categories: ["seo"],
|
|
2551
2829
|
severity: "error",
|
|
2552
2830
|
weight: 10,
|
|
@@ -2557,10 +2835,14 @@ var audit14 = {
|
|
|
2557
2835
|
status: "fail",
|
|
2558
2836
|
violations: [
|
|
2559
2837
|
{
|
|
2560
|
-
auditId:
|
|
2561
|
-
label:
|
|
2838
|
+
auditId: audit17.id,
|
|
2839
|
+
label: __41("Page has no title.", "elementor"),
|
|
2562
2840
|
targetHint: "page-settings",
|
|
2563
|
-
angieFix: true
|
|
2841
|
+
angieFix: true,
|
|
2842
|
+
angiePrompt: __41(
|
|
2843
|
+
"Based on this page's contents, generate a title for this page.",
|
|
2844
|
+
"elementor"
|
|
2845
|
+
)
|
|
2564
2846
|
}
|
|
2565
2847
|
]
|
|
2566
2848
|
};
|
|
@@ -2570,8 +2852,8 @@ var audit14 = {
|
|
|
2570
2852
|
status: "fail",
|
|
2571
2853
|
violations: [
|
|
2572
2854
|
{
|
|
2573
|
-
auditId:
|
|
2574
|
-
label:
|
|
2855
|
+
auditId: audit17.id,
|
|
2856
|
+
label: __41("Page title is too long.", "elementor"),
|
|
2575
2857
|
targetHint: "page-settings",
|
|
2576
2858
|
angieFix: true
|
|
2577
2859
|
}
|
|
@@ -2583,7 +2865,7 @@ var audit14 = {
|
|
|
2583
2865
|
};
|
|
2584
2866
|
|
|
2585
2867
|
// src/audits/prefer-global-colors.ts
|
|
2586
|
-
import { __ as
|
|
2868
|
+
import { __ as __42, sprintf as sprintf5 } from "@wordpress/i18n";
|
|
2587
2869
|
|
|
2588
2870
|
// src/utils/collect-hardcoded-colors.ts
|
|
2589
2871
|
var RESERVED_SETTING_KEYS = /* @__PURE__ */ new Set(["__globals__", "__dynamic__"]);
|
|
@@ -2649,20 +2931,20 @@ function findMatchingGlobalByValue(value, globals) {
|
|
|
2649
2931
|
}
|
|
2650
2932
|
|
|
2651
2933
|
// src/audits/prefer-global-colors.ts
|
|
2652
|
-
var
|
|
2934
|
+
var audit18 = {
|
|
2653
2935
|
id: "audits/prefer-global-colors",
|
|
2654
|
-
title:
|
|
2655
|
-
description:
|
|
2656
|
-
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"),
|
|
2657
2939
|
categories: ["best-practices"],
|
|
2658
2940
|
severity: "info",
|
|
2659
2941
|
weight: 3,
|
|
2660
2942
|
evaluate: (ctx) => {
|
|
2661
2943
|
if (ctx.elements.tree.length === 0) {
|
|
2662
|
-
return { status: "skipped", reason:
|
|
2944
|
+
return { status: "skipped", reason: __42("No elements", "elementor") };
|
|
2663
2945
|
}
|
|
2664
2946
|
if (ctx.kit.globals.colors.length === 0) {
|
|
2665
|
-
return { status: "skipped", reason:
|
|
2947
|
+
return { status: "skipped", reason: __42("No global colors", "elementor") };
|
|
2666
2948
|
}
|
|
2667
2949
|
const violations = [];
|
|
2668
2950
|
walkElements(ctx.elements.tree, (node) => {
|
|
@@ -2672,13 +2954,13 @@ var audit15 = {
|
|
|
2672
2954
|
continue;
|
|
2673
2955
|
}
|
|
2674
2956
|
violations.push({
|
|
2675
|
-
auditId:
|
|
2957
|
+
auditId: audit18.id,
|
|
2676
2958
|
elementId: node.id,
|
|
2677
2959
|
targetHint: "element-settings",
|
|
2678
2960
|
angieFix: true,
|
|
2679
2961
|
label: sprintf5(
|
|
2680
2962
|
/* translators: 1: hard-coded color value, 2: global color title. */
|
|
2681
|
-
|
|
2963
|
+
__42('replace "%1$s" with "%2$s" global color', "elementor"),
|
|
2682
2964
|
value,
|
|
2683
2965
|
global.title
|
|
2684
2966
|
)
|
|
@@ -2690,7 +2972,7 @@ var audit15 = {
|
|
|
2690
2972
|
};
|
|
2691
2973
|
|
|
2692
2974
|
// src/audits/prefer-global-fonts.ts
|
|
2693
|
-
import { __ as
|
|
2975
|
+
import { __ as __43, sprintf as sprintf6 } from "@wordpress/i18n";
|
|
2694
2976
|
|
|
2695
2977
|
// src/utils/collect-hardcoded-fonts.ts
|
|
2696
2978
|
var RESERVED_SETTING_KEYS2 = /* @__PURE__ */ new Set(["__globals__", "__dynamic__"]);
|
|
@@ -2748,20 +3030,20 @@ function collectHardcodedFonts(settings, pathPrefix = "") {
|
|
|
2748
3030
|
}
|
|
2749
3031
|
|
|
2750
3032
|
// src/audits/prefer-global-fonts.ts
|
|
2751
|
-
var
|
|
3033
|
+
var audit19 = {
|
|
2752
3034
|
id: "audits/prefer-global-fonts",
|
|
2753
|
-
title:
|
|
2754
|
-
description:
|
|
2755
|
-
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"),
|
|
2756
3038
|
categories: ["best-practices", "performance"],
|
|
2757
3039
|
severity: "info",
|
|
2758
3040
|
weight: 3,
|
|
2759
3041
|
evaluate: (ctx) => {
|
|
2760
3042
|
if (ctx.elements.tree.length === 0) {
|
|
2761
|
-
return { status: "skipped", reason:
|
|
3043
|
+
return { status: "skipped", reason: __43("No elements", "elementor") };
|
|
2762
3044
|
}
|
|
2763
3045
|
if (ctx.kit.globals.fonts.length === 0) {
|
|
2764
|
-
return { status: "skipped", reason:
|
|
3046
|
+
return { status: "skipped", reason: __43("No global fonts", "elementor") };
|
|
2765
3047
|
}
|
|
2766
3048
|
const violations = [];
|
|
2767
3049
|
walkElements(ctx.elements.tree, (node) => {
|
|
@@ -2771,12 +3053,12 @@ var audit16 = {
|
|
|
2771
3053
|
continue;
|
|
2772
3054
|
}
|
|
2773
3055
|
violations.push({
|
|
2774
|
-
auditId:
|
|
3056
|
+
auditId: audit19.id,
|
|
2775
3057
|
elementId: node.id,
|
|
2776
3058
|
targetHint: "element-settings",
|
|
2777
3059
|
label: sprintf6(
|
|
2778
3060
|
/* translators: %s: global font title. */
|
|
2779
|
-
|
|
3061
|
+
__43('replace hardcoded typography with "%s" global font', "elementor"),
|
|
2780
3062
|
global.title
|
|
2781
3063
|
)
|
|
2782
3064
|
});
|
|
@@ -2787,15 +3069,15 @@ var audit16 = {
|
|
|
2787
3069
|
};
|
|
2788
3070
|
|
|
2789
3071
|
// src/audits/privacy-policy.ts
|
|
2790
|
-
import { __ as
|
|
2791
|
-
var
|
|
3072
|
+
import { __ as __44 } from "@wordpress/i18n";
|
|
3073
|
+
var audit20 = {
|
|
2792
3074
|
id: "audits/privacy-policy",
|
|
2793
|
-
title:
|
|
2794
|
-
description:
|
|
3075
|
+
title: __44("Privacy policy", "elementor"),
|
|
3076
|
+
description: __44(
|
|
2795
3077
|
"A privacy policy page is required by privacy regulations such as GDPR (EU) and CCPA (US).",
|
|
2796
3078
|
"elementor"
|
|
2797
3079
|
),
|
|
2798
|
-
fixHint:
|
|
3080
|
+
fixHint: __44(
|
|
2799
3081
|
"Go to Settings > Privacy in the WordPress admin and assign a published privacy policy page.",
|
|
2800
3082
|
"elementor"
|
|
2801
3083
|
),
|
|
@@ -2810,10 +3092,10 @@ var audit17 = {
|
|
|
2810
3092
|
status: "fail",
|
|
2811
3093
|
violations: [
|
|
2812
3094
|
{
|
|
2813
|
-
auditId:
|
|
2814
|
-
label:
|
|
3095
|
+
auditId: audit20.id,
|
|
3096
|
+
label: __44("No privacy policy page is set.", "elementor"),
|
|
2815
3097
|
externalUrl: ctx.pageContext.privacy_settings_url,
|
|
2816
|
-
ctaLabel:
|
|
3098
|
+
ctaLabel: __44("Create", "elementor")
|
|
2817
3099
|
}
|
|
2818
3100
|
]
|
|
2819
3101
|
};
|
|
@@ -2821,15 +3103,15 @@ var audit17 = {
|
|
|
2821
3103
|
};
|
|
2822
3104
|
|
|
2823
3105
|
// src/audits/robots-noindex.ts
|
|
2824
|
-
import { __ as
|
|
2825
|
-
var
|
|
3106
|
+
import { __ as __45 } from "@wordpress/i18n";
|
|
3107
|
+
var audit21 = {
|
|
2826
3108
|
id: "audits/robots-noindex",
|
|
2827
|
-
title:
|
|
2828
|
-
description:
|
|
3109
|
+
title: __45("Search engine visibility", "elementor"),
|
|
3110
|
+
description: __45(
|
|
2829
3111
|
"When search engine visibility is checked in WordPress Settings -> Reading -> Search Engine Visibility, search engines are discouraged from indexing the website.",
|
|
2830
3112
|
"elementor"
|
|
2831
3113
|
),
|
|
2832
|
-
fixHint:
|
|
3114
|
+
fixHint: __45(
|
|
2833
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.',
|
|
2834
3116
|
"elementor"
|
|
2835
3117
|
),
|
|
@@ -2844,8 +3126,8 @@ var audit18 = {
|
|
|
2844
3126
|
status: "fail",
|
|
2845
3127
|
violations: [
|
|
2846
3128
|
{
|
|
2847
|
-
auditId:
|
|
2848
|
-
label:
|
|
3129
|
+
auditId: audit21.id,
|
|
3130
|
+
label: __45("Search engines are discouraged from indexing this website.", "elementor"),
|
|
2849
3131
|
externalUrl: ctx.pageContext.reading_settings_url
|
|
2850
3132
|
}
|
|
2851
3133
|
]
|
|
@@ -2854,15 +3136,15 @@ var audit18 = {
|
|
|
2854
3136
|
};
|
|
2855
3137
|
|
|
2856
3138
|
// src/audits/scan-for-cookies.ts
|
|
2857
|
-
import { __ as
|
|
2858
|
-
var
|
|
3139
|
+
import { __ as __46 } from "@wordpress/i18n";
|
|
3140
|
+
var audit22 = {
|
|
2859
3141
|
id: "audits/scan-for-cookies",
|
|
2860
|
-
title:
|
|
2861
|
-
description:
|
|
3142
|
+
title: __46("Scan for cookies", "elementor"),
|
|
3143
|
+
description: __46(
|
|
2862
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.",
|
|
2863
3145
|
"elementor"
|
|
2864
3146
|
),
|
|
2865
|
-
fixHint:
|
|
3147
|
+
fixHint: __46("Run a Cookiez scan on this page to see which cookies need disclosure.", "elementor"),
|
|
2866
3148
|
categories: ["compliance"],
|
|
2867
3149
|
severity: "info",
|
|
2868
3150
|
weight: 0,
|
|
@@ -2872,8 +3154,8 @@ var audit19 = {
|
|
|
2872
3154
|
status: "fail",
|
|
2873
3155
|
violations: [
|
|
2874
3156
|
{
|
|
2875
|
-
auditId:
|
|
2876
|
-
label:
|
|
3157
|
+
auditId: audit22.id,
|
|
3158
|
+
label: __46("This page has not been scanned for cookies yet.", "elementor"),
|
|
2877
3159
|
externalUrl: isReady ? ctx.pageContext.cookiez_scan_url : ctx.pageContext.cookiez_plugin_action_url
|
|
2878
3160
|
}
|
|
2879
3161
|
]
|
|
@@ -2882,29 +3164,29 @@ var audit19 = {
|
|
|
2882
3164
|
};
|
|
2883
3165
|
|
|
2884
3166
|
// src/audits/sections-and-columns.ts
|
|
2885
|
-
import { __ as
|
|
2886
|
-
var
|
|
3167
|
+
import { __ as __47 } from "@wordpress/i18n";
|
|
3168
|
+
var audit23 = {
|
|
2887
3169
|
id: "audits/sections-and-columns",
|
|
2888
|
-
title:
|
|
2889
|
-
description:
|
|
3170
|
+
title: __47("Sections and columns", "elementor"),
|
|
3171
|
+
description: __47(
|
|
2890
3172
|
"Sections and columns are legacy elements. Containers render fewer DOM nodes and are more flexible.",
|
|
2891
3173
|
"elementor"
|
|
2892
3174
|
),
|
|
2893
|
-
fixHint:
|
|
3175
|
+
fixHint: __47("Use the Container Converter to replace each section/column with a container.", "elementor"),
|
|
2894
3176
|
categories: ["best-practices", "performance"],
|
|
2895
3177
|
severity: "warning",
|
|
2896
3178
|
weight: 7,
|
|
2897
3179
|
evaluate: (ctx) => {
|
|
2898
3180
|
if (ctx.elements.tree.length === 0) {
|
|
2899
|
-
return { status: "skipped", reason:
|
|
3181
|
+
return { status: "skipped", reason: __47("No elements", "elementor") };
|
|
2900
3182
|
}
|
|
2901
3183
|
const violations = [];
|
|
2902
3184
|
walkElements(ctx.elements.tree, (node) => {
|
|
2903
3185
|
if (node.elType === "section" || node.elType === "column") {
|
|
2904
3186
|
violations.push({
|
|
2905
|
-
auditId:
|
|
3187
|
+
auditId: audit23.id,
|
|
2906
3188
|
elementId: node.id,
|
|
2907
|
-
label: node.elType === "section" ?
|
|
3189
|
+
label: node.elType === "section" ? __47("Section element", "elementor") : __47("Column element", "elementor")
|
|
2908
3190
|
});
|
|
2909
3191
|
}
|
|
2910
3192
|
});
|
|
@@ -2913,15 +3195,15 @@ var audit20 = {
|
|
|
2913
3195
|
};
|
|
2914
3196
|
|
|
2915
3197
|
// src/audits/site-identity.ts
|
|
2916
|
-
import { __ as
|
|
2917
|
-
var
|
|
3198
|
+
import { __ as __48 } from "@wordpress/i18n";
|
|
3199
|
+
var audit24 = {
|
|
2918
3200
|
id: "audits/site-identity",
|
|
2919
|
-
title:
|
|
2920
|
-
description:
|
|
3201
|
+
title: __48("Site identity", "elementor"),
|
|
3202
|
+
description: __48(
|
|
2921
3203
|
"Site name, description, logo, and favicon establish your brand and appear in search results and browser tabs.",
|
|
2922
3204
|
"elementor"
|
|
2923
3205
|
),
|
|
2924
|
-
fixHint:
|
|
3206
|
+
fixHint: __48("Open Site Settings \u2192 Site Identity and complete all the missing fields.", "elementor"),
|
|
2925
3207
|
categories: ["best-practices", "seo"],
|
|
2926
3208
|
severity: "info",
|
|
2927
3209
|
weight: 7,
|
|
@@ -2930,30 +3212,30 @@ var audit21 = {
|
|
|
2930
3212
|
const violations = [];
|
|
2931
3213
|
if (!identity.site_name_set) {
|
|
2932
3214
|
violations.push({
|
|
2933
|
-
auditId:
|
|
2934
|
-
label:
|
|
3215
|
+
auditId: audit24.id,
|
|
3216
|
+
label: __48("Site name is missing or still uses the default.", "elementor"),
|
|
2935
3217
|
targetHint: "site-identity-settings"
|
|
2936
3218
|
});
|
|
2937
3219
|
}
|
|
2938
3220
|
if (!identity.site_description_set) {
|
|
2939
3221
|
violations.push({
|
|
2940
|
-
auditId:
|
|
2941
|
-
label:
|
|
3222
|
+
auditId: audit24.id,
|
|
3223
|
+
label: __48("Site description is missing or still uses the default.", "elementor"),
|
|
2942
3224
|
targetHint: "site-identity-settings",
|
|
2943
3225
|
angieFix: true
|
|
2944
3226
|
});
|
|
2945
3227
|
}
|
|
2946
3228
|
if (!identity.site_logo_set) {
|
|
2947
3229
|
violations.push({
|
|
2948
|
-
auditId:
|
|
2949
|
-
label:
|
|
3230
|
+
auditId: audit24.id,
|
|
3231
|
+
label: __48("Site logo is not set.", "elementor"),
|
|
2950
3232
|
targetHint: "site-identity-settings"
|
|
2951
3233
|
});
|
|
2952
3234
|
}
|
|
2953
3235
|
if (!identity.site_favicon_set) {
|
|
2954
3236
|
violations.push({
|
|
2955
|
-
auditId:
|
|
2956
|
-
label:
|
|
3237
|
+
auditId: audit24.id,
|
|
3238
|
+
label: __48("Site favicon is not set.", "elementor"),
|
|
2957
3239
|
targetHint: "site-identity-settings"
|
|
2958
3240
|
});
|
|
2959
3241
|
}
|
|
@@ -2969,7 +3251,7 @@ var audit21 = {
|
|
|
2969
3251
|
|
|
2970
3252
|
// src/audits/too-many-widgets.ts
|
|
2971
3253
|
import { getWidgetsCache as getWidgetsCache3 } from "@elementor/editor-elements";
|
|
2972
|
-
import { __ as
|
|
3254
|
+
import { __ as __49 } from "@wordpress/i18n";
|
|
2973
3255
|
var WIDGET_COUNT_THRESHOLD = 100;
|
|
2974
3256
|
function isCountableWidget(node, widgetsCache) {
|
|
2975
3257
|
if (node.elType === "widget") {
|
|
@@ -2977,17 +3259,17 @@ function isCountableWidget(node, widgetsCache) {
|
|
|
2977
3259
|
}
|
|
2978
3260
|
return !!widgetsCache?.[node.elType]?.meta?.is_compound;
|
|
2979
3261
|
}
|
|
2980
|
-
var
|
|
3262
|
+
var audit25 = {
|
|
2981
3263
|
id: "audits/too-many-widgets",
|
|
2982
|
-
title:
|
|
2983
|
-
description:
|
|
2984
|
-
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"),
|
|
2985
3267
|
categories: ["best-practices", "performance"],
|
|
2986
3268
|
severity: "warning",
|
|
2987
3269
|
weight: 5,
|
|
2988
3270
|
evaluate: (ctx) => {
|
|
2989
3271
|
if (ctx.elements.tree.length === 0) {
|
|
2990
|
-
return { status: "skipped", reason:
|
|
3272
|
+
return { status: "skipped", reason: __49("No elements", "elementor") };
|
|
2991
3273
|
}
|
|
2992
3274
|
const widgetsCache = getWidgetsCache3();
|
|
2993
3275
|
let widgetCount = 0;
|
|
@@ -3003,8 +3285,8 @@ var audit22 = {
|
|
|
3003
3285
|
status: "fail",
|
|
3004
3286
|
violations: [
|
|
3005
3287
|
{
|
|
3006
|
-
auditId:
|
|
3007
|
-
label:
|
|
3288
|
+
auditId: audit25.id,
|
|
3289
|
+
label: __49("Page has too many widgets.", "elementor")
|
|
3008
3290
|
}
|
|
3009
3291
|
]
|
|
3010
3292
|
};
|
|
@@ -3013,32 +3295,35 @@ var audit22 = {
|
|
|
3013
3295
|
|
|
3014
3296
|
// src/register-audits.ts
|
|
3015
3297
|
var AUDITS = [
|
|
3016
|
-
|
|
3017
|
-
audit12,
|
|
3018
|
-
audit13,
|
|
3019
|
-
audit8,
|
|
3020
|
-
audit5,
|
|
3021
|
-
audit22,
|
|
3022
|
-
audit20,
|
|
3023
|
-
audit3,
|
|
3024
|
-
audit11,
|
|
3025
|
-
audit4,
|
|
3026
|
-
audit21,
|
|
3298
|
+
audit17,
|
|
3027
3299
|
audit15,
|
|
3028
3300
|
audit16,
|
|
3029
|
-
audit7,
|
|
3030
|
-
audit9,
|
|
3031
3301
|
audit10,
|
|
3302
|
+
audit7,
|
|
3303
|
+
audit25,
|
|
3304
|
+
audit23,
|
|
3305
|
+
audit5,
|
|
3306
|
+
audit14,
|
|
3307
|
+
audit6,
|
|
3308
|
+
audit24,
|
|
3032
3309
|
audit18,
|
|
3033
|
-
|
|
3310
|
+
audit19,
|
|
3311
|
+
audit9,
|
|
3312
|
+
audit11,
|
|
3313
|
+
audit13,
|
|
3314
|
+
audit12,
|
|
3315
|
+
audit21,
|
|
3316
|
+
audit20,
|
|
3034
3317
|
audit,
|
|
3035
3318
|
audit2,
|
|
3036
|
-
|
|
3037
|
-
|
|
3319
|
+
audit3,
|
|
3320
|
+
audit4,
|
|
3321
|
+
audit22,
|
|
3322
|
+
audit8
|
|
3038
3323
|
];
|
|
3039
3324
|
function registerAllAudits() {
|
|
3040
|
-
for (const
|
|
3041
|
-
registerAudit(
|
|
3325
|
+
for (const audit26 of AUDITS) {
|
|
3326
|
+
registerAudit(audit26);
|
|
3042
3327
|
}
|
|
3043
3328
|
}
|
|
3044
3329
|
|