Skip to content

PRO-959: Add edac_get_landmark_types() as single source of truth for landmark detection - #1745

Closed
SteveJonesDev wants to merge 1 commit into
developfrom
steve/pro-959-landmark-filter-options-replace-hardcoded-lists-with-a
Closed

PRO-959: Add edac_get_landmark_types() as single source of truth for landmark detection#1745
SteveJonesDev wants to merge 1 commit into
developfrom
steve/pro-959-landmark-filter-options-replace-hardcoded-lists-with-a

Conversation

@SteveJonesDev

@SteveJonesDev SteveJonesDev commented Jun 16, 2026

Copy link
Copy Markdown
Member

Summary

  • The scanner's landmark detection rules (LANDMARK_TAGS, LANDMARK_ROLES, CONDITIONAL_LANDMARK_TAGS, CONDITIONAL_LANDMARK_ROLES in src/pageScanner/index.js) were hardcoded inline, with the pro plugin maintaining its own separate, incomplete, out-of-sync copy for its Landmark filter dropdown.
  • Added edac_get_landmark_types() in includes/helper-functions.php as the canonical PHP source, plus edac_get_landmark_filter_options() which flattens it into { value, label } pairs for filter UIs.
  • pageScanner/index.js now reads its detection constants from window.scanOptions (matching the existing maxAltLength override pattern) with the same hardcoded values kept only as a fallback for contexts that don't localize scanOptions (e.g. standalone test runs).
  • Wired edac_get_landmark_types() into the editor scan's wp_localize_script payload (edac_editor_app.landmarkTypes) and into checkPage.js's iframe scanOptions injection, alongside the existing maxAltLength override.

Linear: https://linear.app/equalize-digital/issue/PRO-959/landmark-filter-options-replace-hardcoded-lists-with-a-single-source

Companion PR in accessibility-checker-pro consumes edac_get_landmark_filter_options() for the Issues Explorer's Landmark filter.

Test plan

  • Run an editor "Check" scan on a post with <nav>, <aside>, role="navigation", and role="complementary" elements; confirm the saved landmark values match the expected tag/role strings (unchanged behavior — same hardcoded defaults, now sourced via localization)
  • Confirm a scan with no wp_localize_script data present (e.g. direct script load without the editor flow) still works via the fallback constants

Summary by CodeRabbit

  • New Features
    • Landmark detection now supports custom configuration options, allowing dynamic adjustments to landmark tag and role matching for page scanning.
    • Landmark type definitions and filter options are now available throughout the editor and admin interface, enabling consistent landmark handling across all scanning operations.

…landmark detection

