Security and session timeout accessibility get treated as if only one of them counts. The usual move is to shorten session durations, call that data protection, and never notice it locked out 20% of the audience.
To a developer a session timeout is a cookie expiring. To someone on a screen reader, or using a switch device because of a motor impairment, it’s a wall. If a checkout form takes that person four times as long to work through and the session dies at 15 minutes with no warning, their data isn’t any safer. They just can’t finish, and the message they take away is that the site wasn’t built for them.
Where this goes wrong in practice
I’ve watched this happen on enterprise WooCommerce builds more times than I want to count. The client asks for tight security, the team sets a short auth_cookie_expiration, and then support starts fielding messages like “I spent 30 minutes picking my configuration and the site logged me out before I could pay.”
It usually comes down to the same few mistakes:
- The session dies on the server while the interface sits there looking fine, so the user only finds out at submit, after the work is gone.
- The time limit can’t be turned off or extended, which is exactly what WCAG SC 2.2.1 asks for.
- There is a warning, but it never reaches a screen reader because the
aria-liveregion isn’t wired up correctly.
The naive approach
Hooking auth_cookie_expiration is where most attempts start and stop. It sets the server-side rule, and it tells the person filling in your form precisely nothing.
<?php
/**
* DO NOT JUST DO THIS. It's technically correct for security
* but a disaster for accessibility without front-end feedback.
*/
add_filter( 'auth_cookie_expiration', 'bbioon_strict_session_length', 10, 3 );
function bbioon_strict_session_length( $expiration, $user_id, $remember ) {
return 1800; // 30 minutes is not enough for many disabled users.
}
Building a warning that meets WCAG
The fix is split across both sides. The server stays the source of truth, and a JavaScript layer watches the clock and raises an accessible warning before the deadline. The trap here is a race condition: the interface still shows a minute remaining after the server has already purged the transient.
Track the start time in sessionStorage and check against it with a setInterval, or lean on the WordPress Heartbeat API. The modal matters more than the timing, though. Give it role="alertdialog" so assistive technology announces it the moment it appears.
// Example of a simple accessible timeout warning
const sessionLimit = 30 * 60 * 1000; // 30 mins
const warningThreshold = 2 * 60 * 1000; // Warn at 2 mins
function checkSession() {
const startTime = parseInt(sessionStorage.getItem('session_start'));
const elapsed = Date.now() - startTime;
if (elapsed > (sessionLimit - warningThreshold)) {
showAccessibleWarning();
}
}
function showAccessibleWarning() {
const modal = document.getElementById('timeout-warning');
modal.setAttribute('aria-hidden', 'false');
// Ensure focus is trapped and screen readers announce the alert
modal.querySelector('button').focus();
}
Pair that with accessible UI design patterns so the warning is readable and operable when it shows up, rather than just present in the markup.
Auto-save as the safety net
Some people will time out anyway. Someone steps away for a medical reason, or their assistive tech crashes. Keep the form data in localStorage or push it up with background AJAX requests. Logging back in to find a 2,000-word application gone is the thing people remember about a site.
I’ve written before about why checklist accessibility fails, and session management is a good example of it. The checklist item says to add a warning. The actual requirement is that nobody loses their work.
If session timeout work is eating hours you don’t have, I can take it on. I’ve been working with WordPress since the 4.x days.
Where session management belongs
Session management is a front-end concern as much as a security one. Warn people before the clock runs out, let them extend the session, and save their work in the background, and what you end up with is usable rather than merely compliant. Skipping that isn’t shipping faster. It’s debt, and someone else pays it down later.