Install
This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.
Install straight from GitHub with WP-CLI:
wp plugin install https://github.com/padilhars/wp-a11y/archive/refs/heads/main.zipNo built-in updater. New versions won't appear under Dashboard → Updates. Install new releases yourself, or let Git Updater track the repository.
Plugin de acessibilidade para WordPress — port do plugin local_a11y, desenvolvido originalmente para Moodle.
Status
Fases 0-5 concluídas — v1.0.5.
Fase 0 (esqueleto de dados):
- 29 opções de acessibilidade (
WP_A11y\Options) e 9 perfis prontos (WP_A11y\Profiles), transcritos dolocal_a11yatual (não do protótipo_design-reference/, que está desatualizado — ver DECISIONS.md D1). - Configurações do admin em
/wp-admin/admin.php?page=wp-a11y(5 seções: Geral, FAB, Painel, Cores, Estatísticas), armazenadas em uma única opçãowp_a11y_settings. - Tabela de estatísticas agregadas e anônimas (
{prefix}wp_a11y_stats) + relatório em/wp-admin/admin.php?page=wp-a11y-stats.
Fase 1 (FAB + painel + efeitos CSS puros):
- Botão flutuante + painel (popover/gaveta/modal conforme configuração; sempre gaveta em telas pequenas), com busca, perfis, categorias colapsáveis, atalho
Alt+A,Escfecha, focus trap. - 19 das 29 opções têm efeito visual real via classes
body.a11y-*(assets/css/a11y-effects.css): tipografia (incl. 3 fontes OFL auto-hospedadas — Atkinson Hyperlegible, Lexend, OpenDyslexic), cores/contraste (incl. simulação de daltonismo via filtros SVGfeColorMatrix), mídia (ocultar imagens/pausar animações) e foco/navegação (cursor, modo foco). As 10 restantes são módulos JS sob demanda, completados na Fase 3 abaixo. - Persistência via
localStoragepara visitantes; usuários logados agora sincronizam de verdade com o servidor (Fase 2, abaixo). Script no-FOUC (wp_body_open) aplica o estado salvo antes da 1ª pintura. - Testado com Chrome headless real: FAB/painel renderizam e funcionam, toggles/perfis/persistência/reload confirmados sem erros de console.
Fase 2 (REST API + estatísticas):
GET/POST /wp-json/wp-a11y/v1/settings(autenticado, noncewp_rest): usuário logado lê/escreve sua preferência real emusermeta, sincronizada entre dispositivos. Migração automática de qualquer preferência de visitante salva emlocalStorageno primeiro login sem preferência salva ainda.- Script no-FOUC agora embute a preferência real do usuário logado (lida direto do
usermetano PHP) em vez de sempre depender dolocalStorage— elimina o flash de FOUC que a Fase 1 ainda tinha para quem já estava logado. POST /wp-json/wp-a11y/v1/activate: contador de ativação por opção, mesma validação/allowlist server-side de antes (Fase 0), agora de fato alimentado pelo painel — disparado (fire-and-forget) sempre que uma opção passa de padrão→ativa, só quando a coleta de estatísticas está ligada.- Relatório de estatísticas (
/wp-admin/admin.php?page=wp-a11y-stats) agora mostra dados reais. - Testado ponta a ponta com Chrome headless real (login incluso): sincronização de preferência, reidratação sem FOUC após reload, e contador de estatísticas confirmados direto no banco.
Fase 3 (módulos avançados, um de cada vez — concluída, 10/10):
- Dicas de Ferramentas (
tooltips): converte[title]nativo (pequeno, com atraso, só no mouse) numa dica visível também por foco de teclado (assets/js/features/tooltips.js). - Silenciar Mídia (
silenceMedia): muta todo<audio>/<video>da página, incluindo mídia que começa a tocar depois de ativado; restaura o estado original ao desativar (silence-media.js). - Leitura Biônica (
bionicReading): negrita a primeira metade de cada palavra do conteúdo real da página, reversível sem perder o texto original (bionic-reading.js). - Guia de Leitura (
readingGuide): faixa horizontal destacada (cor configurável em Cores) que acompanha o mouse verticalmente, ajudando a manter a linha de leitura (reading-guide.js). - Máscara de Leitura (
readingMask): duas faixas escurecidas acima/abaixo do cursor, isolando uma janela de leitura de ~120px (reading-mask.js). - Lupa (
magnifier): lente circular que segue o mouse mostrando uma cópia ampliada (2,2×) do conteúdo sob o cursor — clona#wp-a11y-content-wrapuma vez e só reposiciona viatransforma cada movimento (magnifier.js). - Leitor de Tela (
screenReader): passar o mouse destaca qualquer texto da página (títulos, parágrafos, links, botões, etc.); clicar lê em voz alta viaspeechSynthesisnativo do navegador — nenhum áudio é enviado a lugar nenhum, é 100% processamento local do navegador (screen-reader.js). - Teclado Virtual (
virtualKeyboard): aparece automaticamente ao focar um campo de texto dentro do conteúdo da página; digita usandoexecCommand('insertText'/'delete'), que preserva posição do cursor e dispara os eventosinputreais (virtual-keyboard.js). - Comandos por Voz (
voiceCommands): controla o painel e ~35 comandos falados (tipografia, cores, navegação, rolagem) viaSpeechRecognitionnativo do navegador — o áudio é enviado a um serviço remoto do próprio navegador (não deste site), por isso exige aviso de privacidade e consentimento explícito antes de começar, com uma pílula de status/feedback na tela (voice-commands.js). - Navegação por Face (
faceNavigation): move um cursor virtual com movimentos da cabeça e "clica" abrindo a boca ou piscando, via MediaPipe FaceLandmarker rodando 100% no navegador — a imagem da câmera nunca é enviada a lugar nenhum. Os dois arquivos de terceiros necessários (bundle de visão + modelo) são baixados ao vivo e verificados por SHA-256 antes do uso, fechando o mesmo gap TOCTOU que olocal_a11ytrata; exige aviso de privacidade/consentimento antes de pedir acesso à câmera (face-navigation.js). - Cada módulo é importado dinamicamente (
import()por URL, sem bundler) só na primeira ativação real da opção — nada é baixado à toa. Todos testados ligando/desligando de verdade num Chrome headless (efeito aplicado E revertido corretamente, posições/transformações conferidas, digitação de verdade num campo de teste, sem erro de console) — Comandos por Voz e Navegação por Face testados comSpeechRecognition/câmera e MediaPipe simulados (mock), já que o ambiente de CI/headless não tem microfone/câmera reais nem pode validar o hash de um modelo de verdade sem rede liberada para o CDN. Ver DECISIONS.md D10 sobre um falso alarme de bug encontrado (e descartado) durante esse teste.
Fase 4 (privacidade + auditoria de segurança/qualidade):
- Privacy API (
includes/class-privacy.php): exporter e eraser da única preferência pessoal que o plugin guarda (wp_a11y_settings, usermeta), registrados em Ferramentas > Exportar/Apagar Dados Pessoais; texto sugerido de política de privacidade (wp_add_privacy_policy_content()) cobrindo a preferência em si e os dois recursos cujo navegador conversa com um terceiro quando ativados (Comandos por Voz → serviço de reconhecimento de fala do fabricante do navegador; Navegação por Face → dois arquivos baixados ao vivo do MediaPipe, imagem da câmera nunca sai do navegador). A tabela de estatísticas agregadas não é declarada — não tem coluna que identifique ninguém. Testado com um usuário real viawp eval: exportação/exclusão confirmadas ponta a ponta. Ver DECISIONS.md D11. - Auditoria PHPCS (
WordPress-Extra): 3 erros reais encontrados e corrigidos emclass-stats.php(nome de tabela interpolado direto na query em vez do placeholder%ido$wpdb->prepare()— não era injeção de verdade na prática, mas corrigido mesmo assim; um comentário de supressão existente também apontava para o código de sniff errado). Verificado com uma ativação de teste de verdade no banco. Os outros 57 achados eram só formatação (corrigida automaticamente comphpcbf, comportamento reconfirmado depois). - Auditoria ESLint: zero erros reais em
assets/js/**; 18 avisos cosméticos limpos (blocoscatchcom a exceção nunca usada convertidos paracatch {}, umlettrocado porconst). Comportamento reconfirmado com os mesmos testes mock de Comandos por Voz/Navegação por Face. - XSS do JSON inline (
class-render.php): já seguro por construção — os únicos dados de usuário embutidos em `