Skip to main content
Aggregate Drupal.org Planet Drupal 14 Oct 2026 - 18:06

Aten Design Group: Extending Editoria11y with Custom Content Checks in Drupal

RSS 官方收录 · 可信分层展示

关键摘要

Extending Editoria11y with Custom Content Checks in Drupal Joel Steidl Tue, 10/13/2026 - 14:53 Drupal An editor copies a link from an email, adds it to a page, and publishes.…

  • The link text looks right.
  • The destination opens.
  • Nothing about the normal authoring workflow suggests a problem.

规则摘要 · 来源可核验

正文提要

Extending Editoria11y with Custom Content Checks in Drupal Joel Steidl Drupal

An editor copies a link from an email, adds it to a page, and publishes. The link text looks right. The destination opens. Nothing about the normal authoring workflow suggests a problem.

But the saved URL may not be the destination the editor intended to publish. Microsoft Safe Links can wrap an address in a long, encoded URL that sends visitors through a security-checking redirect service.

On of our client’s websites, a custom Editoria11y check helps editors recognize these links and replace them with the original destination. It adds site-specific guidance to a tool already used for accessibility feedback.

A Content Problem Worth Flagging

Microsoft Safe Links is a legitimate security feature, not evidence that a link is spam or malicious. The problem here was context: a URL copied from an email was becoming a public website link.

A simplified example looks like this:

<https://gcc02.safelinks.protection.outlook.com/?url=https%3A%2F%2Fexample.com%2Fmeeting>

The intended destination is https://example.com/meeting. Publishing the wrapper makes that destination harder to inspect and introduces dependence on another redirect service. The addresses can also be difficult to read and maintain.

Those are good reasons for an editorial warning. They are not proof that every Safe Link violates WCAG or cannot be used with a screen reader.

The useful question was narrower: could the website identify this recurring content pattern and give editors a practical next step?

Discovering an Existing Extension Point

Editoria11y brings accessibility feedback into the page context. Its custom-test capability lets developers add checks beyond the standard set without building a separate reporting interface.

Princeton's documentation includes an example for email-obfuscated URLs, providing a starting point for both detection and integration. The extension builds on that existing capability rather than introducing a separate checking system.

A Small Drupal Integration

The custom module, custom_editoria11y, handles the Drupal integration. Its metadata declares a dependency on Editoria11y. A library definition registers the custom JavaScript and depends on the contrib module's library.

The PHP attachment hook checks for the view editoria11y checker permission before attaching that library. This keeps the extra script scoped to users authorized to use the checker rather than delivering it to public visitors.

JavaScript handles detection and feedback. Although we might informally call this a custom rule or plugin, it is not a Drupal PHP Plugin API class. It is an event-driven JavaScript test delivered through a Drupal module.

That division keeps the implementation small: Drupal controls availability, the custom script identifies the content pattern, and Editoria11y provides the warning interface.

How the Custom Test Runs

Editoria11y's custom-test lifecycle has four steps: register the expected callbacks, listen for ed11yRunCustomTests, add results, and dispatch ed11yResume when finished.

Our script increments options.customTests through the Drupal integration's options override. That tells the checker to wait for one additional completion event before drawing its tooltips.

The count represents completing test callbacks, not matching links. A callback that finds ten links still sends one completion event. A callback that finds none must finish too.

The rule searches for anchors using a[href*="safelinks.protection.outlook.com"]. This catches different Safe Links subdomains without maintaining a list of regional prefixes. It is substring matching, however, not comprehensive URL-host validation; the same text elsewhere in an address could also match.

The following excerpt shows the site's v3 integration. It assumes the options override and tooltip helper are already defined:

document.addEventListener('ed11yRunCustomTests', function () {
  Drupal.Ed11y.findElements(
    'customSafeLinks',
    'a[href*="safelinks.protection.outlook.com"]'
  );
 
  Drupal.Ed11y.elements.customSafeLinks?.forEach(function (element) {
    Drupal.Ed11y.State.results.push({
      element,
      test: 'customSafeLink',
      type: 'warning',
      content: customSafeLinkContent(element.getAttribute('href')),
      position: 'beforebegin',
      dismiss: false,
    });
  });
 
  document.dispatchEvent(new CustomEvent('ed11yResume'));
});

Using findElements keeps the search within the configured content roots and respects selector-based exclusions. Results enter the existing checker workflow rather than a separate alert system.

The tooltip names the issue, displays the encoded address, and asks the editor to replace it with the original URL. When available, new URL(href).searchParams.get('url') extracts the destination as an additional hint. If parsing fails or the parameter is missing, that hint is omitted.

Displayed URL strings are sanitized with Drupal.Ed11y.sanitizeHTML. In this v3 implementation, tooltip content is a DOM element, with a .title child supplying its heading.

The rule does not rewrite content or block publication. The editor remains responsible for checking and replacing the link.

Maintaining the Rule Through an Upgrade

An upgrade from Editoria11y 2.2.6 to 3.0.2 required migrating the custom module to the v3 API.

The migration changed more than a version constraint. The custom code moved from older Ed11y references to Drupal.Ed11y, changed the sanitization helper, and pushed results into Drupal.Ed11y.State.results. Tooltip construction moved from the older message-registration approach and HTML strings to DOM-element content. Result properties also changed, including explicit warning severity and the dismissal setting.

The lesson is practical: extending a supported tool avoids owning an entire checker, but the extension still has an API contract. Major upgrades require reviewing that contract and testing the custom feedback, not just confirming that the base module loads.

Testing and Extending Thoughtfully

For ongoing maintenance, a focused regression checklist should cover matching and ordinary links, missing destination parameters, configured exclusions, permission boundaries, safe tooltip rendering, and completion events when no matches exist.

Additional checks could flag obsolete internal domains or temporary campaign URLs. Those are possibilities, not features delivered in this project. Each proposed rule should have a recognizable problem, a clear correction, and a manageable risk of false positives.

Multiple extensions also need to coordinate the shared options override rather than replace one another's callbacks. The expected completion count must stay aligned with the listeners actually running.

Princeton's custom-test documentation is a useful starting point. Check examples against the installed version, especially when maintaining an older integration.

Give Editors an Actionable Next Step

The value of this extension is specific feedback at the point where someone can act on it. Instead of asking editors to remember every problematic URL pattern, the website identifies one and explains what to change.

Custom tests can support content standards alongside accessibility checks. They do not replace human review or establish accessibility compliance. They make the existing editorial workflow more useful, one well-defined problem at a time.

Philip Stier
打开官方原文 站点原文页 可信分区 本信源更多 今日简报 分享图 RSS 稍后再看列表