Localizes pageScanner's LANDMARK_TAGS/LANDMARK_ROLES/CONDITIONAL_LANDMARK_TAGS/
CONDITIONAL_LANDMARK_ROLES from a new PHP helper instead of hardcoding them in
both the scanner and downstream consumers (e.g. the pro plugin's filter UI).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds two PHP helper functions (edac_get_landmark_types, edac_get_landmark_filter_options) that define canonical landmark detection rules. The admin enqueue class passes these types as localized script data to the editor app. The editor iframe's injectIframe function reads this data and sets scanOptions on the iframe window. The page scanner reads those scanOptions properties with fallback to the previous hardcoded arrays.

Changes

Landmark types configuration pipeline

Layer / File(s) Summary
PHP landmark type and filter helpers
includes/helper-functions.php
Adds edac_get_landmark_types() returning tag, role, conditional tag, and conditional role arrays matching scanner persistence format, and edac_get_landmark_filter_options() building deduplicated lowercase { value, label } pairs from those types.
Admin script localization wiring
admin/class-enqueue-admin.php
Extends the wp_localize_script payload for edac-editor-app with a landmarkTypes key sourced from edac_get_landmark_types(), alongside existing keys like postID, scanUrl, and restNonce.
Iframe scanOptions injection and page scanner consumption
src/editorApp/checkPage.js, src/pageScanner/index.js
injectIframe reads window.edac_editor_app.landmarkTypes and assigns iframeDocument.defaultView.scanOptions with landmark tag/role fields via object spread. The page scanner replaces hardcoded LANDMARK_TAGS, LANDMARK_ROLES, CONDITIONAL_LANDMARK_TAGS, and CONDITIONAL_LANDMARK_ROLES constants with values from window.scanOptions.*, retaining the previous arrays as fallbacks.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Suggested reviewers

  • pattonwebz

Poem

🐰 Hop, hop, through the landmark maze,
No more hardcoded arrays — PHP sets the stage!
edac_get_landmark_types() leads the way,
scanOptions now carry the server's say.
The scanner reads window with a fallback grace,
Every tag and role finds its proper place! 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main objective of the PR, which is to establish a single source of truth for landmark detection rules through the new edac_get_landmark_types() function.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch steve/pro-959-landmark-filter-options-replace-hardcoded-lists-with-a

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces dynamic landmark detection rules by passing canonical landmark types from PHP to the frontend page scanner via localized script data and iframe scan options. The review feedback suggests improving localization in includes/helper-functions.php by using WordPress translation functions instead of hardcoding ucfirst(), and preventing potential runtime errors in src/editorApp/checkPage.js by using optional chaining when accessing window.edac_editor_app.maxAltLength.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +861 to +885
function edac_get_landmark_filter_options(): array {
$types = edac_get_landmark_types();

$values = array_unique(
array_map(
'strtolower',
array_merge(
$types['tags'],
$types['roles'],
$types['conditionalTags'],
$types['conditionalRoles']
)
)
);

return array_map(
static function ( $value ) {
return [
'value' => $value,
'label' => ucfirst( $value ),
];
},
array_values( $values )
);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The landmark labels (e.g., 'Main', 'Navigation', 'Banner') are user-facing strings displayed in the Issues Explorer's Landmark filter in the pro plugin. Hardcoding ucfirst( $value ) prevents these labels from being translated.

Using a translation mapping array with WordPress translation functions (__()) ensures these strings can be localized properly.

function edac_get_landmark_filter_options(): array {
	$types = edac_get_landmark_types();

	$values = array_unique(
		array_map(
			'strtolower',
			array_merge(
				$types['tags'],
				$types['roles'],
				$types['conditionalTags'],
				$types['conditionalRoles']
			)
		)
	);

	$labels = [
		'main'          => __( 'Main', 'accessibility-checker' ),
		'navigation'    => __( 'Navigation', 'accessibility-checker' ),
		'banner'        => __( 'Banner', 'accessibility-checker' ),
		'contentinfo'   => __( 'Contentinfo', 'accessibility-checker' ),
		'complementary' => __( 'Complementary', 'accessibility-checker' ),
		'region'        => __( 'Region', 'accessibility-checker' ),
		'article'       => __( 'Article', 'accessibility-checker' ),
		'form'          => __( 'Form', 'accessibility-checker' ),
		'section'       => __( 'Section', 'accessibility-checker' ),
		'header'        => __( 'Header', 'accessibility-checker' ),
		'footer'        => __( 'Footer', 'accessibility-checker' ),
		'nav'           => __( 'Navigation', 'accessibility-checker' ),
		'aside'         => __( 'Aside', 'accessibility-checker' ),
	];

	return array_map(
		static function ( $value ) use ( $labels ) {
			return [
				'value' => $value,
				'label' => $labels[ $value ] ?? ucfirst( $value ),
			];
		},
		array_values( $values )
	);
}

Comment on lines 114 to 122
iframeDocument.defaultView.scanOptions = {
maxAltLength: window.edac_editor_app.maxAltLength,
...( landmarkTypes && {
landmarkTags: landmarkTypes.tags,
landmarkRoles: landmarkTypes.roles,
conditionalLandmarkTags: landmarkTypes.conditionalTags,
conditionalLandmarkRoles: landmarkTypes.conditionalRoles,
} ),
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To prevent potential runtime TypeError exceptions if window.edac_editor_app is undefined or null, use optional chaining (?.) when accessing maxAltLength.

Suggested change
iframeDocument.defaultView.scanOptions = {
maxAltLength: window.edac_editor_app.maxAltLength,
...( landmarkTypes && {
landmarkTags: landmarkTypes.tags,
landmarkRoles: landmarkTypes.roles,
conditionalLandmarkTags: landmarkTypes.conditionalTags,
conditionalLandmarkRoles: landmarkTypes.conditionalRoles,
} ),
};
iframeDocument.defaultView.scanOptions = {
maxAltLength: window?.edac_editor_app?.maxAltLength,
...( landmarkTypes && {
landmarkTags: landmarkTypes.tags,
landmarkRoles: landmarkTypes.roles,
conditionalLandmarkTags: landmarkTypes.conditionalTags,
conditionalLandmarkRoles: landmarkTypes.conditionalRoles,
} ),
};

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/editorApp/checkPage.js (1)

109-123: ⚡ Quick win

Use conditional spread for maxAltLength to match landmarkTypes pattern.

Line 115 unconditionally includes maxAltLength in the scanOptions object, even when it might be falsy. While the PHP code ensures maxAltLength is always at least 1, using a conditional spread would make the code more robust and consistent with how landmarkTypes is handled.

♻️ Refactor to use conditional spread
 const injectIframe = ( previewUrl, postID ) => {
+	const maxAltLength = window?.edac_editor_app?.maxAltLength;
+	const landmarkTypes = window?.edac_editor_app?.landmarkTypes;

-	if ( iframeDocument ) {
-		const landmarkTypes = window?.edac_editor_app?.landmarkTypes;
-
-		if ( window?.edac_editor_app?.maxAltLength || landmarkTypes ) {
+	if ( iframeDocument && ( maxAltLength || landmarkTypes ) ) {
-			// Pass scan overrides into the iframe's own window so pageScanner.bundle.js
-			// (injected below, into this same iframe document) can read them.
-			iframeDocument.defaultView.scanOptions = {
-				maxAltLength: window.edac_editor_app.maxAltLength,
-				...( landmarkTypes && {
-					landmarkTags: landmarkTypes.tags,
-					landmarkRoles: landmarkTypes.roles,
-					conditionalLandmarkTags: landmarkTypes.conditionalTags,
-					conditionalLandmarkRoles: landmarkTypes.conditionalRoles,
-				} ),
-			};
-		}
+		// Pass scan overrides into the iframe's own window so pageScanner.bundle.js
+		// (injected below, into this same iframe document) can read them.
+		iframeDocument.defaultView.scanOptions = {
+			...( maxAltLength && { maxAltLength } ),
+			...( landmarkTypes && {
+				landmarkTags: landmarkTypes.tags,
+				landmarkRoles: landmarkTypes.roles,
+				conditionalLandmarkTags: landmarkTypes.conditionalTags,
+				conditionalLandmarkRoles: landmarkTypes.conditionalRoles,
+			} ),
+		};
+	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/editorApp/checkPage.js` around lines 109 - 123, In the scanOptions object
assignment, the maxAltLength property is unconditionally included even when it
might be falsy. Refactor it to use a conditional spread operator pattern,
similar to how landmarkTypes is handled. Wrap the maxAltLength property
assignment in a conditional spread using the same pattern: ...(
window.edac_editor_app.maxAltLength && { maxAltLength:
window.edac_editor_app.maxAltLength, } ) to make the code more robust and
consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/editorApp/checkPage.js`:
- Around line 109-123: In the scanOptions object assignment, the maxAltLength
property is unconditionally included even when it might be falsy. Refactor it to
use a conditional spread operator pattern, similar to how landmarkTypes is
handled. Wrap the maxAltLength property assignment in a conditional spread using
the same pattern: ...( window.edac_editor_app.maxAltLength && { maxAltLength:
window.edac_editor_app.maxAltLength, } ) to make the code more robust and
consistent.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d66de6c3-fa3a-4c84-befd-bdb4e0d6c489

📥 Commits

Reviewing files that changed from the base of the PR and between cb1bb42 and dd0998a.

📒 Files selected for processing (4)
  • admin/class-enqueue-admin.php
  • includes/helper-functions.php
  • src/editorApp/checkPage.js
  • src/pageScanner/index.js

@SteveJonesDev

Copy link
Copy Markdown
Member Author

Closing — the proposed single-source-of-truth approach needs rework (edac_get_landmark_filter_options shouldn't live in the free plugin, it's pro-only UI formatting). Leaving PRO-959 open to redo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant