Designing an Accessible Citation System in WordPress

A Must-Use Plugin Case Study

This case study documents the design and implementation of a lightweight, accessible citation system for long-form content in WordPress.

The goal was not to build a feature for end-users, but to solve a recurring editorial and UX problem in a way that was:

  • semantically correct
  • accessible by default
  • editor-friendly
  • dependency-free
  • portable across themes and environments

The solution was implemented as a Must-Use (MU) plugin, combining PHP, vanilla JavaScript, and Gutenberg editor APIs.

The Problem

Instructional and technical content often needs inline citations to establish trust and accuracy. In WordPress, this is commonly handled in one of three ways:

  1. Inline links that disrupt reading flow
  2. Footnote plugins that add complexity and markup noise
  3. Ad-hoc styling hacks that lack semantic clarity

Each approach introduces trade-offs in accessibility, maintainability, or editorial consistency.

The challenge was to create a citation system that:

  • reads naturally in long paragraphs
  • clearly signals “source” without acting like a CTA;
  • remains accessible to screen readers and keyboard users;
  • is easy for non-technical editors to use;
  • avoids third-party plugin bloat.

This isn’t just a technical exercise. The citation system grew out of a broader goal for the Help Centre: to publish guidance that’s transparent, verifiable, and genuinely useful — without hiding sources or forcing readers to trust hand-waving claims.

Design Constraints and Decisions

Why a Must-Use plugin?

A Must-Use plugin was chosen because this functionality is editorial infrastructure, not theme behaviour.

Key reasons:

  • Always loaded, regardless of active theme
  • Not accidentally disabled
  • Portable between projects
  • Appropriate for cross-site content standards
  • Never affects site performance

This keeps the citation system stable and decoupled from visual presentation.

Why a shortcode as the source of truth?

Rather than parsing content or auto-detecting patterns, the system uses an explicit shortcode:

[cite url="https://support.google.com/" label="Google Help"]

This was a deliberate decision:

  • Explicit intent is clearer than “magic” parsing
  • Works in both Block and Classic editors
  • Safe for migrations, exports, and feeds
  • Server-rendered HTML ensures SEO reliability

The shortcode outputs semantic, minimal markup:

<sup class="oa-sup">[<a href="…">Google Help</a>]</sup>

Semantics and Accessibility

Accessibility was treated as a first-class requirement, not an afterthought.

Key considerations:

  • The citation link is a real <a> element
  • <sup> is used purely for presentation
  • Brackets are literal text nodes, not CSS artefacts
  • Keyboard navigation remains unchanged
  • Optional aria-label support improves screen reader clarity

Screen readers announce the link naturally, and the citation does not create duplicate focus targets or hidden controls.

Visual Treatment and UX

Citations are styled to be present but unobtrusive:

  • Superscript positioning signals “reference”
  • Dotted underline indicates clickability without shouting
  • Solid underline on hover/focus provides an affordance

This keeps the reading flow intact while still communicating credibility.

This keeps the reading flow intact while still communicating credibility.

The Editor UX Problem

While the front-end behaviour was robust, manually typing shortcodes in the block editor was:

  • slow
  • error-prone
  • inconsistent across editors

The next challenge was improving editor UX without breaking the underlying semantic model.

Editor solution: Gutenberg RichText integration

Rather than creating a custom block, the solution adds an inline toolbar control to RichText fields in the Gutenberg editor.

This approach:

  • avoids block clutter
  • keeps citations inline with text
  • works anywhere RichText is used

Behaviour

Inside a paragraph block, the editor gains a “Cite” toolbar button.

Workflow:

  1. Optionally select text to use as the label
  2. Click “Cite”
  3. Enter URL and options in a small modal
  4. insert citation at the cursor (or replace selection)

The editor inserts the canonical shortcode, preserving a single source of truth.

Technical implementation (JavaScript)

The editor UI is implemented using vanilla JavaScript, leveraging WordPress’s existing React environment rather than introducing a build step.

The editor inserts the canonical shortcode, preserving a single source of truth.

Key points:

  • Uses registerFormatType from the RichText API
  • Adds a toolbar button via RichTextToolbarButton
  • Modal UI built with WordPress components
  • No bundler, no transpilation, no external dependencies

This keeps the solution easy to audit, modify, and maintain long-term.

A Bug Worth Documenting: Format Collisions

During development, the editor button failed to appear consistently.

The cause was a format collision:

  • Gutenberg already registers formats using <span>
  • A custom format with a generic tagName: "span" conflicted with core/underline

The fix was to register the format with a unique className, making the signature unambiguous.

This is a subtle Gutenberg detail that’s rarely documented, but critical when extending RichText.

PHP Logic Overview

On the PHP side, the MU plugin handles:

  • shortcode registration
  • attribute sanitisation
  • accessible HTML output
  • shared CSS injection for front-end and editor

CSS is generated via a function and injected inline to avoid additional files and keep the footprint minimal.

Outcome

The final system delivers:

  • clean, semantic citations in rendered content
  • strong accessibility defaults
  • consistent editorial usage
  • a fast, error-resistant editor workflow
  • zero third-party dependencies

Most importantly, it demonstrates how small, well-considered tooling can significantly improve content quality without adding complexity.

Why this matters

This project isn’t about building a “plugin feature”.
It’s about designing editorial infrastructure that respects:

  • readers
  • writers
  • maintainers

It reflects a preference for:

  • explicit intent over automation
  • standards over hacks
  • long-term maintainability over novelty

Technologies used

  • WordPress
  • Gutenberg
  • PHP (shortcodes, MU plugin architecture)
  • Vanilla JavaScript (editor UI)
  • WordPress component system

Lessons Learned

1. Editorial infrastructure deserves the same rigour as features

Small editorial tools can have an outsized impact on content quality, accessibility, and consistency. Treating citations as infrastructure — not decoration — led to better decisions around semantics, portability, and long-term maintenance.

2. Explicit intent beats clever automation

While it’s tempting to auto-parse content or infer meaning, explicit constructs (like a shortcode) are easier to reason about, safer to migrate, and more predictable for both editors and developers.

3. Accessibility is easiest when designed in from the start

By starting with real HTML semantics (<a>, <sup>, literal text nodes), accessibility largely “fell out” of the implementation. Retrofitting ARIA and keyboard behaviour later would have been significantly more complex.

4. Gutenberg extensibility has sharp edges

The RichText API is powerful, but format registration is sensitive to collisions. Seemingly innocuous choices (such as a generic span format) can conflict with core features like underline, causing silent failures. Unique format signatures are essential.

5. Build steps are a trade-off, not a default

Leveraging WordPress’s existing React environment with vanilla JavaScript avoided unnecessary tooling, simplified debugging, and made the solution easier to audit. Not every editor extension needs a bundler or transpilation layer.

6. Editor UX directly affects content quality

Reducing friction in the editor — even by a few seconds per citation — significantly lowers error rates and improves consistency. Good tooling encourages good writing habits.

7. Bugs are often architectural signals

The format collision issue wasn’t just a bug; it revealed how Gutenberg internally reasons about formats. Treating the error as a learning opportunity improved both the implementation and future editor extensions.

8. The best solutions disappear into the workflow

A successful editorial tool doesn’t draw attention to itself. Once implemented, this citation system becomes invisible — editors simply use it, and readers benefit without noticing the machinery underneath.

If you’re interested, check out all my services.

Posted in Dev