Spotted while reviewing #3608694 (1.x-dev), verified with a standalone reproduction of the process() logic.
In ExternalLinkA11yFilter::process(), a local $updated flag controls whether setProcessedText() is called at the end. The rel-handling block sets the rel attribute (noopener / noreferrer) but never sets $updated to TRUE. So when a rel attribute is the only thing that changes, the attribute is written to the in-memory DOM but the processed text is discarded, and the change is silently lost.
Reproduction: configure the filter with "Apply if external URL" off, "Apply if target is _blank" on, "Add rel attribute noopener" on, the "Open in new window" message off, and no HTML suffix, then run a link that already carries target="_blank" through the filter. The anchor gets rel="noopener" in the DOM, but process() returns the original unchanged text.
Related coupling issue in the same method: the "CSS classes to add to the link element" handling is nested inside the a11y_new_window (Open in new window message) block, so that setting has no effect unless the message option is also enabled, even though the two are presented as independent settings.
Proposed fix: set $updated to TRUE whenever the rel attribute is modified, and move the css_classes handling out of the a11y_new_window block so it applies on its own.
Issue fork external_link_a11y-3608714
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #3
mably commentedMR !9 opened with the fix and kernel test coverage. It sets the internal updated flag when the rel attribute is modified, so a rel-only change is no longer discarded, and it moves the CSS-classes handling out of the "Open in new window" block so those classes apply independently. Tests cover the rel-only change, rel de-duplication, CSS classes without the a11y message, the full external-link treatment and internal links left untouched. Pipeline is green.
Comment #5
mably commented