@elementor/editor-audits 4.4.0-1106 → 4.4.0-1108

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elementor/editor-audits",
3
- "version": "4.4.0-1106",
3
+ "version": "4.4.0-1108",
4
4
  "private": false,
5
5
  "author": "Elementor Team",
6
6
  "homepage": "https://elementor.com/",
@@ -39,21 +39,21 @@
39
39
  "dev": "tsup --config=../../tsup.dev.ts"
40
40
  },
41
41
  "dependencies": {
42
- "@elementor/editor": "4.4.0-1106",
43
- "@elementor/editor-mcp": "4.4.0-1106",
44
- "@elementor/editor-app-bar": "4.4.0-1106",
45
- "@elementor/editor-elements": "4.4.0-1106",
46
- "@elementor/editor-floating-panels": "4.4.0-1106",
47
- "@elementor/editor-notifications": "4.4.0-1106",
48
- "@elementor/editor-props": "4.4.0-1106",
49
- "@elementor/editor-styles": "4.4.0-1106",
50
- "@elementor/editor-v1-adapters": "4.4.0-1106",
51
- "@elementor/events": "4.4.0-1106",
52
- "@elementor/http-client": "4.4.0-1106",
42
+ "@elementor/editor": "4.4.0-1108",
43
+ "@elementor/editor-mcp": "4.4.0-1108",
44
+ "@elementor/editor-app-bar": "4.4.0-1108",
45
+ "@elementor/editor-elements": "4.4.0-1108",
46
+ "@elementor/editor-floating-panels": "4.4.0-1108",
47
+ "@elementor/editor-notifications": "4.4.0-1108",
48
+ "@elementor/editor-props": "4.4.0-1108",
49
+ "@elementor/editor-styles": "4.4.0-1108",
50
+ "@elementor/editor-v1-adapters": "4.4.0-1108",
51
+ "@elementor/events": "4.4.0-1108",
52
+ "@elementor/http-client": "4.4.0-1108",
53
53
  "@elementor/icons": "~1.77.0",
54
- "@elementor/locations": "4.4.0-1106",
55
- "@elementor/session": "4.4.0-1106",
56
- "@elementor/store": "4.4.0-1106",
54
+ "@elementor/locations": "4.4.0-1108",
55
+ "@elementor/session": "4.4.0-1108",
56
+ "@elementor/store": "4.4.0-1108",
57
57
  "@elementor/ui": "1.37.5"
58
58
  },
59
59
  "peerDependencies": {
@@ -0,0 +1,39 @@
1
+ import { __ } from '@wordpress/i18n';
2
+
3
+ import { type Audit } from '../types';
4
+
5
+ export const audit: Audit = {
6
+ id: 'audits/accessibility-statement',
7
+ title: __( 'Create an accessibility statement', 'elementor' ),
8
+ description: __(
9
+ 'An accessibility statement showcases your efforts to create an inclusive online space, highlighting helpful features and a commitment to accessibility.',
10
+ 'elementor'
11
+ ),
12
+ fixHint: __( 'Use Ally to create and publish an accessibility statement for your site.', 'elementor' ),
13
+ categories: [ 'accessibility' ],
14
+ severity: 'info',
15
+ weight: 1,
16
+ evaluate: ( ctx ) => {
17
+ const isReady = ctx.pageContext.ally_plugin_active;
18
+
19
+ if ( isReady && ctx.pageContext.ally_accessibility_statement_created ) {
20
+ return { status: 'pass' };
21
+ }
22
+
23
+ return {
24
+ status: 'fail',
25
+ violations: [
26
+ {
27
+ auditId: audit.id,
28
+ label: __( 'No accessibility statement has been created for this site.', 'elementor' ),
29
+ externalUrl: isReady
30
+ ? ctx.pageContext.ally_accessibility_statement_url
31
+ : ctx.pageContext.ally_plugin_url,
32
+ ctaLabel: isReady ? __( 'Create', 'elementor' ) : undefined,
33
+ secondaryCtaLabel: __( 'Learn more', 'elementor' ),
34
+ secondaryCtaUrl: 'https://go.elementor.com/acc-plg-learn-more',
35
+ },
36
+ ],
37
+ };
38
+ },
39
+ };
@@ -0,0 +1,41 @@
1
+ import { __ } from '@wordpress/i18n';
2
+
3
+ import { type Audit } from '../types';
4
+ import { hasAccessibilityWidgetScript } from '../utils/scan-accessibility-widgets';
5
+
6
+ export const audit: Audit = {
7
+ id: 'audits/accessibility-widget',
8
+ title: __( 'Add an accessibility widget', 'elementor' ),
9
+ description: __( 'Make your site more inclusive by adding an accessibility widget.', 'elementor' ),
10
+ fixHint: __( 'Activate Ally’s accessibility widget to give visitors on-page accessibility tools.', 'elementor' ),
11
+ categories: [ 'accessibility' ],
12
+ severity: 'info',
13
+ weight: 1,
14
+ evaluate: ( ctx ) => {
15
+ if ( ! ctx.pageContext.frontend_url ) {
16
+ return { status: 'skipped', reason: __( 'Page is not published.', 'elementor' ) };
17
+ }
18
+
19
+ if ( ! ctx.renderedHtml ) {
20
+ return { status: 'skipped', reason: __( 'Could not fetch the published page.', 'elementor' ) };
21
+ }
22
+
23
+ if ( hasAccessibilityWidgetScript( ctx.renderedHtml ) ) {
24
+ return { status: 'pass' };
25
+ }
26
+
27
+ const isReady = ctx.pageContext.ally_plugin_active;
28
+
29
+ return {
30
+ status: 'fail',
31
+ violations: [
32
+ {
33
+ auditId: audit.id,
34
+ label: __( 'No accessibility widget is active on this site.', 'elementor' ),
35
+ externalUrl: isReady ? ctx.pageContext.ally_widget_settings_url : ctx.pageContext.ally_plugin_url,
36
+ ctaLabel: __( 'Activate', 'elementor' ),
37
+ },
38
+ ],
39
+ };
40
+ },
41
+ };
@@ -1,7 +1,6 @@
1
1
  import { __ } from '@wordpress/i18n';
2
2
 
3
3
  import { type Audit } from '../types';
4
- import { fetchRenderedHtml } from '../utils/fetch-rendered-html';
5
4
  import { hasConsentDefaultCall, hasGoogleTracking } from '../utils/scan-consent-signals';
6
5
 
7
6
  export const audit: Audit = {
@@ -18,22 +17,20 @@ export const audit: Audit = {
18
17
  categories: [ 'compliance' ],
19
18
  severity: 'warning',
20
19
  weight: 1,
21
- evaluate: async ( ctx ) => {
20
+ evaluate: ( ctx ) => {
22
21
  if ( ! ctx.pageContext.frontend_url ) {
23
22
  return { status: 'skipped', reason: __( 'Page is not published.', 'elementor' ) };
24
23
  }
25
24
 
26
- const html = await fetchRenderedHtml( ctx.pageContext.frontend_url );
27
-
28
- if ( ! html ) {
25
+ if ( ! ctx.renderedHtml ) {
29
26
  return { status: 'skipped', reason: __( 'Could not fetch the published page.', 'elementor' ) };
30
27
  }
31
28
 
32
- if ( ! hasGoogleTracking( html ) ) {
29
+ if ( ! hasGoogleTracking( ctx.renderedHtml ) ) {
33
30
  return { status: 'skipped', reason: __( 'No Google tracking product detected.', 'elementor' ) };
34
31
  }
35
32
 
36
- if ( hasConsentDefaultCall( html ) ) {
33
+ if ( hasConsentDefaultCall( ctx.renderedHtml ) ) {
37
34
  return { status: 'pass' };
38
35
  }
39
36
 
@@ -4,9 +4,10 @@ import { Button } from '@elementor/ui';
4
4
  type Props = {
5
5
  ctaLabel: string;
6
6
  externalUrl: string;
7
+ variant?: 'outlined' | 'text';
7
8
  };
8
9
 
9
- export default function ViolationCtaButton( { ctaLabel, externalUrl }: Props ) {
10
+ export default function ViolationCtaButton( { ctaLabel, externalUrl, variant = 'outlined' }: Props ) {
10
11
  const handleClick = ( event: React.MouseEvent< HTMLButtonElement > ) => {
11
12
  event.stopPropagation();
12
13
  event.preventDefault();
@@ -15,7 +16,7 @@ export default function ViolationCtaButton( { ctaLabel, externalUrl }: Props ) {
15
16
  };
16
17
 
17
18
  return (
18
- <Button variant="outlined" color="secondary" size="small" onClick={ handleClick }>
19
+ <Button variant={ variant } color="secondary" size="small" onClick={ handleClick }>
19
20
  { ctaLabel }
20
21
  </Button>
21
22
  );
@@ -164,10 +164,19 @@ export default function ViolationRow( { audit, skipReason, violations }: Props )
164
164
  />
165
165
  ) }
166
166
  { violation.ctaLabel && violation.externalUrl ? (
167
- <ViolationCtaButton
168
- ctaLabel={ violation.ctaLabel }
169
- externalUrl={ violation.externalUrl }
170
- />
167
+ <Box sx={ { display: 'flex', alignItems: 'center', gap: 0.5 } }>
168
+ <ViolationCtaButton
169
+ ctaLabel={ violation.ctaLabel }
170
+ externalUrl={ violation.externalUrl }
171
+ />
172
+ { violation.secondaryCtaLabel && violation.secondaryCtaUrl && (
173
+ <ViolationCtaButton
174
+ ctaLabel={ violation.secondaryCtaLabel }
175
+ externalUrl={ violation.secondaryCtaUrl }
176
+ variant="text"
177
+ />
178
+ ) }
179
+ </Box>
171
180
  ) : (
172
181
  <EyeIcon
173
182
  className="violation-hover-icon"
@@ -1,4 +1,6 @@
1
1
  import * as accessibilityPolicy from './audits/accessibility-policy';
2
+ import * as accessibilityStatement from './audits/accessibility-statement';
3
+ import * as accessibilityWidget from './audits/accessibility-widget';
2
4
  import * as cookiePolicy from './audits/cookie-policy';
3
5
  import * as deepNesting from './audits/deep-nesting';
4
6
  import * as defaultDesignSystem from './audits/default-design-system';
@@ -48,6 +50,8 @@ const AUDITS: Audit[] = [
48
50
 
49
51
  privacyPolicy.audit,
50
52
  accessibilityPolicy.audit,
53
+ accessibilityStatement.audit,
54
+ accessibilityWidget.audit,
51
55
  cookiePolicy.audit,
52
56
  scanForCookies.audit,
53
57
  googleConsentMode.audit,
package/src/runner.ts CHANGED
@@ -12,6 +12,7 @@ import {
12
12
  type PageAuditReport,
13
13
  } from './types';
14
14
  import { computeReport } from './utils/compute-report';
15
+ import { fetchRenderedHtml } from './utils/fetch-rendered-html';
15
16
  import { extractImageSizeRequests } from './utils/page-attachments';
16
17
  import { readKitSnapshot } from './utils/read-kit-snapshot';
17
18
  import { buildSnapshotTree } from './utils/v1-snapshot';
@@ -22,9 +23,12 @@ export async function runPageAudit( documentId: number ): Promise< PageAuditRepo
22
23
  const pageContext = await fetchPageContext( documentId, imageSizeRequests );
23
24
 
24
25
  const elements: ElementsModelSnapshot = { documentId, tree };
25
- const kit: KitSnapshot = await readKitSnapshot( pageContext.kit_id );
26
+ const [ kit, renderedHtml ]: [ KitSnapshot, string | null ] = await Promise.all( [
27
+ readKitSnapshot( pageContext.kit_id ),
28
+ fetchRenderedHtml( pageContext.frontend_url ),
29
+ ] );
26
30
 
27
- const ctx: AuditContext = { documentId, elements, pageContext, kit };
31
+ const ctx: AuditContext = { documentId, elements, pageContext, kit, renderedHtml };
28
32
  const registered = getRegisteredAudits();
29
33
 
30
34
  const auditResults: AuditRun[] = await Promise.all(
package/src/types.ts CHANGED
@@ -40,6 +40,8 @@ export type AuditViolation = {
40
40
  angieFix?: boolean;
41
41
  angiePrompt?: string;
42
42
  ctaLabel?: string;
43
+ secondaryCtaLabel?: string;
44
+ secondaryCtaUrl?: string;
43
45
  };
44
46
 
45
47
  export type PageContextResponse = {
@@ -66,6 +68,9 @@ export type PageContextResponse = {
66
68
  privacy_settings_url: string;
67
69
  ally_plugin_active: boolean;
68
70
  ally_plugin_url: string;
71
+ ally_accessibility_statement_created: boolean;
72
+ ally_accessibility_statement_url: string;
73
+ ally_widget_settings_url: string;
69
74
  cookiez_plugin_active: boolean;
70
75
  cookiez_plugin_url: string;
71
76
  cookiez_plugin_installed: boolean;
@@ -109,6 +114,7 @@ export type AuditContext = {
109
114
  elements: ElementsModelSnapshot;
110
115
  pageContext: PageContextResponse;
111
116
  kit: KitSnapshot;
117
+ renderedHtml: string | null;
112
118
  };
113
119
 
114
120
  export type PageAuditReport = {
@@ -0,0 +1,7 @@
1
+ // Script sources of known accessibility widgets. Ally is listed first; append third-party
2
+ // widget script sources here (UserWay, AccessiBe, EqualWeb, etc.) once confirmed.
3
+ const ACCESSIBILITY_WIDGET_SCRIPT_SOURCES = [ 'cdn.elementor.com/a11y/widget.js' ];
4
+
5
+ export function hasAccessibilityWidgetScript( html: string ): boolean {
6
+ return ACCESSIBILITY_WIDGET_SCRIPT_SOURCES.some( ( src ) => html.includes( src ) );
7
+ }